Streamline: Work Plan¶
Companion to
SPEC.md. Section numbers like §6.2c refer to the spec. Status (2026-10-06): Part A and Part C confirmed (seeDECISIONS.md). Phases 1, 2, 2a, 2b and 3 are complete, plus the owner's follow-ups (orange unplanned banner, Done → To do on the board, tasks in several projects, daily activity log; D-48), routine versions (D-49) and 2b.6a Places (D-50). Phases 3b (prerequisites, multi-step chores) and 4 (groups) are complete too. Phase 5 (calendar) and 3b.6a Occasions (D-57) are complete. Phase 5a (conflicts, blocks, planner) 5b (summary, tracking) and 5c (goals) too (D-58..D-60). Phase 6.1–6.3 (installable app, push, backups) are done (D-62, D-63). 6.4 (performance and accessibility, D-66) too. Next: 6.5 v1.0 release. Legend:[x]done ·[~]partly done (the remaining work is noted) ·[ ]not started.
MVP status (2026-10-06)¶
Runs with docker compose up -d: first-run admin setup, users/API tokens, projects, inbox, tasks
with all §6.6 attributes, Today view (scheduled/plan/due/done, now line, up next, day
navigation), pull-in sheet, drag-to-reorder lists, carry-on/expires rollover at a configurable
day end, live multi-device sync. Remaining Phase 1/2 work is marked [~] below.
How to use this plan¶
- The work is split into phases that follow §7. Each phase is split into chunks. A chunk is sized for one focused Claude Code session and ends in a commit (or PR) that builds, passes tests, and leaves the app runnable.
- A phase ends with a phase gate (Part D): resource measurements, a manual smoke test,
and updates to
README.mdanddocs/DECISIONS.md. - Tick the checkboxes as chunks land. If a chunk turns out bigger than one session, split it here first, then do the work.
- When a chunk needs an open question settled, it says so (
needs Q-x, see Part C). Don't start that chunk until the owner has confirmed the default or picked another option.
Part A. Architecture baseline (proposed, confirm before Phase 1)¶
A.1 Repository layout¶
Streamline/
├── Cargo.toml # Cargo workspace
├── crates/
│ ├── domain/ # Pure logic, no IO: recurrence, rollover, dependency graph,
│ │ # conflict detection, planner, task-type rules. Most tests live here.
│ ├── server/ # Axum binary: config, HTTP API, auth, SSE, jobs, DB access,
│ │ # embeds the built frontend
│ ├── caldav/ # (Phase 5) CalDAV client + iCal parsing behind a provider trait
│ └── integrations/ # (Phase 7) Mealie and later providers
├── migrations/ # sqlx migrations (SQLite)
├── web/ # SvelteKit app (adapter-static, SPA mode)
│ └── src/lib/api/types/ # TS types generated from Rust (ts-rs); committed, checked in CI
├── docker/
│ ├── Dockerfile # multi-stage: node build → rust musl build → scratch/distroless
│ └── docker-compose.yml # app (+ optional radicale profile for dev)
├── scripts/ # measure.sh, gen-types.sh, dev helpers
├── docs/
│ ├── SPEC.md WORKPLAN.md DECISIONS.md API.md (links to generated OpenAPI)
└── justfile # dev, test, build, measure, gen-types
Why split out domain: the spec's risky logic (§8: recurrence, rollover, dependencies,
conflicts, planner) is pure and deterministic. Keeping it free of DB and HTTP code makes it fast
to test and easy to reuse later, e.g. in a Tauri client.
A.2 Backend conventions¶
| Topic | Proposal |
|---|---|
| Framework | Axum + Tokio + tower-http (compression, tracing, timeouts). |
| DB | SQLite via sqlx, WAL mode, foreign_keys=ON, a single writer pool plus a read pool. Migrations embedded with sqlx::migrate!. |
| IDs | ULID, stored as TEXT (sorts by time, safe to create offline). |
| Timestamps | Instants stored as UTC RFC 3339 TEXT. Local dates as YYYY-MM-DD, local times as HH:MM, plus the user's IANA timezone. |
| Sync fields | Every entity has created_at, updated_at, deleted_at (tombstone) and rev. rev is a global, monotonically increasing change sequence. GET /api/v1/changes?since=<rev> returns everything changed since then. SSE events carry the same rev (used as SSE id). |
| Ordering | Fractional-index string keys (position TEXT), so reordering touches one row and stays sync-friendly. |
| API | /api/v1/... JSON. Errors use RFC 7807 problem+json. OpenAPI generated with utoipa and served at /api/v1/openapi.json, with a docs UI only in dev builds to keep the binary small. |
| Types to TS | ts-rs on the API DTOs. just gen-types writes them to web/src/lib/api/types, and CI fails if they are stale. |
| Auth | Argon2id passwords. Sessions in a DB table, with the cookie holding a random token (stored hashed). Cookie is HttpOnly and SameSite=Lax, and Secure only when the request is HTTPS (directly or via a trusted X-Forwarded-Proto). Per-device API tokens sent as Authorization: Bearer, stored hashed, revocable. Requests that change data and use cookie auth must pass an Origin/Host check. Login is rate-limited. |
| Proxy-awareness | No hard-coded scheme or host. Absolute URLs (QR links, push) come from PUBLIC_URL if set, else from forwarded headers when TRUST_PROXY=true, else from the request itself. |
| Realtime | A tokio::sync::broadcast bus feeds the SSE endpoint GET /api/v1/events. Events are filtered per subscriber by a single visibility function (A.4). Supports Last-Event-ID resume (the server replays from rev or tells the client to refetch) and sends a heartbeat every 25 s. |
| Jobs | One in-process scheduler (Tokio interval, 30–60 s tick) for: day rollover, occurrence materialization, wait-time readiness, reminders, calendar sync. All jobs are idempotent. No external cron. |
| Config | Env vars (PORT, DATA_DIR, SECRET_KEY, INITIAL_ADMIN_USER/PASSWORD, PUBLIC_URL, TRUST_PROXY, LOG_LEVEL), plus a settings table for anything editable in the app. SECRET_KEY is generated on first boot into data/ if not given. |
| Secrets at rest | CalDAV and integration credentials encrypted with a key derived from SECRET_KEY (XChaCha20-Poly1305). They are never returned by the API or written to logs. |
| Static assets | The built SPA is embedded with rust-embed and served with precompressed br/gzip variants and immutable cache headers for hashed files. Unknown non-API paths fall back to index.html. |
| Image | Frontend built with node:alpine. Rust built for *-unknown-linux-musl with opt-level="z"/"s", LTO, strip, and the musl allocator swapped for mimalloc if RSS benefits. Final stage is scratch (or distroless static) with CA certs. Images built for amd64 and arm64 (Raspberry Pi). |
A.3 Frontend conventions¶
- Svelte 5 + SvelteKit with
adapter-static(SPA fallback) and TypeScript. No UI kit. Plain CSS with design tokens (custom properties), light and dark themes, a fluid type scale. - Layout: bottom tab bar on phones (Today · Projects · Plan · More), a sidebar on tablet and desktop, sheets/drawers for editing (no full-page forms).
- Client store: a normalized entity cache keyed by ID. Every mutation goes through
mutate(), which (1) applies the change locally right away, (2) sends it, and (3) on failure rolls back and shows a toast. SSE events are merged in byrev, so a device's own echoes do nothing. - Small hand-picked dependencies only: a date helper, tree-shaken icons, and drag-and-drop (choose in 2.6). Charts are custom SVG components (§6.2b).
- Bundle budget: < 150 KB gzip for the initial route, enforced by a CI check (target in the spec is < 300 KB).
A.4 Core data model decisions (the ones that are hard to change later)¶
- Everything actionable is a
taskrow. One-off tasks, recurring occurrences and workflow steps are all tasks. A recurring item is aseriesrow (RRULE, mode, template fields) that spawns task rows withseries_idandoccurrence_key(date or window). A workflow run is aworkflow_instancerow whose steps are task rows. Because of this, completion, day-plan entries, dependencies, focus sessions, task types, groups and the external reference only need to work on one kind of thing. Occurrences are created lazily within a horizon (from the past rollover up to today + N days, plus on demand for a viewed date), never as an unbounded expansion. - Completion and history:
tasks.status(open|done|missed|skipped|wont_do) pluscompleted_at/completed_by. An append-onlytask_eventslog records carried, missed, snoozed, skipped, completed and reopened events, each with the actor and source (app|api|print|integration). Stats and streaks are computed from this log. - Task types are data. A
task_typestable with config columns:day_end_behavior(carry|expire|window|deadline),counts_for_streak,shows_overdue,shows_carry_count,window_overflow(miss|roll). Built-in rows are seeded. Users may add their own in v1 (needs Q-1). The rollover engine indomainreads only this config, with no special cases by type name. - Ownership and visibility: a task or project has
owner_user_idorowner_group_id(DB CHECK: exactly one). A task also has a nullableassignee_user_id, unused until Q-4 is decided. A singlevisible_to(user)SQL fragment plus a Rust predicate is used by every query and by SSE filtering. Personal data (day records, metrics, focus sessions) is always filtered by user only, never by group. - Day plan is a separate layer:
day_plan_entries(user_id, date, task_id, position, start_time?, duration_min?, block_id?). Tasks know nothing about day plans. - External reference from day one:
tasks.ext_source,ext_id,ext_url,ext_payload JSON, with a unique index on (ext_source,ext_id) for deduplication (needed by Mealie and GitHub later). - "Logical date": one domain function maps (instant, user timezone, day-end time) to the local date it belongs to. Every "today" comes from this function. The server is the source of truth, and the client asks the server what "today" is.
Part B. Phases and chunks¶
Legend: Deliverables = what exists afterwards · Tests = what must be covered · Done when = acceptance check.
Phase 0: Planning (this document)¶
- [x] 0.1 Confirm plan. Owner reviews Part A and Part C and answers or confirms the defaults.
Record the answers in
docs/DECISIONS.md(ADR-style, one short entry per decision).
Phase 1: Foundation (§7.1, §3, §4, §4b, §6.1)¶
- [x] 1.1 Scaffold and toolchain (Makefile instead of justfile, D-26; CI in
.github/workflows/ci.yml) - Deliverables: Cargo workspace (
domain,server), SvelteKit app inweb/,justfile(devruns Vite with a proxy to the backend, plustest,lint,build), rustfmt/clippy, prettier/eslint/svelte-check,.editorconfig,.gitignoreadditions (data/,target/,node_modules/,web/build/). Check and pin current stable versions of Axum, sqlx, Svelte and SvelteKit. - CI (GitHub Actions): fmt, clippy
-D warnings, cargo test, web lint/check/test, build. -
Done when:
just devserves a hello page via the Rust server, and CI is green. -
[x] 1.2 Server skeleton
- Deliverables: config loading (env + defaults + validation), tracing,
/healthz, graceful shutdown, embedded SPA with fallback and precompressed assets, problem+json error type, request ID, compression, proxy-awareness helper (PUBLIC_URL/TRUST_PROXY). -
Tests: config parsing; scheme/host resolution with and without forwarded headers.
-
[x] 1.3 Database and conventions
- Deliverables: sqlx pool (WAL, pragmas), migration runner at startup,
revcounter, a shared helper/trait for create/update/soft-delete (stamps timestamps andrev), ULID type. First migration:users,sessions,api_tokens,settings,projects,tasks(including the A.4 columns: owner, assignee, ext_*, attribute columns nullable for now),task_types(seedcarry_on,expires),task_events. - Tests: migrations apply cleanly on an empty DB; soft-delete hides rows;
revincreases monotonically under concurrent writes. -
Note: add attribute columns now (estimate, difficulty, importance, urgency, actual_minutes) so Phase 2 doesn't need an awkward migration.
-
[x] 1.4 Auth
- Deliverables: initial admin created from env on first boot; login/logout; session
middleware;
meendpoint; change password; admin-only user CRUD (no public sign-up); API token create/list/revoke; Origin check for cookie-based writes; login rate limit. - Tests: wrong password, expired or revoked session/token, CSRF origin rejection, cookie
Secureflag over HTTP vs HTTPS (proxied), admin-only routes. -
Done when:
curlwith a bearer token and the browser with a cookie both reach/api/v1/me. -
[x] 1.5 Projects and tasks API (OpenAPI 3.1 via utoipa at
/api/v1/openapi.json, viewer at/api/docs) - Deliverables: projects CRUD and archive; tasks CRUD, complete/reopen, move between
projects, reorder (fractional index), inbox (
project_id IS NULL), list filters;GET /changes?since=; utoipa OpenAPI; ts-rs type generation script. -
Tests: integration tests via
tower::ServiceExt::oneshoton an in-memory DB, covering CRUD, reorder, move, archive hiding, tombstones in the change feed, and ownership checks (a user cannot read another user's tasks). -
[x] 1.6 Realtime event stream
- Deliverables: event bus;
GET /api/v1/eventsSSE with heartbeat andLast-Event-IDresume; events emitted from the shared helper for every entity change; visibility filter hook (user-only for now, groups added in Phase 4). -
Tests: subscriber receives own-user events and not other users' events; resume after reconnect.
-
[x] 1.7 Frontend shell (Vitest store/order tests and a CI bundle budget)
- Deliverables: routing, responsive layout (tab bar / sidebar), theme tokens + dark mode,
login page, API client on top of generated types, normalized store with
mutate()(optimistic + rollback), SSE subscription with reconnect, toast system, empty states. - Tests: vitest for the store (optimistic apply, rollback on error, SSE merge ignores echoes).
-
Done when: login works on a phone and on desktop, and the bundle stays within budget.
-
[x] 1.8 Projects and tasks UI
- Deliverables: quick-add inbox (one input, Enter to add), project list (create, rename, archive), task list (complete with animation, inline edit, detail sheet for notes and due date), move-to-project menu, reorder via up/down menu (drag arrives in 2.6); settings page (change password, API tokens, admin user management).
-
Done when: two browser windows stay in sync live; actions feel instant with network throttling set to "Slow 3G".
-
[x] 1.9 Packaging and phase gate (multi-arch CI image → GHCR; Caddy example in
docs/examples/caddy, tested over HTTPS 2026-10-06; arm64 build itself only verified once CI runs it) - Deliverables: multi-stage Dockerfile (amd64 and arm64),
docker-compose.ymlwith./datavolume andPORT,scripts/measure.sh(image size, idle RSS viadocker statsafter 60 s, initial gzip/brotli payload), README quick start,docs/DECISIONS.mdstarted,docs/API.md. - Done when:
docker compose up -don a clean machine works over plain HTTP and behind a Caddy HTTPS proxy (sample Caddyfile indocs/). Phase gate passes (Part D).
Phase 2: Day plan (§6.2, §6.2c, §6.6, basic §6.12)¶
- [x] 2.1 Time model and user preferences (needs Q-2) (timezone, day end, locale, week start;
day_bounds/week_boundswith DST tests) - Deliverables: user prefs (timezone, day-end time, week start, locale);
domain::timewithlogical_date(), day bounds,HH:MMhandling. -
Tests: DST transitions (Europe/Tallinn spring/autumn), a day end of 04:00 around midnight, timezone change mid-use. Check these carefully, since everything later depends on them.
-
[x] 2.2 Task attributes (needs Q-18, Q-22)
-
Deliverables: API and validation for estimate, difficulty, importance, urgency, actual_minutes, due date; UI quick-setters (chip rows, not dropdowns); badges in lists.
-
[x] 2.3 Task-type engine and day rollover (needs Q-1)
- Deliverables:
domain::rollover, a pure function from (task, type config, day outcome) to the resulting state and events; a rollover job that runs per user once their day end passes (idempotent vialast_rollover_dateper user, and catches up over several days if the server was down); carry counter; per-item overrides API: skip today, snooze to date, won't do, all logged intask_events. Typescarry_onandexpiresare active. -
Tests: carry vs expire at the boundary; catching up after 3 days of downtime; overrides; idempotency (running twice gives the same result).
-
[x] 2.4 Day plan API
- Deliverables:
day_plan_entriesmigration; pull into day, remove, reorder, set/clear time slot and duration; ready stack endpoint (open, not planned elsewhere, not blocked once Phase 3b lands);GET /api/v1/days/{date}aggregate (entries, due tasks, carried-over tasks, and later routines, events and blocks) so the Today view needs only one request. -
Tests: one entry per task per day; carried tasks move to the next day according to type; the aggregate respects visibility.
-
[x] 2.5 Today view (landing page)
- Deliverables: Today as the default route; sections for Now/Next, scheduled timeline (with a now marker), ordered unscheduled list, due/overdue, carried over (with "×3 days" badges); placeholders for events and routines; a "pull from ready stack" sheet; date navigation (yesterday/tomorrow).
-
Done when: opening the app on a phone shows the day in one screen within ~1 s on LAN.
-
[x] 2.6 Basic drag and drop (own pointer-based layer, D-36: reorder, drop onto projects/Inbox/Today, timeline scheduling/move/resize; tested in headless Chrome with mouse and emulated touch, real-device check still advisable)
- Deliverables: choose a DnD approach (evaluate
svelte-dnd-actionagainst a small custom pointer-events action; pick on bundle size, touch quality and keyboard support, and log the choice in DECISIONS.md). Reorder within a list, drag from the ready stack into the day, drag onto a time slot. Long-press to start on touch, scrolling must not trigger a drag, keyboard pickup/move/drop, and a menu alternative for every drag. -
Done when: it works on a real phone (iOS Safari + Android Chrome) and with the keyboard only.
-
[x] 2.7 Phase gate (2026-10-06: tests green, measurements logged, HTTP + HTTPS browser smoke tests, no secrets in trace logs)
Phase 2a: Planning ritual, basic (§6.2d)¶
- [x] 2a.1 Plan status and preferences (needs Q-8, Q-9) (
day_plansdraft/planned, plan mode and times, available-day window; free time = window minus scheduled, for today only what's left) - Deliverables:
day_plan_status(user, date, planned_at); preferences (evening / morning / both, planning time); API to mark a day planned or unplanned; free-time calculation (day window minus fixed items; calendar events join in Phase 5). - [x] 2a.2 Planning wizard (
/plan/<date>, 5 steps, resumes from the server-side draft step, lazy-loaded) - Deliverables: a 5-step full-screen flow (Review → Look ahead → Pick → Arrange → Confirm), each step one screen with a sticky "Next"; a running total of planned time vs. free time with a non-blocking overbooking warning; it resumes where the user left off if interrupted. The Review step uses the outcomes logged by the rollover engine.
- Done when: a plan for a typical day can be made in under 2 minutes on a phone.
- [x] 2a.3 Reminders (in-app) and fallback (needs Q-5) (
notifymodule, reminder job once per kind and day, toast + dismissible banner) - Deliverables: notification abstraction (
Notifiertrait: in-app via SSE now, with Web Push and ntfy added in Phase 6); a reminder job at the planning time; an "Unplanned: plan your day" banner in the Today view; the fallback Today view needs no plan. - [x] 2a.4 Phase gate (2026-10-06: tests green, measurements logged, browser run of the full ritual on desktop and phone)
Phase 2b: Views and focus (§6.7, §6.9, §6.12)¶
- [x] 2b.1 View framework (list/board/matrix on All tasks, Inbox and projects; per-scope prefs in
users.prefs): view switcher (list / kanban / matrix), filters stored per view in server-side user prefs (so they follow the user across devices). - [x] 2b.2 Kanban (in progress =
started_at, D-44; also by difficulty): columns by status (open / in progress / done), or by project or task type; drag between columns changes the matching field; adds anin_progressstatus. - [x] 2b.3 Eisenhower matrix (needs Q-22): four quadrants; drag sets importance and urgency; blocked tasks are dimmed (once 3b lands).
- [x] 2b.4 DnD everywhere and accessibility pass (board/matrix targets, horizontal auto-scroll, aria-live announcements for drops, menu/sheet alternatives): drag tasks onto projects in the sidebar; one shared DnD layer for all views; screen reader announcements; menu alternatives everywhere.
- [x] 2b.5 Focus sessions backend (needs Q-20)
- Deliverables:
focus_sessionstable; a server-side timer state machine per user (idle → work → break → long_break, pause/resume/skip), stored as start time + accumulated pause, so any device can reconstruct the countdown from the server state. Work sessions add totasks.actual_minutes. SSE updates. - Tests: state transitions, pause accounting, long break after N sessions, recovery after a server restart.
- [x] 2b.6 Focus view UI: distraction-free page (title, notes, step context), large timer,
start/pause/skip, sound +
navigator.vibratecue, a mini-timer pill visible on all pages, and done / snooze / next-planned-task actions. - [x] 2b.6a Places (SPEC §6.16, D-45; done 2026-10-06, D-50):
placesper user/household (name, optional coordinates + radius); optionalplace_idon tasks with a per-project default for new tasks; place chip on rows; a "where am I" filter on the ready stack, pull-in sheet and views, picked manually, or detected by GPS when enabled in Settings and permitted by the browser (secure contexts only; falls back to manual). - [x] 2b.7 Phase gate (2026-10-06: tests green, measurements logged, browser run of views and focus on desktop and phone)
Phase 3: Recurrence and routines (§6.3, remaining §6.2c types)¶
- [x] 3.1 Recurrence spike and module (rrule 0.14: all edge cases pass, nothing hand-rolled, D-46)
- Check how mature and well maintained the
rrulecrate is; checkchrono-tzfor timezones. Report any gaps to the owner. Then builddomain::recurrence: expand an RRULE (with DTSTART, TZID, EXDATE, UNTIL/COUNT) into local dates/times within a range. - Tests: daily/weekly/monthly/BYDAY/BYSETPOS, last day of month, DST, EXDATE, COUNT across the horizon.
- [x] 3.2 Series and occurrence materialization
- Deliverables:
seriestable (template fields, rrule, mode, task type, project/owner); materializer job that spawns task rows within the horizon (idempotent via a unique key onseries_id, occurrence_key); "edit this occurrence" (detaches into an exception) vs "edit all future" (splits the series at that date: close the old one with UNTIL, start a new one); deleting future occurrences. - Tests: completing one occurrence does not affect others; editing all future keeps past history; the materializer is idempotent; changing the horizon.
- [x] 3.3 Anchored routines: occurrences with a fixed time appear automatically in the
Today view timeline; default type
expires; missed occurrences are logged. - [x] 3.4 Flexible routines and the window type (needs Q-3)
- Deliverables: series with
times_per_windowand a window (week/month); spawns N task rows per window ("Laundry 1/2", "2/2") that can be done on any day;windowtask type activated (overflow: miss or roll into the next window, per config); UI shows "1 of 2 this week". - Tests: window boundaries respect week start and day end; overflow behavior; completing early in the window.
- [x] 3.5 Deadline type, routines UI and streaks
- Deliverables:
deadlinetype (carries on until the due date, then overdue); routines page; recurrence editor with presets (daily, weekdays, weekly on…, every N days, N times per week) plus a raw RRULE field for advanced use; streak calculation fromtask_events(only types withcounts_for_streak). - [x] 3.6 Phase gate (2026-10-06: tests green, measurements logged, browser run of routines)
Phase 3b: Prerequisites and workflows (§6.3b)¶
- [x] 3b.1 Dependency graph (needs Q-6)
- Deliverables:
task_dependencies(task_id, depends_on_id);domain::depswith cycle detection (DFS over the affected subgraph) and readiness evaluation; a storedtasks.blockedflag kept up to date transactionally on every change, so the ready stack stays a cheap query; behavior when a prerequisite is skipped or deleted follows Q-6; an SSE "became ready" event. - Tests: reject direct and indirect cycles; diamond graphs; dependencies across projects and groups; completing the last prerequisite unblocks; reopening a prerequisite blocks again; blocked tasks never "miss" at rollover (§6.2c).
- [x] 3b.2 Blocked UI: blocked badge with "waiting on …" links in project lists; hidden from the ready stack and the planner; dimmed in the matrix; add/remove prerequisite UI (task picker).
- [x] 3b.3 Workflow templates (steps/variants as JSON on the template; linear chains, D-51)
- Deliverables:
workflow_templates,workflow_steps(title, type, estimate, wait_minutes),workflow_step_edges,workflow_variants+ per-variant step inclusion; CRUD API;instantiate(template, variants[])creates one chain of tasks per selected variant with dependencies wired, all in one transaction; seed an example "Laundry" template. - Tests: variant inclusion and skipped steps re-linking the chain (wash → fold when dry and iron are skipped); everything rolls back if instantiation fails.
- [x] 3b.4 Wait time:
ready_aton dependent tasks (prerequisite done + wait); the scheduler flips them to ready; "mark ready now" override; countdown shown in the UI. - [x] 3b.5 Workflow UI (JSON export/import of templates (Q-12) still open): template editor as an ordered step list with "skip in variant" toggles (no graph editor); "Start Laundry" sheet with variant multi-select; chain progress dots on each task.
- [x] 3b.6 Routine-attached workflows (needs Q-7) (runs start on their day; per-routine override of D-7 not yet): a series can reference a template; each occurrence spawns an instance; policy for a still-unfinished previous instance (Q-7).
- [x] 3b.6a Occasions: birthdays and namedays (SPEC §6.17, D-57; the calendar is downloaded, not bundled)
- Deliverables: bundled nameday calendar (data file + licence check);
peoplewith name(s) and optional birthday; "names of interest" picker; occasion templates = workflow templates whose steps carry a day offset from the occasion (e.g. buy present −2 d → greet 0 d, with a dependency); a yearly series per person/occasion spawns them ahead of time; default task type per occasion kind, editable. - Tests: nameday lookup incl. leap years and names with several days; offsets across month and year boundaries; greet stays blocked until the present step is done; no duplicate spawns.
- [x] 3b.7 Phase gate (2026-10-06; 3b.6a Occasions still waits for Q-24)
Phase 4: Groups (§6.4)¶
- [x] 4.1 Groups and visibility
- Deliverables:
groups,group_members; admin and group-owner management; build out thevisible_tofunction (A.4.4) and route every list/detail/SSE path through it. - Tests: a visibility matrix (owner / group member / non-member / admin) for projects, tasks, series, workflow instances, day-plan entries and personal data. This test is required to pass before the phase can close.
- [x] 4.2 Group projects, tasks and chores (needs Q-4)
- Deliverables: create a project or task for a group; group tasks show up in every member's
ready stack; any member completes it, and
completed_byis shown; recurring group chores use the same series system (one shared occurrence, not one per member); a member's day plan can include a group task, and if another member completes it, it shows as done for everyone. - [x] 4.3 Live sync between members: SSE fan-out to group audiences; membership changes update subscriptions; UI shows group badges and avatars on completions. E2E test: two users, one completes the garbage chore, and it disappears for the other within 1 s.
- [x] 4.4 Phase gate (2026-10-06: visibility matrix + live-stream tests, two-browser run)
Phase 5: Calendar read (§6.5)¶
- [x] 5.1 CalDAV and iCal spike (D-55) (report to the owner before building on it)
- Add a
radicaleservice to a dev compose profile. Prototype discovery (current-user-principal→calendar-home-set→ list calendars via PROPFIND) and acalendar-queryREPORT with a time range, usingreqwest+quick-xml. Compare iCal parsers (icalendarwith its parser feature vs.ical) on VTIMEZONE, RECURRENCE-ID and all-day events. Expected result: the CalDAV transport is hand-rolled (small); parsing and RRULE use crates. Log this in DECISIONS.md. - [x] 5.2 Provider abstraction and settings
- Deliverables:
CalendarProvidertrait (list_calendars,fetch_events(range), and unimplementedput_event/delete_eventreserved for later write-back); the CalDAV implementation; encrypted credential storage; settings API + UI (URL, user, password, "test connection", calendar selection and colors). The password is write-only in the API. - [x] 5.3 Sync engine and expansion
- Deliverables: periodic and on-demand sync; incremental via ctag/etag (sync-token where supported); cache of raw VEVENTs + expanded instances for a rolling window; handles RRULE, EXDATE, RECURRENCE-ID overrides, all-day and floating times, TZID; sync status and last error shown in settings; on failure, keep the last known data and show a warning.
- Tests: fixture
.icsfiles (recurring with exceptions, all-day across DST, floating time, non-UTC TZID, cancelled instances); mocked HTTP for the PROPFIND/REPORT XML. - [x] 5.4 Events in the UI: events in the Today timeline (fixed, read-only); free-time gaps between events; agenda/week view; the planning wizard's free-time number now subtracts events.
- [x] 5.5 Phase gate
Phase 5a: Conflicts and block planning (§6.8, §6.11)¶
- [x] 5a.1 Conflict detection:
domain::conflicts, a pure interval-overlap function returning conflict pairs (task↔event, task↔task, block↔event); included in the day aggregate; alert banner and inline markers; quick fixes (move to next free slot, shorten, unschedule); notification through theNotifier. Tests: touching vs. overlapping edges, all-day events (ignored or blocking: configurable per calendar), midnight and day-end crossings. - [x] 5a.2 Time blocks and day-plan templates:
time_blocks,day_plan_templates, template blocks, weekday assignment; applying a template to a date (idempotent, editable afterwards); block view UI; drag tasks into blocks and resize/move blocks (with a menu alternative). - [x] 5a.3 Auto-suggest planner (needs Q-19)
- Deliverables:
domain::planner::suggest(blocks, events, ready_tasks, prefs) -> Plan. Stable sort by a documented score (deadline proximity, urgency/importance, difficulty matched to block theme), greedy fit into free time inside blocks, never overlapping events, ties broken by ID so results are deterministic. Each placement includes machine-readable reasons that the UI shows ("Hard + due tomorrow → Deep work block"). Integrated as an option in the wizard's Arrange step: accept all / accept some / reject. - Tests: golden tests (fixed inputs → exact plan); never places on an event; respects readiness and task types; overbooked input → leftovers listed with a reason.
- [x] 5a.4 Phase gate (D-58)
Phase 5b: Daily summary and tracking (§6.2b)¶
- [x] 5b.1 Day records and reflection (needs Q-16): lazily created
day_records; free text + optional prompt layout (went well / didn't / tomorrow) with autosave; the evening flow chains reflection → plan tomorrow. - [x] 5b.2 Metrics (needs Q-23):
metric_definitions(built-in mood and weight, plus custom number/scale/yes-no with unit and reminder),metric_entries(several per day); quick-log widgets on the Today view (mood emoji row, weight input); unit preference with conversion. - [x] 5b.3 Day summary: planned vs. done, missed vs. carried (shown separately), events, focus time, estimate vs. actual, routine streaks; browse past days in a month calendar.
- [x] 5b.4 Trends: small SVG chart components (line, bar, heat-strip); week/month/year ranges per metric; mood vs. routine-completion overlay. No chart library.
- [x] 5b.5 Export/import and metric reminders (needs Q-17): JSON export of all of a
user's data; CSV per metric; CSV import for metrics if Q-17 says yes; metric reminders
through the
Notifier. - [x] Privacy test: no 5b endpoint or SSE event ever reaches another user, including group co-members.
- [x] 5b.6 Phase gate (D-59)
Phase 5c: Long-term goals (§6.10)¶
- [x] 5c.1 Goals backend (needs Q-21): goals, milestones, links to projects and tasks; derived progress (share of linked items done) with manual override; group goals via the ownership model.
- [x] 5c.2 Goals UI and reviews: goals overview with progress bars, goal detail with milestones and linked work; weekly/monthly review prompt that ties into reflection; optional weekly planning (§6.2d "later").
- [x] 5c.3 Phase gate
Phase 6: PWA and polish (§7.6) → v1.0¶
- [x] 6.1 PWA: manifest and icons; a service worker registered only in a secure context, caching the app shell and recent API reads (stale-while-revalidate); offline read-only banner. Plain HTTP must keep working unchanged.
- [x] 6.2 Notifications: Web Push (VAPID keys generated into
data/) as aNotifierbackend when HTTPS is available; optional ntfy backend; per-user reminder settings covering planning, metrics, focus end and conflicts. - [x] 6.3 Backup and restore: SQLite online backup (
VACUUM INTO) on a schedule intodata/backups/with retention; an admin download endpoint; restore documented in the README. - [x] 6.4 Performance and accessibility pass (D-66): Lighthouse on a mid-range phone profile, bundle audit, query plans/indices for the day aggregate, accessibility audit (contrast, focus order, reduced motion).
- [x] 6.4b Calendar events ↔ work (owner request, D-68): assign an event (all instances of a recurring one) to a project; attach todos to an event; event sheet, project page list.
- [x] 6.5 Release v1.0 (owner go-ahead 2026-10-07): complete README (install, proxy setups for Caddy, Traefik and Tailscale, backup, upgrade), CHANGELOG, tagged multi-arch image, final resource report.
Phase 7: Later (after v1.0, in the order given in §7.7)¶
v1.4 (D-93) takes 7.1, 7.2, 7.3, 7.6 and 7.7; 7.4 (thermal printing) is dropped and 7.5 stays postponed.
- [ ] 7.1 Integration framework + Mealie shopping list (parked, D-101):
IntegrationProvidertrait, encrypted settings, polling job, last-known state + warning on failure; develop against Mealie v3.25.0 (the owner's version, D-96) in a local container with its OpenAPI. One open "Go shopping" task per list (deduplicated viaext_source/ext_id), auto-complete when the list is empty, optional minimum item count. - [ ] 7.2 Mealie meal plan (parked, D-101): one task per meal entry with a recipe link, ingredients and
steps shown in the focus view, prep+cook time as the estimate, type
expires; generic "prepare lunch" tasks resolve against the meal plan. - [x] 7.3 Print, A4: print-CSS day sheet with stable item codes and a QR code to the reconcile page.
- [ ] 7.4 Thermal printing + reconcile (needs Q-13, Q-14): ESC/POS over TCP 9100,
58/80 mm layouts, scheduled morning print; signed, expiring reconcile links that can only
complete the printed items (
source=print). - [ ] 7.5 Child profiles (needs Q-15, only if needed): restricted role, simplified UI, optional parent confirmation.
- [x] 7.6 GitHub, GitLab and others (D-97, D-99): connect accounts with access tokens (GitHub, GitLab.com or self-hosted, Gitea/Forgejo; encrypted like the calendar password); a polling job brings in what's yours (assigned issues, assigned PRs/MRs, review requests, mentions; each kind on/off per account) as tasks with a link, deduplicated by source and id; repository rules choose the project (else the inbox); closed, merged or unassigned upstream completes the task; read-only towards the forge; tests with recorded API answers; help and CHANGELOG.
- [x] 7.7 Calendar write-back:
put_eventon the provider; write planned blocks as busy events to a dedicated calendar. - [ ] 7.8 Native app (Linux desktop app moved to Phase 9, D-78; phones stay on the PWA, D-61): evaluate Tauri 2 reusing
web/, with token auth and the change feed.
Phase 7a: Waiting, default tasks, project ideas, health check-in and tour (v1.2, D-70, D-71, D-72, D-75, D-77)¶
Developed on the v1.2 branch. Waiting: work that's been handed off and only needs a check
later (a model training, a slow build, an e-mail waiting for a reply). Default tasks: ready-made
tasks with a checklist ("Do laundry": sort, wash, hang, fold) created in two taps. Project
ideas: projects that aren't started yet, kept with a description.
- [x] 7a.1 Server:
tasks.waiting_since,check_back_at,waiting_note,waiting_by(migration);PATCH /tasks/{id}withwaiting/check_back_at/waiting_note, and clearing it; waiting tasks carry on at day end whatever their type; atcheck_back_ata reminder through the usual channels (in-app, push, ntfy) and the task stops waiting; overlaps and the planner ignore waiting tasks; tests (rollover, reminder once, completing or editing clears waiting). - [x] 7a.2 UI: "Waiting" column on the status board (between In progress and Done); "Wait for results…" in the task sheet and when ending a focus session, with quick choices (in 30 min, 1 h, 2 h, 4 h, tomorrow morning, a time, no time); waiting tasks leave Up next and the ready stack and show a "check back 15:30" chip; a check-back marker on the timeline; a Waiting section in Today; due check-backs at the top of Up next; help and CHANGELOG.
- [x] 7a.3 Checklists:
tasks.checklist(JSON items{id, text, done}, ≤ 50, migration) and on routines (each occurrence gets a fresh copy); edit, tick and reorder in the task sheet and the focus view; "2/4" on task rows, the timeline and board cards; ticking the last item offers to complete the task; carried-over tasks keep their ticks; tests. - [x] 7a.4 Default tasks (task templates):
task_templates(personal or group-owned, like workflow templates): name, title, notes, checklist, estimate, difficulty, importance, urgency, task type, project, place. "Save as default task" in the task sheet; manage them in Settings; quick-add suggests matching ones as you type ("laun…" → Do laundry) and has a button listing them; creating copies the fields with the checklist unticked; export and import with the other data; tests; help and CHANGELOG. - [x] 7a.5 Project ideas and descriptions:
projects.description(all projects) andprojects.status(active|idea, migration; archiving staysarchived_at); create a project as an idea, "Activate" turns it active, "Move to ideas" the other way; ideas stay under Projects with a grey "Idea" tag (owner choice), subprojects follow their idea parent; the project page shows the description (editable, plain text with links) above the tasks; an idea's tasks are kept out of Today, Up next, the ready stack, the planner, overdue and reminders, and aren't missed or rolled over, until it starts; tests; help and CHANGELOG. - [x] 7a.6 Project marks (owner request, D-74): automatic colour + shape per project (domain picker mirrored in the client, migration backfill), empty grey circle for ideas, shape picker in the project menu; ideas can be added inside active projects.
- [x] 7a.7 Health check-in (owner request, D-75):
health_days(user, date, statusgreat | ok | unwell | sick | injured, kind, note; migration; one row per user and day); domain validation of status/kind pairs; sync and export; a Health row on the Today card (one tap for great/OK/unwell, a second step for what sickness or where the injury, optional note), also in the planner's reflect step and editable for past days from the summary; marker on the month calendar, a health strip in Trends; personal only (never shown to group members); no effect on streaks or planning; tests; help and CHANGELOG. - [x] 7a.8 Guided tour (owner request, D-77): offered once on first sign-in (user pref), replayable from Help and Settings; each step opens its page and highlights what it describes, on desktop and phone; tests for the steps and card placement; help and CHANGELOG.
Phase 8: Sync between Streamline servers (v1.4, D-69, D-93; as built: D-100)¶
Shared projects across instances: each collaborator keeps their own server. Home-server model: the sharer's server is authoritative; members' servers hold a replica and forward writes.
- [x] 8.1 Federated identities: remote members (
name@host) as login-less user rows; group membership for remote members; how they're shown (name, server). - [x] 8.2 Invites and handshake: per-project invite link (expiring, single use); the
collaborator's server redeems it over HTTPS and gets a per-link secret (revocable);
server identity check; outbound calls through
net.rs. - [x] 8.3 Replication feed: project-scoped change feed and live stream for a link (project, subprojects, tasks, routines); the replica server applies changes as read-only mirrors; routines, rollover of shared items and occurrences run only on the home server.
- [x] 8.4 Forwarded writes: edits to replicated items go to the home server as the remote member (same permission checks as local members); the result comes back via the feed. Home unreachable → read-only with a banner (D-69).
- [x] 8.5 UI: invite/join flow, remote members in groups, server status per shared project, leaving/removing (replica deleted).
- [x] 8.6 Tests and security review: two servers in one test process (join, edit both ways, remove, revoke, home down, hostile peer input); compose file with two instances; review of the new server-to-server surface.
Phase 9: Desktop app, checklists everywhere, focus options (v1.3, D-78..D-83)¶
Developed on the v1.3 branch. Order: the small web features first (each releasable on its
own), then the server's merge support, then the desktop app on top of it.
- [x] 9.1 Checklists complete their task (D-80): on the server, ticking the last item completes the task and unticking one on a done task reopens it (routine occurrences too, with their usual completion side effects); drop the "complete it?" prompt in the client; tests; help and CHANGELOG.
- [x] 9.2 Checklist popover and Agenda sublist (D-81): hover popover on timeline items with a checklist (tick, progress, open the task), long-press on touch, keyboard access (focus + Enter), stays on screen near edges; indented tickable items under tasks in the Agenda; tests for placement; help and CHANGELOG.
- [x] 9.2a Steps logged per day (D-84):
done_at/done_byon checklist items (server-stamped, offline tick times kept), astepentry in the day log; the timeline's 2/4 chip moves to the second line so the title keeps the first; tests; help and CHANGELOG. - [x] 9.2b Default-task kinds and quick-add list (D-86):
task_templates.kinds(migration, validation indomain::checklist), kinds editor in Settings → Default tasks; quick-add opens the list on focus, matches kinds, keyboard picking, a kind chooser that adds one task per kind; tests; help and CHANGELOG. - [x] 9.3 Server merge for offline edits (D-79):
crates/domain::merge(per-field newest wins, checklist per-item merge, delete beats edit) with tests; writes may carrybasevalues andedited_at; the response lists overwritten fields; creates with client ids stay idempotent; covers tasks, day entries, routines, projects and tracking records the client edits; OpenAPI and TS types. - [x] 9.4 Desktop app shell (D-78):
crates/desktop(Tauri 2) with the builtweb/; first run asks for the server URL and signs in for a device token (keyring); tray, close-to-tray, start at login; the web client detects the desktop app; CSP and outbound checks as in D-67. - [x] 9.5 Local replica and outbox (D-78, D-79): local SQLite replica fed by
/syncand/events; the UI reads and writes through the local engine; outbox replayed in order on reconnect with base values (9.3); "offline, changes will sync" banner instead of the read-only one, pending-change count, "synced with changes" notice; tests (offline edits, conflicts, delete vs edit, restart with a full outbox). - [x] 9.5b "This computer only" mode (D-88): the desktop app can run the Streamline server
in-process on 127.0.0.1 (data in the user's data folder) instead of connecting to one;
first-run choice between the two; background jobs (routines, rollover, reminders,
backups) run while the app runs; moving to a server later by starting one on a copy of
the data folder (password for
meset in Settings); tests; help. - [x] 9.6 Focus options (D-82): mute and screens options on the focus start screen (off by
default, last choice remembered), stored with the focus session and synced; desktop:
mute/restore through
pactl, overlay or full-screen timer windows on every monitor (follows monitors being plugged in), break colours; browser shows "needs the desktop app"; tests for the state machine (what is muted/shown in which phase); help and CHANGELOG. - [x] 9.7 Packaging (D-83): release workflow builds the Linux app (tarball + .deb);
packaging/aur/streamline-desktop-binandstreamline-desktopPKGBUILDs, .desktop file and icons;namcapclean; build both in a clean Arch container; README section on installing and on how the owner pushes the packages to the AUR. - [ ] 9.8 Phase gate (Part D) plus: desktop app memory at idle, offline smoke test (pull the network, edit, reconnect), security review of the local engine and token storage. Done 2026-10-14: tests, fmt and clippy green (CI not run yet: not pushed); resource log updated (image 15.0 MB, idle 7.8 MiB, 97.9 KB initial; desktop app 294 MiB PSS at idle); offline smoke test in the real app passed; security review done and fixed (D-92); no test passwords or tokens in the test, server or app logs; README, DECISIONS, OpenAPI and TS types current. Left for the owner: smoke test on a phone and behind the HTTPS proxy, and the pre-release tag.
Phase 10: Productivity (v1.4, D-93)¶
Developed on the v1.4 branch, with Phase 7's picked integrations and Phase 8. Order: the
productivity features first (small, used daily), then 7.3, 7.7, 7.6, 7.1–7.2, then Phase 8,
then the gate.
- [x] 10.1 README badges: CI, latest release, licence, image, and what the CI enforces (rustfmt, clippy with warnings as errors, tests, bundle budget).
- [x] 10.2 Command palette and keyboard shortcuts: Ctrl+K (⌘K) searches tasks (titles,
notes, checklist steps), projects, routines, journal and pages, and runs actions on the
chosen item (open, plan today or tomorrow, focus, complete); single-key shortcuts
outside text fields (n new task, / search, g t Today, g i Inbox, g p Plan, j/k move,
x complete, ? lists them); pure ranking in
web/src/libwith tests; help and CHANGELOG. - [x] 10.2b Week view (D-94):
/weekwith two modes, remembered: a planner (7 day columns with every planned task, each day's load against free time, drag tasks between days and in from an unplanned list, add to a day) and a calendar (7 days on an hour grid with events, timed tasks and time blocks; drag to another day or time). The overlap layout moves from the timeline into a tested function both use; sidebar entry,g w, the palette; help and CHANGELOG. - [x] 10.3 Inbox triage: process the inbox one item at a time with one-key decisions (do now, today, tomorrow, pick a project, schedule, waiting, delete, skip), progress and undo; tests; help and CHANGELOG.
- [x] 10.4 Weekly review: a guided review: last week's numbers, overdue and stale tasks, waiting items, projects without a next step, ideas to start or drop, then plan next week; the goal review folds in; remembers when it was last done and reminds on the chosen day; tests; help and CHANGELOG.
- [x] 10.5 Better estimates: from estimates vs. focus time actually spent (domain, tested): the usual overrun overall and per project and type of task, a suggested estimate when planning and in the task sheet, and planning load using realistic times (optional); Trends shows estimate accuracy; help and CHANGELOG.
- [x] 10.6 Morning digest: one message each morning (time per user, off by default) through push or ntfy: today's plan, fixed times, what's due, waiting items to check; tests for the content; help and CHANGELOG.
- [x] 10.8 Quick-add extras (owner request, D-103): steps typed in while adding; add as done, as waiting, or as ongoing.
- [x] 10.9 Ongoing tasks (owner request, D-102): kept at over a period, "worked on it" per day, never carried or missed, finished by hand; domain + web logic tested.
- [x] 10.10 Habit goals (owner request, D-105): goals that are habits, answered per day (yes / partly / no) in Track and the reflection, judged per week in the review.
- [ ] 10.7 Phase gate (Part D) for v1.4. Done 2026-10-15: tests, fmt and clippy green (CI not run yet: not pushed); resource log updated (image 16.2 MB, idle 9.0 MiB, 110.4 KB initial); two-server, forge and ongoing flows tried in the real app (headless Chrome, desktop and phone width); security review done and fixed (D-104); no test passwords, tokens or link secrets in the test or server logs; README, DECISIONS, Help, CHANGELOG, TS types current (OpenAPI is generated at runtime). Left for the owner: smoke test on a phone and behind the HTTPS proxy, push so CI runs, and the release (tag, GitHub release, AUR).
Phase 11: Tracking, routine days, done times, goal tree and rules (v1.5, D-107)¶
Developed on the v1.5 branch. Owner requests of 2026-10-17. Migrations: 0036 tracking,
0037 goal tree and rules.
- [x] 11.1 Tracking tab and metric choice (D-108):
/trackingin the sidebar and the phone tab bar (log every shown metric for a day, with day navigation, the day's entries, a 7-day strip, health and habit check-ins, link to Trends); metrics get an emoji and quick amounts (presets); built-in water (ml, summed per day, buttons +100 ml, +200 ml, +1 l, configurable); Settings: emoji, quick amounts, order, show or hide, and suggestions to add (sleep, steps, coffee, energy); Today's Track card uses the same widgets; tests; help and CHANGELOG. - [x] 11.2 Routine days, chores that roll on, nothing done early (D-109, D-110): the routine sheet shows day chips straight away for "on a schedule" and "at a fixed time" (all days = every day); "If not done in time" reads Routine: missed / Chore: carries on until done; a carry-on routine keeps one open occurrence (at day start older open ones are folded into the newest: skipped as rolled on, plan and carry count moved); an occurrence can't be completed before its day (server refuses, rows show it as not yet due; skip and won't do stay allowed); domain + server tests; help and CHANGELOG.
- [x] 11.3 Change when a task was done (D-111):
PATCH /tasks/{id}takescompleted_at(not in the future; the completed event moves with it, so the day log follows); task sheet shows and edits "Done on"; Week planner lets a done task be dragged to an earlier day (also past days) to set its done day; completing from a past day's page dates it on that day; tests; help and CHANGELOG. - [x] 11.4 Goal tree, attachments and rules (D-112):
goals.parent_id(any number of top-level goals; a child has its parent's owner; no cycles,domain::tree),goals.series_ids(routines attach, counted by how often they were done in the last four weeks), parent progress from its children and its own linked work (domain::goals, tested); a third kind rule ("eat less junk": no daily question, a period that may have no end) with its own Rules tab; goals can be attached from the task sheet, the project page, the routine sheet and the rule; goals page shows the tree with sub-goals; only newly linked ids are checked (a deleted linked task no longer blocks edits); goals in the JSON export; tests; help and CHANGELOG. - [ ] 11.5 Phase gate (Part D) for v1.5.
Done 2026-10-17: fmt, clippy, all tests (server, domain, web) and the web build green;
TS types regenerated; docs site builds with
--strict; new migrations tried on a copy of an older database; API smoke test of every new flow on a fresh server. 2026-10-18: resource log updated (image 16.7 MB, idle 9.4 MiB, 117.7 KB initial); security review done, nothing to fix (D-114). Left for the owner: a look at the new pages in a browser (desktop and phone width), the phone and HTTPS smoke test, push so CI runs, and the release.
Phase 12: Week templates with routines and tasks in blocks (v1.5, D-113)¶
Owner request of 2026-10-18. On the v1.5 branch, after Phase 11. Migration 0038.
- [x] 12.1 Routines and tasks in template blocks: a template block holds items (a
routine, or a one-off task with title, estimate and notes); on each day the template
sets up, the routine's occurrence due that day (or one open slot of an N-per-week
routine) is planned into that block, one after another from the block's start, and
one-off items become a fresh task there (once per day: deleted or moved ones don't
come back); days changed by hand are left alone as before (D-58); placement in
domainwith tests; server tests. - [x] 12.2 Several week templates: a week template maps each weekday to a day template
(or none); one is the default, one can alternate with it every other week, and others
apply for a date range ("Holiday week"); existing weekday assignments become the
default week template; which day template a date gets is resolved in
domain(tested) and used by the 8-day set-up. - [x] 12.3 Visual week editor:
/week-template(Settings and the Week view link to it): pick a week template, 7 day columns on an hour grid; draw, move and resize blocks, set their theme and energy; drag routines (searchable list) and new one-off tasks into blocks, with a menu alternative for every drag (§6.12); choose a day template per weekday; manage week templates (default, alternating, date range). - [x] 12.4 Preview on the Week view: days not set up yet show their template's blocks and the routines and tasks it will put there, marked as a preview; help and CHANGELOG.
- [ ] 12.5 Phase gate (with 11.5): see 11.5.
Part C. Open questions with proposed defaults¶
Status: all defaults below accepted by the owner on 2026-10-05 (recorded as D-1…D-23 in
DECISIONS.md).needs Q-xmarkers in Part B now just point to the relevant decision.
These are the §9 questions. Each has a recommended default so work isn't blocked. The owner
confirms or overrides each one, and the answer goes into DECISIONS.md. The "Needed by"
column says when it must be settled.
| # | Question (§9) | Proposed default | Needed by |
|---|---|---|---|
| Q-1 | Default task types; custom types in v1? | One-off → carry_on; anchored routine → expires; flexible routine → window; tasks with due date may opt into deadline; workflow steps inherit from the template (default carry_on). Users can create custom types in v1, since types are just config. |
2.3 |
| Q-2 | Day-end rollover | Configurable per user, default 04:00. | 2.1 |
| Q-3 | Flexible routine window | Fixed calendar periods (ISO week with configurable week start; calendar month), not rolling. Easier to reason about and to show as "1 of 2 this week". | 3.4 |
| Q-4 | Assign to a member within a group | Not in v1. The schema keeps a nullable assignee_user_id so it can be added later without a migration. |
4.2 |
| Q-5 | Reminders on HTTP-only | In-app (SSE banner/toast) always; optional ntfy backend in Phase 6; Web Push when HTTPS is available. | 2a.3 |
| Q-6 | Prerequisite skipped or deleted | Auto-unblock, with a visible note on the dependent task ("prerequisite X was skipped"). wont_do counts the same as skipped. |
3b.1 |
| Q-7 | Routine spawns a workflow while the previous instance is unfinished | Don't spawn; log the occurrence as skipped ("previous run still open"). Can be changed per routine. | 3b.6 |
| Q-8 | Ritual default and reminder persistence | Default evening. One reminder at the planning time, plus a persistent (dismissible) banner in the Today view until the day is planned. No repeated nagging. | 2a.1 |
| Q-9 | Overbooking: warn or inform | Warn (amber, non-blocking). | 2a.2 |
| Q-10 | Mealie details | Watch one list chosen in settings; create the task automatically; one task per meal. | 7.1 |
| Q-11 | Meal blocked by shopping | Out of scope for v1 (users can add the dependency by hand). | 7.2 |
| Q-12 | Shareable workflow templates | JSON export/import of templates (cheap). Add in 3b.5 if time allows, otherwise in Phase 6. | 3b.5 |
| Q-13 | Thermal printer model; A4 first? | A4/browser print first (7.3). Owner names the printer model before 7.4. | 7.4 |
| Q-14 | QR reconcile link auth | Signed link that expires after 48 h and can only complete the printed items. | 7.4 |
| Q-15 | Child profiles | Postpone; decide after using printed sheets. | 7.5 |
| Q-16 | Journal encryption at rest | v1: no app-level encryption (the disk and host are trusted; documented). Revisit E2E later, since it conflicts with server-side search/export. | 5b.1 |
| Q-17 | Import historical data | Yes, a simple CSV import for metric entries (date, value). | 5b.5 |
| Q-18 | Difficulty scale; estimate format | 3 levels (stored as 1–3, so it can grow later). Estimates stored in minutes, set via preset chips 5/15/30/60/120, with custom entry allowed. | 2.2 |
| Q-19 | Auto-suggest aggressiveness | Suggest only, on request in the wizard. Optional morning auto-draft later. | 5a.3 |
| Q-20 | Pomodoro defaults; notify when closed | 25/5/15, long break after 4, configurable per user (per task later). Notify when the app is closed only via Web Push/ntfy (Phase 6). | 2b.5 |
| Q-21 | Goal progress | Mixed: derived by default, manual override per goal. | 5c.1 |
| Q-22 | Eisenhower: flags or scores | Store 0–3 scores; quadrant threshold ≥ 2. Dragging into a quadrant sets the value to 2 or 0 only if it crosses the threshold, so finer values are kept. | 2.2 |
| Q-24 | Occasions: which nameday calendar, and where do names of interest come from? | Estonian nameday calendar first (others addable as data files). Names of interest are entered by the user as people (name + optional birthday), and only their namedays and birthdays create tasks. Default template per kind: buy present −2 d (deadline) → greet 0 d (expires). | 3b.6a |
| Q-25 | Places: just a filter, or more? | Answered (D-45): a filter; pick "I'm at X" from a list, or opt in to GPS in Settings, which then detects the place automatically when the browser grants location access (HTTPS only). | 2b.6a |
| Q-23 | Units and locale | Per-user locale (date/number format) and unit system (metric default, kg). Values stored in canonical units (kg) and converted for display. | 5b.2 |
Part D. Phase gate checklist (run at the end of every phase)¶
just testand CI green; new risky logic has unit tests indomain(§8 list).scripts/measure.shresults logged indocs/DECISIONS.md→ "Resource log" table:- Docker image size (target < 50 MB; aim < 25 MB)
- Idle container RSS after 60 s (target < 50 MB; aim < 20 MB)
- Initial frontend payload, compressed (budget < 150 KB, hard limit 300 KB)
- p95 API latency for the day aggregate on a Pi-class machine (target < 50 ms)
- Manual smoke test on phone + desktop, over plain HTTP and behind the HTTPS proxy.
- No secrets in logs (grep test logs for the test passwords).
- Docs site (
docs/,mkdocs build --strict), README and DECISIONS.md updated; OpenAPI and TS types regenerated. - Tag a pre-release (
v0.<phase>), so each phase is a usable, runnable version.
Part E. Risks and mitigations¶
| Risk | Mitigation |
|---|---|
| Rust CalDAV/iCal ecosystem gaps | Spike in 5.1 before building on it. Hand-roll the small CalDAV transport; use fixture-heavy tests. TS fallback only if parsing is truly blocked (ask the owner). |
| Recurrence + rollover + timezones get subtle | Keep them pure in domain, using the single logical_date() helper, with explicit DST tests; occurrences materialized within a bounded horizon. |
| Visibility bugs leak private or group data | One visible_to function used by every query and the SSE filter; the 4.1 visibility matrix test is required. |
| DnD quality on touch | Decide in 2.6 after testing on real devices; every drag also has a menu alternative. |
| Scope creep (the spec is large) | Strict phase gates; Phase 7 is explicitly after v1.0; each chunk is small enough for one session. |
| SQLite write contention with SSE + jobs | WAL, a single-writer pool, short transactions, jobs batched per tick. |
| Bundle growth | CI size budget check from 1.7 onwards. |
Rough size estimate¶
| Phase | Chunks | Relative size |
|---|---|---|
| 1 Foundation | 9 | L |
| 2 Day plan | 7 | L |
| 2a Ritual | 4 | S |
| 2b Views & focus | 7 | M |
| 3 Recurrence | 6 | L |
| 3b Workflows | 7 | M–L |
| 4 Groups | 4 | M |
| 5 Calendar | 5 | M–L |
| 5a Blocks & planner | 4 | M |
| 5b Tracking | 6 | M |
| 5c Goals | 3 | S |
| 6 PWA & polish | 5 | M |