7.7 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 05-web-push-notifications | 01 | api/push-foundation |
|
|
|
|
|
|
Phase 05 Plan 01: Wave-0 Foundation Summary
Web Push Wave-0 foundation: push dependencies installed, VAPID keypair env-injected, push_subscriptions table + calendar_events.title migrated, five RED test scaffolds committed.
Tasks Executed
Task 1: Package legitimacy gate + install push dependencies
Status: Done by orchestrator before this agent spawned.
Installed packages verified in package.json:
apps/api: web-push@^3.6.7 (prod), @types/web-push@^3.6.4 (dev)apps/pwa: workbox-core@^7.4.1, workbox-precaching@^7.4.1, workbox-routing@^7.4.1 (dev)
Commit: 80bbdc1 — chore(05-01): install web-push and workbox push dependencies
Task 2: Generate VAPID keypair + record in env
Status: Done by orchestrator before this agent spawned.
VAPID keypair generated and stored in gitignored .env (VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT). Real keys never committed.
(No dedicated commit — keys in .env only; .env.example documenting placeholders committed in Task 3.)
Task 3: Schema — push_subscriptions table + calendar_events.title, generate+migrate
Status: Completed.
Added pushSubscriptions mysqlTable to apps/api/src/db/schema.ts:
user_idINT NOT NULL FK → users.id ON DELETE CASCADEendpointTEXT NOT NULL (globally unique —uniq_push_endpoint)p256dhTEXT NOT NULLauthVARCHAR(256) NOT NULLcreated_at,updated_atTIMESTAMP- Index
idx_push_subscriptions_user_idon userId
Added title VARCHAR(500) (nullable) to calendarEvents after rawVevent. Populated from VEVENT SUMMARY by sync.ts in Plan 05-07; required for readable reminder/change copy (D-02/NOTIF-01).
Migration generated via db:generate and applied via db:migrate (NOT db:push — anti-pattern per drizzle-mariadb-push-unsafe memory). Migration file: 0003_same_xavin.sql.
VAPID container-transposability: added VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT to docker-compose.yml api environment: block using ${VAR} syntax (no default — must be set). Created root .env.example documenting all environment variables including VAPID vars with placeholders and generation instructions.
Commit: 73fcdaf — feat(05-01): add push_subscriptions table + calendar_events.title column; VAPID env wiring
Task 4: Wave-0 RED test scaffolds + VAPID fixture + setup truncation
Status: Completed.
Created tests/fixtures/vapid.ts — exports TEST_VAPID const with a statically inlined P-256 keypair (generated once; no runtime network call; offline-safe).
Created five RED test scaffolds (all fail on Cannot find module — correct RED state):
- tests/lib/pushDispatcher.test.ts — 4 tests: 410/404 prune DELETE, 201 no-delete, 5xx no-delete
- tests/lib/pushCoalescer.test.ts — 3 tests: burst collapses to 1 dispatch with count=N; excludeUserId passed; separate lists are independent
- tests/broker/reminderScheduler.test.ts — 3 tests: all-day excluded (D-07); non-shared excluded (D-05); (uid,minuteBucket) dedup
- tests/lib/eventChangeDispatcher.test.ts — 4 tests: create fires; title-change fires; description-only silent (D-04); actor excluded (D-03)
- tests/routes/push.test.ts — POST 201/401; DELETE removes rows; GET /api/push/vapid-public-key returns
{ publicKey }
Updated test/setup.ts:
- Added
pushSubscriptionsto import from schema - Added
await db.delete(pushSubscriptions)in afterEach (before lists delete; no FK to lists)
Commit: ef558b6 — test(05-01): add Wave-0 RED scaffolds + VAPID fixture + setup truncation
Deviations from Plan
Auto-added: VAPID container-transposability (orchestrator requirement)
The orchestrator folded in a requirement not in the original plan: VAPID env vars must be env-injected in docker-compose.yml, not baked into the image.
- Fix: Added three
${VAPID_*}entries todocker-compose.ymlapienvironment:block (no default fallback — unset = container won't start, which is correct: no VAPID = no push). - Also created: Root
.env.example(the plan listed it infiles_modifiedbut it didn't exist yet) documenting all environment variables for the project including VAPID. - Files modified: docker-compose.yml, .env.example (created)
Package dependencies committed separately (Rule 3 — blocking issue)
Tasks 1/2 package installs were done by the orchestrator but not yet committed (uncommitted changes in apps/api/package.json, apps/pwa/package.json, pnpm-lock.yaml). These were staged and committed as a separate chore commit (80bbdc1) before the schema commit, to keep dependency changes isolated from schema changes.
Known Stubs
None. This plan lays only schema and test scaffolds — no UI rendering or data-flow stubs.
Threat Flags
No new threat surface introduced. VAPID private key is in gitignored .env only; .env.example contains placeholders only (T-05-01 mitigated). Migration used generate+migrate workflow (T-05-02 mitigated). Package installs were pre-approved by human checkpoint Task 1 (T-05-SC mitigated).
Self-Check
Files created/verified:
- apps/api/src/db/migrations/0003_same_xavin.sql — exists
- apps/api/tests/fixtures/vapid.ts — exists
- apps/api/tests/lib/pushDispatcher.test.ts — exists
- apps/api/tests/lib/pushCoalescer.test.ts — exists
- apps/api/tests/broker/reminderScheduler.test.ts — exists
- apps/api/tests/lib/eventChangeDispatcher.test.ts — exists
- apps/api/tests/routes/push.test.ts — exists
- .env.example — exists
Commits verified:
80bbdc1: chore(05-01): install web-push and workbox push dependencies73fcdaf: feat(05-01): add push_subscriptions table + calendar_events.title column; VAPID env wiringef558b6: test(05-01): add Wave-0 RED scaffolds + VAPID fixture + setup truncation
Typecheck: passes (pnpm --filter @familysync/api typecheck — no errors)
RED tests: all 5 scaffold files fail on Cannot find module (correct; implementations in Plans 05-02..05-06)