--- context: phase phase: 05-web-push-notifications task: null total_tasks: null status: paused last_updated: 2026-06-09T19:14:03.727Z --- Phase 5 (Web Push Notifications, MVP mode, depends on Phase 3 + Phase 4) just completed **discuss-phase**. `05-CONTEXT.md` and `05-DISCUSSION-LOG.md` are written and committed (e74f24d); STATE.md session recorded (3bbfbbc). Working tree clean. This is a clean stop **between discuss and plan** — no plans/tasks exist yet, nothing is mid-edit. Resume by planning the phase. - Task 1: discuss-phase 5 → `05-CONTEXT.md` + `05-DISCUSSION-LOG.md` (decisions D-01..D-14). Done (e74f24d). - Task 2: STATE.md session recorded. Done (3bbfbbc). - Task 3 (optional): `/gsd-ui-phase 5` — UI design contract for the permission prompt, settings master toggle, and notification flow. This phase has real frontend surface. - Task 4: `/gsd-plan-phase 5` — research + plan (reads `05-CONTEXT.md`). - Task 5: execute the plans. - **D-05 (most consequential): reminders fire for the SHARED Family calendar ONLY** — not personal events. Deliberate, because each member's native device calendar app already reminds for personal events and FamilySync must not duplicate. This narrows a literal reading of NOTIF-01; flagged for planner + verification. - Coalesce list-change pushes per list; events show specifics, list pings stay generic (actor + list + count, no item text); name the actor; only meaningful event-changes push (description-only edits stay silent). - Contextual permission prompt right after install; single master on/off toggle (v1); silent auto re-subscribe when a subscription dies but OS permission is still granted. - Fixed 15-min lead; no all-day reminders. - None blocking planning/implementation. (Human action — non-blocking: the shared "Family" calendar must be created + shared + `is_shared=1` per Phase 2 D-16 before reminders have real events to fire on for live verification.) ## Required Reading (in order) 1. `.planning/phases/05-web-push-notifications/05-CONTEXT.md` — the source of truth; decisions, canonical refs, code-context, deferred items. 2. `CLAUDE.md` §"React PWA Stack" — iOS push constraints (16.4 min, install required, gesture subscribe, visible-notification mandatory) + web-push/VAPID stack entry. 3. `.planning/STATE.md` (Phase 5 note) — iOS revokes after ~3 silent pushes; health-check + `event.waitUntil()` mandatory. 4. `apps/api/src/lib/listEmitter.ts`, `apps/api/src/broker/poller.ts`, `apps/api/src/broker/outboxWorker.ts` — push-dispatch hook points + change-detection sources. ## Critical Anti-Patterns (do NOT repeat these) | Pattern | Description | Severity | Prevention Mechanism | |---------|-------------|----------|---------------------| | `db:push` on populated MariaDB | The new push-subscription table must NOT be created via `drizzle-kit push` — it emits a false destructive diff and can truncate tables on populated MariaDB | advisory | Use `drizzle-kit generate` + `migrate` for all new tables this phase | | Silent pushes on iOS | Any push that does not display a visible notification counts toward iOS's ~3-strike silent-revocation; subscriptions die silently | advisory | Every push MUST show a visible notification; SW uses `event.waitUntil()`; implement the subscription health-check from day one | | Introducing Redis for fan-out | The API is a single Node process; `ioredis` is not installed | advisory | Push dispatch reuses the in-memory `listEmitter` publish points — do not add Redis (matches Ph4 decision) | ## Infrastructure State - `web-push` and `ioredis`: NOT installed. VAPID keys not yet generated. No Redis (single Node process). - Service worker: vite-plugin-pwa `generateSW` + `autoUpdate` — adding a `push`/`notificationclick` handler likely requires switching to `injectManifest` (planner's call; preserve Workbox precache + autoupdate). - react-router installed (Ph4 D-17) — enables tap-to-open deep links (`/lists/:id`, event URLs). - No running background services from this session. Discussion is done and committed; nothing is in flight. Three gray areas were discussed (Copy & anti-spam, Reminder scope & timing, Onboarding & opt-out); Quiet-hours/DND was left to discretion (v1 = none). The shared-only reminder scope (D-05) is the decision most worth re-examining before committing the plan if the household's mental model is "remind me about everything." Start with: `/clear` then `/gsd-plan-phase 5` (optionally `/gsd-ui-phase 5` first for the notification UI design contract). Read `05-CONTEXT.md` before acting.