Files
familysync/.planning/phases/03-event-write-back-pwa-install/03-01-SUMMARY.md
T

133 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 03-event-write-back-pwa-install
plan: 01
subsystem: database, testing, infra
tags: [drizzle, mariadb, vitest, vite-plugin-pwa, caldav, outbox]
# Dependency graph
requires:
- phase: 02-calendar-read-display
provides: calendarEvents table, sync.ts upsert loop, existing test infrastructure
provides:
- calendarOutbox table live in MariaDB (calendar_outbox, 3 indexes)
- calendarEvents.objectUrl column live in MariaDB (object_url varchar 1024)
- vite-plugin-pwa installed in apps/pwa
- Five Wave 0 RED test files covering all Phase 3 behaviors (vevent, write, outboxWorker, events routes, InstallPrompt)
affects: [03-02, 03-03, 03-04, 03-05, 03-06, 03-07, 03-08]
# Tech tracking
tech-stack:
added: [vite-plugin-pwa@1.3.0]
patterns:
- mysqlEnum for outbox status/operation columns in Drizzle schema
- objectUrl stored on calendarEvents from obj.url during sync upsert
- Wave 0 RED scaffold: import not-yet-existing modules so test suite fails before implementation
key-files:
created:
- apps/api/tests/broker/vevent.test.ts
- apps/api/tests/broker/write.test.ts
- apps/api/tests/broker/outboxWorker.test.ts
- apps/pwa/src/components/InstallPrompt.test.tsx
modified:
- apps/api/src/db/schema.ts
- apps/api/src/broker/sync.ts
- apps/api/tests/routes/events.test.ts
- apps/pwa/package.json
key-decisions:
- "D-Task5-DDL: drizzle-kit push is unsafe on MariaDB 11 with mysql dialect — misreads metadata and schedules truncate on populated tables. Additive DDL (calendar_outbox CREATE + object_url ALTER) was hand-applied and verified. Adopt drizzle-kit generate+migrate workflow before next schema change (tracked in todos/pending/adopt-drizzle-migrations-workflow.md)."
patterns-established:
- "Outbox pattern: calendar_outbox table with status enum (pending/done/failed/dead), groupId for edit-as-move pairing, nextAttemptAt for exponential backoff"
- "objectUrl stored from tsdav obj.url on every sync upsert — enables If-Match header on CalDAV update/delete"
- "Wave 0 RED scaffold: all phase test files created before any implementation so GREEN gate is explicit"
requirements-completed: [CAL-04, CAL-05, CAL-06, CAL-07, PWA-01, PWA-02]
# Metrics
duration: ~45min
completed: 2026-06-05
---
# Phase 03 Plan 01: Foundation Scaffold Summary
**calendarOutbox table + calendarEvents.objectUrl pushed live to MariaDB, vite-plugin-pwa installed, and five Wave 0 RED test files covering all Phase 3 write-back and PWA behaviors**
## Performance
- **Duration:** ~45 min
- **Started:** 2026-06-05T21:18Z
- **Completed:** 2026-06-05T22:10Z
- **Tasks:** 5 (Tasks 1-5; Task 1 was human-verify gate, Task 5 was human-action gate)
- **Files modified:** 8
## Accomplishments
- Extended Drizzle schema with `calendarOutbox` table (12 columns, 3 indexes: idx_outbox_user_status, idx_outbox_next_attempt, idx_outbox_uid) and `calendarEvents.objectUrl` column; both live in MariaDB
- Populated `objectUrl: obj.url ?? null` in both `.values()` and `.onDuplicateKeyUpdate()` blocks of the calendarEvents upsert in sync.ts — enables If-Match writes (D-08)
- Installed `vite-plugin-pwa` (legitimacy-gated via Task 1 supply-chain checkpoint T-03-SC)
- Created five Wave 0 RED test files covering every Phase 3 behavior: VEVENT builder, CalDAV write layer, outbox state machine, events API routes, and PWA InstallPrompt
## Task Commits
1. **Task 1: Supply-chain gate T-03-SC** — no commit (verification-only checkpoint)
2. **Task 2: Extend Drizzle schema + install vite-plugin-pwa**`78f0dee` (feat)
3. **Task 3: Populate calendarEvents.objectUrl in sync.ts**`0c0bcef` (feat)
4. **Task 4: Wave 0 RED test scaffold**`bbfccda` (test)
5. **Task 5: Push schema to MariaDB** — hand-applied DDL by orchestrator (no code commit; DB verified)
## Files Created/Modified
- `apps/api/src/db/schema.ts` — added mysqlEnum import, calendarOutbox table definition, groupId column, 3 indexes; added objectUrl column to calendarEvents
- `apps/api/src/broker/sync.ts` — set `objectUrl: obj.url ?? null` in values and onDuplicateKeyUpdate blocks
- `apps/api/tests/broker/vevent.test.ts` — RED: VCALENDAR/VEVENT builder tests (timed, all-day D-13, RRULE)
- `apps/api/tests/broker/write.test.ts` — RED: createCalendarEvent, updateCalendarEvent (If-Match), deleteCalendarEvent
- `apps/api/tests/broker/outboxWorker.test.ts` — RED: outbox state machine (pending→done/failed/backoff/dead), edit-as-move ordering (D-04)
- `apps/api/tests/routes/events.test.ts` — extended with POST create, PATCH edit, DELETE, sync-status, writable-calendars, D-03 access control
- `apps/pwa/src/components/InstallPrompt.test.tsx` — RED: isIOSSafariNonStandalone(), useAndroidInstallPrompt
- `apps/pwa/package.json` — added vite-plugin-pwa dependency
## Decisions Made
- **D-Task5-DDL:** `drizzle-kit push` with the `mysql` dialect against a live MariaDB 11 instance produces a FALSE destructive diff — it misreads MariaDB-11 metadata and schedules `truncate table` on `calendars`, `calendar_events`, and `users` (503 events at risk). The two genuinely additive statements were hand-applied by the orchestrator and verified. A follow-up todo (`.planning/todos/pending/adopt-drizzle-migrations-workflow.md`) tracks migrating to `drizzle-kit generate` + `drizzle-kit migrate` before any future schema change. No `drizzle-kit push` should be run against this instance again.
## Deviations from Plan
### Task 5: drizzle-kit push replaced by hand-applied additive DDL
**Category:** Orchestrator-resolved deviation (not a Rule 14 auto-fix; resolved by human operator per gate instructions)
- **Found during:** Task 5 (blocking human-action gate)
- **Issue:** `drizzle-kit push` with the Drizzle `mysql` dialect against MariaDB 11 misread database metadata and reported a destructive plan including `truncate table` on `calendars`, `calendar_events`, and `users`. This is a known incompatibility — drizzle-kit 0.31.10 has no `mariadb` dialect; the `mysql` dialect misinterprets MariaDB-11 server metadata.
- **Fix:** Orchestrator manually ran only the two additive statements: `CREATE TABLE calendar_outbox (...)` matching schema.ts exactly, and `ALTER TABLE calendar_events ADD COLUMN object_url varchar(1024)`. Data verified intact (calendars=1, calendar_events=503).
- **Files modified:** None (DB DDL only; schema.ts was already correct)
- **Verification:** `SHOW TABLES LIKE 'calendar_outbox'` → 1 row; `SHOW COLUMNS FROM calendar_events LIKE 'object_url'` → 1 row
- **Follow-up:** `.planning/todos/pending/adopt-drizzle-migrations-workflow.md` created to track migrating to generate+migrate workflow
---
**Total deviations:** 1 (Task 5 DDL approach replaced; resolved by operator at the blocking gate)
**Impact on plan:** No scope creep. Schema is correct. Must-haves fully satisfied. Follow-up todo prevents recurrence.
## Issues Encountered
None beyond the Task 5 drizzle-kit deviation documented above.
## User Setup Required
None — no external service configuration required for this plan. The schema push was a one-time operation handled by the orchestrator at the Task 5 gate.
## Next Phase Readiness
- Wave 0 RED scaffold is in place — plans 03-02 through 03-08 can proceed to GREEN implementation
- `calendarOutbox` and `calendarEvents.objectUrl` are live; outbox worker and write routes can reference them immediately
- `vite-plugin-pwa` is installed; PWA manifest configuration (Plan 03-06) can proceed
- **Action before next schema change:** Adopt `drizzle-kit generate` + `drizzle-kit migrate` (see pending todo) — do NOT run `drizzle-kit push` again
---
*Phase: 03-event-write-back-pwa-install*
*Completed: 2026-06-05*