Files
familysync/.planning/phases/05-web-push-notifications/.continue-here.md
T

5.7 KiB

context, phase, task, total_tasks, status, last_updated
context phase task total_tasks status last_updated
phase 05-web-push-notifications null null awaiting_device_uat 2026-06-10T02:49:45.903Z

Critical Anti-Patterns

Pattern Description Severity Prevention Mechanism
await before pushManager.subscribe() in a tap handler The iOS user-gesture gate breaks if ANY async/await (network fetch, navigator.serviceWorker.ready) runs between the user tap and pushManager.subscribe()NotAllowedError. This recurred TWICE this phase (original CR-04, then the fixer's own await serviceWorker.ready). advisory When touching push opt-in UI, pre-resolve BOTH the SW registration and VAPID public key into component state via useEffect, disable the Enable control until both are non-null, and call subscribe(registration, vapidKey) synchronously — zero await before pushManager.subscribe(). See usePushSubscription.ts / PushPermissionPrompt.tsx / SettingsSheet.tsx.
db:push on populated MariaDB drizzle-kit push emits a false destructive diff and can truncate tables. advisory New tables/columns via db:generate + db:migrate only (migrations 0003 + 0004 followed this).
Silent pushes on iOS A push that does not display a visible notification counts toward iOS's ~3-strike silent-revocation. advisory Every push path uses event.waitUntil(showNotification(...)) in sw.ts; keep it that way.
Root .env is permission-blocked from the assistant Read/Write/grep of .env are denied in this harness; secrets cannot be written by the agent. advisory Hand secret values to the user to paste, or read the dev DB password from the container: docker exec familysync-mariadb-1 printenv MARIADB_PASSWORD.

<current_state> Phase 5 (Web Push Notifications) is code-complete and verified at the code level (12/12 must-haves). All 8 plans (05-01..05-08) executed and committed; code review ran --fix --all --auto (14 findings fixed across 3 iterations, 05-REVIEW.md status clean); phase verification produced 05-VERIFICATION.md with status human_needed (no gaps). Working tree clean.

The ONLY remaining work is on-device UAT — the phase goal says "reliably on iOS and Android," which cannot be automated. ROADMAP was reverted from a premature [x] to [ ] pending device UAT. </current_state>

<completed_work>

  • All 8 plans executed (Wave 1: 05-01 foundation; W2: 05-02 dispatchPush, 05-03 coalescer; W3: 05-04 push spine; W4: 05-05 list-change/NOTIF-02, 05-06 reminder scheduler/NOTIF-01, 05-08 opt-out+health UI; W5: 05-07 event-change/NOTIF-03 + title population). Each has a SUMMARY.md.
  • Packages installed (web-push 3.6.7, workbox 7.4.1); VAPID keypair generated + placed in root .env by user; wired into docker-compose.yml + .env.example.
  • Migrations 0003 (push_subscriptions + calendar_events.title) + 0004 (endpoint→varchar(2048), p256dh→varchar(512)) generated and applied.
  • Code review fixes (CR-01..04, WR-01..05, IN-01..03, NEW-CR-01, NEW-WR-01) all committed as fix(05-review):.
  • Test state: API 213/214 (1 flaky real-DB timeout in lists.test.ts under parallel load — passes 59/59 isolated), PWA 160/160, both typecheck clean, PWA builds, no schema drift. </completed_work>

<remaining_work>

  • Run /gsd-verify-work 5 and complete the 5 device-only UAT items in 05-UAT.md:
    1. iOS PWA install → subscribe → 15-min reminder receipt
    2. iOS subscribe without NotAllowedError
    3. iOS health-check survives 1+ week inactivity
    4. Android event-change push arrives
    5. List-change coalescing observable (5 edits → 1 push)
  • After UAT passes, verify-work auto-transitions the phase to complete; then milestone can advance to Phase 6. </remaining_work>

<decisions_made>

  • VAPID config env-injected (docker-compose env + root .env), never baked into image — for container transposability.
  • Reminders are SHARED Family-calendar timed events ONLY (D-05), enforced in SQL.
  • Reverted premature ROADMAP completion to pending; completion gated on device UAT. </decisions_made>
- None technical. Two human actions: (1) device UAT [blocking phase completion], (2) create + share the "Family" calendar with is_shared=1 so SC-1 reminders have real events [non-blocking].

Required Reading (in order)

  1. .planning/phases/05-web-push-notifications/05-VERIFICATION.md — what was verified in code + the 5 human items.
  2. .planning/phases/05-web-push-notifications/05-UAT.md — the device test script to run via verify-work.
  3. .planning/phases/05-web-push-notifications/05-REVIEW.md — code review resolution (esp. the iOS gesture-gate fix).
  4. CLAUDE.md §"React PWA Stack" — iOS push constraints.

Infrastructure State

  • Dev MariaDB container familysync-mariadb-1 is UP, host port 3306 bound. DB password: docker exec familysync-mariadb-1 printenv MARIADB_PASSWORD.
  • VAPID keys present in gitignored root .env; documented in .env.example; wired into docker-compose.yml.
  • No running API/PWA dev servers from this session.
  • Migrations 0003 + 0004 applied to the dev DB.
Phase execution went cleanly; the only substantive risk surfaced by the code-review `--auto` loop was the iOS user-gesture gate, which is the headline feature and was gotten wrong twice before landing correctly. Everything that can be confirmed without hardware has been confirmed. Next session is purely device validation, not code.

<next_action> Start with: /gsd-verify-work 5 — walk the 5 items in 05-UAT.md on a physical iOS (16.4+, Home-Screen-installed) device and an Android device. Ensure the shared "Family" calendar exists with is_shared=1 first so reminders have events to fire on. </next_action>