--- context: phase phase: 04-shared-lists-live-sync task: null total_tasks: null status: ready_to_plan last_updated: 2026-06-08T01:52:24.365Z --- Phase 4 (Shared Lists + Live Sync) — **discussion complete, entry gate cleared, ready to plan.** Nothing is mid-edit. The working tree is clean and this is a deliberate stopping point between discuss-phase and plan-phase. - `04-CONTEXT.md` is written and committed (18 decisions, D-01..D-18). - The Phase 4 **entry gate** (SSE-over-Pangolin smoke test, D-14 / issue #1034) is **CLEARED** — verified live this session and recorded in the gate docs. No infra precondition remains. - No PLAN.md exists yet for Phase 4. This session: - Ran `/gsd-discuss-phase 4` → `04-CONTEXT.md` + `04-DISCUSSION-LOG.md` (commit 05e1c9e). - Executed the SSE-over-Pangolin smoke test live over `familysync-dev.bergerhouse.net`: ~6 min hold, 35 heartbeats (id 0→34) at ~10s, incremental delivery (buffering off), no cut → PASS. - Recorded the PASS via quick task 260607-u8o: updated `01-HUMAN-UAT.md` item 4 and `03-GATE2-RESULTS.md` Part C to PASS; struck the entry-gate blocker in STATE.md (commit 9ee5906). - Saved project memory: design for N family members (not hard-coded two). - **Next:** `/gsd-plan-phase 4` (consumes `04-CONTEXT.md`). - Optional before/after planning: `/gsd-ui-phase 4` — lists UI design contract (ROADMAP UI hint: yes). - Then execute Phase 4 plans. All locked in `04-CONTEXT.md` (read it before planning). Highlights for the planner: - **Sharing:** default-shared lists with a per-list private toggle; `list_shares` join table (member-count-agnostic, N-member-ready); SSE fan-out **scoped to who can see a list** (private lists must NOT broadcast to everyone). - **Items:** checked items sink to a completed section; confirm-on-delete for lists only (reuse `DeleteConfirmationDialog`). - **Live feel/conflicts:** optimistic UI; per-field PATCH + per-field last-write-wins (bounded — NO CRDT); delete-wins. - **Reconnect:** full refetch on reconnect; capped-backoff then a "updates paused" indicator; React Query `refetchInterval` polling fallback. - **Ordering:** string-based fractional index (NOT raw floats, NOT integer-renumber); animate remote reorders; last-write-wins settle. - **Nav:** bottom tab bar + react-router (real URLs, for Phase 5 push deep-links). No router today. - **Project principle:** design for N family members, not hard-coded two. - **Deferred (out of scope):** anonymous public-URL list sharing; per-recipient picker UI. - None. The entry gate that previously blocked the build is cleared. ## Required Reading (in order) 1. `.planning/phases/04-shared-lists-live-sync/04-CONTEXT.md` — locked implementation decisions; the contract for planning. 2. `apps/api/src/db/schema.ts` — Drizzle table conventions for the new `lists` / `list_items` / `list_shares` tables. 3. `apps/api/src/routes/sse.ts` — existing Hono `streamSSE` heartbeat pattern; the live-list stream extends it. 4. `.planning/phases/03-event-write-back-pwa-install/03-GATE2-RESULTS.md` Part C — recorded SSE smoke PASS evidence. ## Open Decisions for the Planner (intentionally NOT pre-decided) - **Fan-out mechanism:** in-memory EventEmitter vs Redis pub/sub. API runs as a single Node process today (no replicas); `ioredis` is NOT installed; `redis` IS in docker-compose. In-memory is the YAGNI default — planner must justify the choice against the N-member future (D-18). - Position-rank column type, SSE auth/middleware wiring, React Query cache-key structure. ## Infrastructure State - Pangolin route already configured (buffering off, idle/read timeout ≥120s) and verified for SSE. - `redis` service present in docker-compose; `ioredis` not yet a dependency. - New DB tables MUST use `drizzle-kit generate` + `migrate` — **never `push`** (unsafe on populated MariaDB). - No background processes were left running. Clean handoff. The hard part (verifying SSE survives the tunnel) is done and recorded, so Phase 4 can be planned and built without an infra gate hanging over it. The planner should treat 04-CONTEXT.md as authoritative and focus its remaining judgment on the fan-out mechanism and the new schema (lists, list_items, list_shares) using generate+migrate. Start with: `/clear` then `/gsd-plan-phase 4`.