Files
familysync/.planning/phases/03-event-write-back-pwa-install/03-09-SUMMARY.md
T
Lucas Berger 0d3883ee02 docs(03-09): complete plan 09 summary — schema rename + OIDC resolution
CR-01: eventFieldsSchema aligned to canonical title/start/end (PWA contract)
CR-06: resolveUserId async with upsertUser on all 5 write handlers
19 tests pass; tsc clean
2026-06-05 20:42:13 -04:00

4.0 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
03-event-write-back-pwa-install 09 api-events-router
tdd
gap-closure
auth
schema
zod
oidc
requires provides affects
canonical-event-schema-title-start-end
async-resolveUserId-with-upsertUser
apps/api/src/routes/events.ts
apps/api/tests/routes/events.test.ts
plan-03-10 (outbox worker reads title/start/end from payload)
added patterns
TDD RED→GREEN per task
vi.hoisted() for configurable per-test auth mocks
async resolveUserId with upsertUser for OIDC path
modified
apps/api/src/routes/events.ts
apps/api/tests/routes/events.test.ts
D-CR01: Server adopts client field names title/start/end — one canonical name set end-to-end, no rename map
D-CR06: resolveUserId async; dev-bypass path unchanged; OIDC path calls upsertUser(iss,sub,email)
duration_minutes completed_date tasks_completed files_modified
6 2026-06-06 2 2

Phase 03 Plan 09: Route Schema + OIDC Resolution Fix Summary

Fix the events router's two blockers that made the write path dead on arrival: align the server zod schema to the PWA's CreateEventPayload shape (title/start/end), and implement real OIDC iss/sub → users.id resolution on all five write handlers via upsertUser.

Tasks Completed

Task Name Commit Files
1 RED Add contract tests for canonical title/start/end 944693f events.test.ts
1 GREEN Rename eventFieldsSchema to title/start/end (CR-01) 99cb169 events.ts, events.test.ts
2 RED Add OIDC path tests — resolveUserId must call upsertUser 6d1d338 events.test.ts
2 GREEN Async resolveUserId with upsertUser on all 5 handlers (CR-06) fac3a21 events.ts

Verification

  • cd apps/api && npx vitest run tests/routes/events.test.ts: 19 tests pass
  • npx tsc --noEmit in apps/api: clean (no errors)
  • grep -n 'summary\|dtstart\|dtend' eventFieldsSchema: CLEAN (no old names)
  • grep -c 'For now return 401' events.ts: 0 stubs remain
  • grep -c 'upsertUser' events.ts: 3 (import + call in resolveUserId)

Decisions Made

  • D-CR01: Server adopts client field names title/start/end. No internal rename map — one canonical name set end-to-end from PWA through events router to calendarOutbox payload to outbox worker (plan 03-10).
  • D-CR06: resolveUserId is now async. Dev-bypass path (c.get('user')) is unchanged. Production OIDC path calls getAuth(c) then upsertUser(iss, sub, email) to resolve DB user id. Returns null only when no session exists.

Deviations from Plan

Auto-fixed Issues

None. The plan was executed exactly as written, including updating the three existing write tests that previously used the old field names (summary/dtstart/dtend) — this was the correct fix since those tests were testing against the wrong boundary (as the review noted).

Test Infrastructure Deviation (Rule 3)

The worktree has no node_modules — the pnpm workspace installs them in the main repo. Created a symlink apps/api/node_modules → /home/luc/Projects/familysync/apps/api/node_modules so vitest could run from within the worktree. This is a standard git-worktree-with-pnpm-workspace setup requirement.

TDD Gate Compliance

Both tasks followed RED→GREEN strictly:

  • Task 1: test(03-09) commit (944693f) → feat(03-09) commit (99cb169)
  • Task 2: test(03-09) commit (6d1d338) → feat(03-09) commit (fac3a21)

Known Stubs

None. All changes are functional code.

Threat Flags

No new network endpoints, auth paths, file access patterns, or schema changes introduced. The resolveUserId change closes a security gap (CR-06) by ensuring unauthenticated requests correctly 401 while authenticated OIDC sessions get through.

Self-Check: PASSED

  • events.ts: FOUND
  • events.test.ts: FOUND
  • 03-09-SUMMARY.md: FOUND
  • 944693f (test RED task1): FOUND
  • 99cb169 (feat GREEN task1): FOUND
  • 6d1d338 (test RED task2): FOUND
  • fac3a21 (feat GREEN task2): FOUND