diff --git a/.planning/phases/03-event-write-back-pwa-install/03-09-SUMMARY.md b/.planning/phases/03-event-write-back-pwa-install/03-09-SUMMARY.md new file mode 100644 index 0000000..48065fd --- /dev/null +++ b/.planning/phases/03-event-write-back-pwa-install/03-09-SUMMARY.md @@ -0,0 +1,93 @@ +--- +phase: 03-event-write-back-pwa-install +plan: "09" +subsystem: api-events-router +tags: [tdd, gap-closure, auth, schema, zod, oidc] +dependency_graph: + requires: [] + provides: + - canonical-event-schema-title-start-end + - async-resolveUserId-with-upsertUser + affects: + - apps/api/src/routes/events.ts + - apps/api/tests/routes/events.test.ts + - plan-03-10 (outbox worker reads title/start/end from payload) +tech_stack: + added: [] + patterns: + - "TDD RED→GREEN per task" + - "vi.hoisted() for configurable per-test auth mocks" + - "async resolveUserId with upsertUser for OIDC path" +key_files: + modified: + - apps/api/src/routes/events.ts + - apps/api/tests/routes/events.test.ts +decisions: + - "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)" +metrics: + duration_minutes: 6 + completed_date: "2026-06-06" + tasks_completed: 2 + files_modified: 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