feat(daily): GTD/todo surface redesign — due-based Today, Inbox split, status-flow Todos, routines overview#16
Conversation
The Today strip counted only the committed daily plan (daily_plan_items), so it read 0/0/0 whenever no plan was built — the normal case for a recurring/due-driven workflow. Recompute it from what is actually scheduled today: Open = due-today + recurring-due + started, Overdue = past-due still open, Completed = finished today (one-time done today plus recurring occurrences stamped today). The front end derives the strip from the section lengths, so completing an item updates it live without a refetch and without a committed plan existing. Adds CompletedTodoItemsOn / Store.CompletedItemsOn for the done-today section and removes the dead plan-based PlanCompletion counting — the daily_plan_items.status column it read has no write path, so it always reported planned.
Inbox and Todos were the same GtdPageComponent differing only by a route data flag. Inbox now has its own page (capture + triage), reusing the GTD store, row, and clarify modal locked to the inbox view. The Todos page becomes a pure status-flow surface: Pending / In Progress / Someday / Complete. The Today and Recurring tabs and the capture bar are gone — "today" lives on the Today dashboard, routines in their own overview and each row's detail, and capture in the Inbox. The Complete tab is backed by a resolved-since query (done + dropped/ archived + recurring occurrences), so a recurring routine's daily completion is visible there; rows badge their resolution kind (done / dropped / recurring). Recurring routines are excluded from the working status tabs so the flow stays free of daily routines. Also adds AllRecurringTodoItems for the upcoming routines overview, and widens the frontend TodoState to match the backend enum (archived, dismissed).
The row's actions (advance, defer, drop, edit recurrence) and its facts (state, project, due, energy, whether it is a recurring routine) were only reachable through hover affordances and keyboard verbs. Clicking a row's title on the Todos page now opens a detail panel that surfaces all of them in one place, including making or editing the todo's recurrence. The panel emits intent against the open target; the store owns the round-trips and closes the panel after a mutation so the backlog reload doesn't pull the row out from under it.
Removing the Recurring tab left a routine on its off-days with nowhere to appear — the Today dashboard shows only what is due today, and the Todos status tabs exclude routines. Add a Routines page (sidebar entry under Daily) that lists every active recurring schedule from the recurring endpoint's new `all` bucket, with its schedule, a due-today marker, and when it last ran. Read-only: a routine's schedule is edited from its Todos detail panel; today's occurrence is completed on Today. Records the two cross-surface decisions in the semantic contract: the human Today dashboard is due-based while the MCP brief(reflection) stays plan-based, and routines have a manage-all surface distinct from due-today.
🤖 Augment PR SummarySummary: This PR reshapes the Admin Daily UI around a due/recurring-driven workflow instead of a plan-driven one, so Today/Todos reflect actual work even when no daily plan is committed. Changes:
Technical Notes: Backend expands 🤖 Was this summary useful? React with 👍 or 👎 |
| completed_at, energy, priority, recur_interval, recur_unit, recur_weekdays, last_completed_on, | ||
| description, created_by, created_at, updated_at | ||
| FROM todos | ||
| WHERE state NOT IN ('archived', 'dismissed') |
There was a problem hiding this comment.
AllRecurringTodoItems is described as “every active recurring schedule”, but the predicate only excludes archived/dismissed and will still include state='done' (and potentially other non-active states). This can make the Routines overview show closed routines; consider excluding terminal done here to match the “active” semantics used elsewhere (e.g. RecurringTodoItemsDueToday).
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in f54fb0c — confirmed valid. AllRecurringTodoItems now uses the same active-state filter as RecurringTodoItemsDueToday (excludes done/someday/inbox/archived/dismissed), so the Routines overview is a strict superset of due-today and never lists a closed routine. Added integration coverage that a terminally-done recurring row appears in neither bucket.
|
augment review |
AllRecurringTodoItems excluded only archived/dismissed, so a recurring row that had been terminally closed (state=done) — reachable e.g. by setting a recurrence on an already-done todo — would still show in the Routines overview as if it were a live schedule. Match the active-state filter RecurringTodoItemsDueToday uses (also excluding done/someday/inbox), so the overview is a strict superset of the due-today list and never lists a closed routine; those rows remain reachable on their own Complete/Someday/Inbox surfaces. Adds integration coverage that a done recurring row appears in neither bucket.
| this.store.advanceRow(row); | ||
| break; | ||
| case 'clarify': | ||
| this.store.clarifyTarget.set(row); |
There was a problem hiding this comment.
InboxPageComponent.handleKeydown sets store.clarifyTarget directly for the clarify action; this bypasses store.openClarify() which resets clarifyIntent to 'clarify'. If the user previously hit t (pull) on an inbox row, the intent can stay 'pull' and a later keyboard-clarify could unexpectedly append the clarified todo to today’s plan.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in 05e75a6. Confirmed it is not yet reachable (the keyboard clarify case only fires when clarifyTarget is null, and every path that nulls it also resets intent to clarify), but routing through openClarify() removes the fragility so a future change cannot leak a stale pull intent into a keyboard clarify.
| completed, err := h.store.CompletedItemsDetailSince(r.Context(), since) | ||
| // Resolved-since path: the default Complete-tab view — done, dropped, and | ||
| // recurring routines' recent occurrences. | ||
| resolved, err := h.store.ResolvedItemsDetailSince(r.Context(), since) |
There was a problem hiding this comment.
Now that the default history endpoint returns “resolved” items (done + dropped + recurring occurrences), the ?q= search path still goes through SearchItems with a completed_after filter (based on completed_at), so dropped/recurring resolutions likely won’t be searchable in the Complete tab. Also, the function header comment above still says “completed-since path,” which no longer matches the new semantics.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in 75ef4f1 — confirmed valid. The ?q= path now uses SearchResolvedTodoItems, which applies the same resolution arms as ResolvedTodoDetailSince (done/dropped/recurring), so dropped and recurring resolutions are searchable in the Complete tab; the stale completed_at-only SearchItems/SearchTodoItems/SearchDetail are removed and the History doc comment is corrected. Integration coverage added: ?q=Japanese finds the recurring occurrence and ?q=do returns the dropped row but not a non-resolved pending one.
The inbox keyboard 'clarify' action set clarifyTarget directly, bypassing openClarify() which resets the clarify intent. The intent only ever becomes 'pull' alongside an open modal today, so this was not yet reachable — but poking the signal instead of the store's API left a stale 'pull' intent one refactor away from making a keyboard clarify silently append the todo to today's plan. Use openClarify so the intent is always reset.
The default Complete view returns resolved todos (done + dropped + recurring occurrences), but the ?q= search path still filtered on completed_at, so dropped rows (no completed_at) and recurring occurrences (last_completed_on) were unsearchable — searching for a completed routine returned nothing. Replace the completed_at-scoped SearchTodoItems with SearchResolvedTodoItems, which applies the same resolution arms as ResolvedTodoDetailSince, so both Complete-tab paths search the same set. Removes the now-dead SearchItems / SearchTodoItems / SearchDetail and fixes the stale History doc comment. Adds integration coverage that ?q= finds a dropped and a recurring resolution and still excludes a non-resolved pending row.
|
augment review |
Summary
Reshapes the admin Daily surface around a due/recurring-driven workflow (the owner does not build daily plans, so the old plan-driven model read empty).
last_completed_on=today; past-due-still-open). It no longer reads the committeddaily_plan(which was empty → a constant0/0/0, plus a latent bug: the front end counteddaily_plan_items.status, a column with no write path). Backend addsCompletedTodoItemsOn/Store.CompletedItemsOnfeeding a newcompleted_todossection; the deadPlanCompletionblock is removed. Completing a row updates the strip live./admin/daily/inbox). Capture + triage only, reusing the GTD store/row/clarify-modal locked to the inbox view. Previously Inbox and Todos were the same component differing only by a route flag.已了結) is backed by a resolved-since query (done + dropped/archived + recurring occurrences), badging each row's kind. Recurring routines are excluded from the working status tabs./admin/daily/routines, new sidebar entry). Lists every active recurring schedule from the recurring endpoint's newallbucket — the home for a routine on its off-days, which neither the Today due-today list nor the recurring-excluding status tabs show. Read-only; editing is via the Todos detail panel.TodoStatewidened to match the backend enum (archived,dismissed); semantic-contract note added (human Today = due-based vs MCPbrief(reflection)= plan-based; routines manage-all surface).Test Plan
Automated verification — all green:
go build ./...,go vet(incl.-tags integration),golangci-lint(0 issues), unit tests, and integration tests against real PostgreSQL (testcontainers) forinternal/todo,internal/today,internal/daily— including the extendedHistory(resolved: done + dropped + recurring) andRecurring(allbucket) assertions.tsc(app + spec),ng lint(0), 609 unit tests,ng build(AOT, full template type-check)./admin/daily/today,/admin/daily/inbox,/admin/daily/todos(Pending/In Progress/Someday/Complete + click a row for the detail panel),/admin/daily/routines.