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
This commit is contained in:
@@ -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
|
||||||
Reference in New Issue
Block a user