3.7 KiB
3.7 KiB
Online Inbox — implementation plan
Date: 2026-06-10
Spec: docs/superpowers/specs/2026-06-10-online-inbox-design.md
Contract: docs/online-inbox-api-contract.md
TDD, one commit per task, Conventional Commits. Build with -c Release per CLAUDE.md.
Phase 1 — Worker sync engine (buildable now, no Zitadel package needed)
Task 1 — Config
- Add
OnlineInboxConfig+ nestedZitadelClientConfigrecords. - Add
online_inbox(OnlineInbox) property toWorkerConfig; defaultenabled=false. Loadleaves it untouched when absent (defaults = disabled).- Test: missing section → disabled defaults; populated section round-trips.
Task 2 — DTOs + Idle-backlog helper
Online/Dtos.cs:RemoteList(Id, Name),RemoteTask(Id, ListId, Title, Description, CreatedAt),MirrorTask(Id, ListId, Title, Description).Online/OnlineBacklog.cs:static Task<List<MirrorTask>> CurrentAsync(TaskRepository/ctx)+ the filter predicate (Idle, no parent, PlanningPhase None, BlockedBy null).- Test the filter against real SQLite seeded with mixed tasks.
Task 3 — Auth abstraction + token store
Online/Interfaces/IOnlineAuthProvider.cs.Online/OnlineTokenStore.cs: DPAPI CurrentUser persistence at~/.todo-app/online-inbox.token;Save(refreshToken),Read(),Clear(). (Windows-only encryption; thin + guarded.)- A trivial
StaticTokenAuthProvider(returns a configured token or null) for tests + as the temporary default until Zitadel is wired. - Test: token store round-trip (Windows); static provider returns/omits token.
Task 4 — API client
Online/IOnlineInboxApi.cs+Online/OnlineInboxApiClient.cs(typedHttpClient).- Attaches
Authorization: BearerfromIOnlineAuthProvider; refuses non-HTTPS non-loopback base URLs; throws a typedOnlineInboxExceptionon non-2xx. - Test with a stubbed
HttpMessageHandler: each method hits the right path/verb/body; 401 surfaces; bearer attached.
Task 5 — Sync service
Online/OnlineSyncService.cs(BackgroundService) implementing the §5 reconcile loop.- DI: register only when
enabled; resolve repos per-cycle via a scope. - Per-cycle try/catch + structured logging; skip when no token; unknown-list skip.
- Test against a fake
IOnlineInboxApi+ real SQLite: pull→import→flag creates local Idle tasks; mirror payload == Idle backlog; lists pushed; unknown list skipped & not flagged; disabled/no-token = no api calls.
Task 6 — Wire-up + docs
- Register the stack in
Program.csbehind the enabled flag. - Update
src/ClaudeDo.Worker/CLAUDE.md(newOnline/area) andsrc/ClaudeDo.Worker/Confignotes. Addonline_inboxto the config section.
Phase 2 — UI + real auth (AFTER the VPS reports client config)
Task 7 — Hub + config plumbing
- Hub:
GetOnlineInboxConfig/SetOnlineInboxConfig/SetOnlineInboxAuth(refreshToken)/ClearOnlineInboxAuth. UpdateIWorkerClient+WorkerClient+ test fakes (both test projects — see the IWorkerClient-fakes memory).
Task 8 — Settings UI
- "Online Inbox" section in
SettingsModalViewModel: enable toggle, base URL, Sign in/out, status. Localized keys in en.json + de.json (parity). - Visual verification = manual (flag it).
Task 9 — ZitadelAuthProvider
- Add the Zitadel package reference; implement
ZitadelAuthProvider(refresh-token → access token, cached to expiry) using the reported authority/client-id/flow. - Swap it in for
StaticTokenAuthProviderin DI when enabled. - Manual smoke against the live VPS API (tracked, not an automated test).
Notes
- No real network / no real Zitadel / no real Claude in any automated test.
- Stage files by explicit path in subagents; sonnet model; build+test+commit by the orchestrator.