From 4e0a5e38e823a4245c2fd7d2fcdbf567515b65cc Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 19 Jun 2026 13:56:19 -0400 Subject: [PATCH] docs: define milestone v1.2 requirements --- .planning/REQUIREMENTS.md | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .planning/REQUIREMENTS.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md new file mode 100644 index 0000000..44fea62 --- /dev/null +++ b/.planning/REQUIREMENTS.md @@ -0,0 +1,78 @@ +# Requirements: FamilySync — v1.2 "Multi-Provider, Theming & Zero-Setup" + +**Defined:** 2026-06-19 +**Milestone:** v1.2 (continues from v1.1 "Operability & Polish", shipped 2026-06-18) +**Core Value:** The household can see and co-edit one color-coded family calendar (shared + each member's personal) and shared lists from a single low-friction PWA — cross-ecosystem, no app store. v1.2 **opens the app beyond Fastmail** (Google Calendar as a first-class provider behind a provider abstraction, with self-service per-provider onboarding), adds **dark mode** and **multiple reminders per event**, and makes the database **bootstrap itself with no manual setup**. + +REQ-IDs continue prior numbering (CAL ≤15, SETUP ≤04, TEST ≤02 already used). New categories: **PROV** (providers & onboarding), **THEME** (PWA theming), **DEP** (dependency maintenance). + +## v1.2 Requirements + +Each requirement maps to exactly one roadmap phase (see Traceability). + +### Providers — abstraction & self-service onboarding + +- [ ] **PROV-01**: All calendar read, write-back, and reminder operations flow through a single `CalendarProvider` abstraction; the existing Fastmail/CalDAV broker is refactored behind it as one implementation with **no behavior regression** to the working Fastmail path (outbox durability, RRULE/VALARM preservation, optimistic-202, per-uid exactly-once all preserved). +- [ ] **PROV-02**: A member can connect a **Google account via a "Connect Google" OAuth flow** (self-service, no admin involvement); the OAuth refresh token is stored encrypted (AES-256-GCM, same path as Fastmail app passwords) and `member_credentials` supports one credential **per provider per user** (`UNIQUE(user_id, provider_type)`). +- [ ] **PROV-03**: A member can self-service connect or re-enter **their own** provider credential using each provider's native mechanism — Fastmail = app-password entry, Google = OAuth consent — without an admin rotating it for them (generalizes the v1.1 admin-managed ADMIN-01 path). +- [ ] **PROV-04**: When a provider connection expires or is revoked, the user sees a **clear, in-calendar banner** (not hidden in settings) and can **reconnect in one tap** by re-running the provider's auth flow, without removing and re-adding the account. + +### Calendar — Google parity & multiple reminders + +- [ ] **CAL-16**: Events from a connected **Google calendar appear in the unified color-coded calendar** (read sync), with recurring events expanded correctly (Google recurrence/cancelled-instance model reconciled to the app's RRULE/EXDATE model) and all-day events not shifted. +- [ ] **CAL-17**: A user can **create / edit / delete events on a connected Google calendar** from the app, written back to Google — full parity with the Fastmail write path, including recurring-event create and whole-series delete. +- [ ] **CAL-18**: A user can set **multiple reminders on a single event** (up to 5), each firing independently; the set serializes to the connected provider's native model (multiple VALARMs for Fastmail / multiple `overrides` for Google), **preserves reminders authored in another client** on edit, and the scheduler fires each lead exactly once (dedup key includes the lead). + +### Theming — PWA dark mode + +- [ ] **THEME-01**: A user can switch the PWA between **Light / Dark / System**, the choice is persisted, there is **no flash-of-wrong-theme** on load, and the dark theme renders cleanly across every route (calendar, lists, admin, settings sheet, login) including the Schedule-X calendar component's `--sx-color-*` variables. + +### Setup — zero-manual-setup database bootstrap + +- [ ] **SETUP-05**: On boot, the app **auto-creates and migrates the full schema** against a bring-your-own MariaDB — the operator supplies only DB credentials and a database name — running drizzle migrations programmatically (`drizzle-orm/mysql2/migrator`, never `drizzle-kit push`), **idempotently and concurrency-safely** (migration-lock sentinel), completing **before requests are served**, so no manual `db:migrate` step is required. + +### Test — dev/mock provider (full-app exercise without a live calendar) + +- [ ] **TEST-03**: A **mock/in-memory `CalendarProvider`** lets the dev-bypass user and the Playwright CI harness exercise the **full app** — calendar create/edit/delete, reminders, and lists — with **no live calendar account**, producing deterministic seed data covering recurring, all-day, past, and future events. + +### Dependencies — apply CI-surfaced updates + +- [ ] **DEP-01**: Apply the **outdated/vulnerable dependency upgrades** surfaced by CI (`pnpm audit` / `pnpm outdated`), respecting the existing version pins and constraints (ESLint held at 9.x until `eslint-plugin-react` supports 10; Drizzle/drizzle-kit kept coupled; Schedule-X minor-only and not bumped before dark mode is locked), with **all CI gates green** after the update. + +## Future Requirements (deferred, not in v1.2) + +- **Additional calendar providers** beyond Fastmail + Google (the PROV-01 abstraction makes them cheaper to add later). +- **Google Calendar webhook push** (`events.watch`) for lower-latency sync — the existing 5-min ctag/poll model is sufficient for a two-person household; evaluate only if latency becomes a problem. +- **Wizard re-run / reconfigure** flow after first setup (carried from v1.1 backlog). +- **Android PWA install walkthrough** verified on a real device (carried from v1.0). +- **Tablet / touchscreen UX** — explicitly reserved for **v1.3**. + +## Out of Scope (explicit exclusions) + +- **Modern visual styling refresh** (backlog 999.21) — current UX is satisfactory; this is a separate future redesign track, not v1.2. +- **Per-event Google color (`colorId`) honoring** — FamilySync uses its own per-calendar colors for consistency; Google's per-event colors are ignored. +- **CalDAV/JMAP for Google** — Google integration uses the Google Calendar API + OAuth2; no CalDAV bridge. +- **Notification-preferences UI / reminder snooze** — the per-event multi-reminder selector (CAL-18) is sufficient for a 2-member household. +- **`googleapis` monolith** — use the scoped `@googleapis/calendar` + `google-auth-library` to avoid the ~50 MB footprint. +- **`drizzle-kit push` at boot** — emits a false destructive diff on populated MariaDB 11; boot migration uses the `migrate()` API only. +- **Bulk `pnpm up`** for DEP-01 — selective, pin-aware updates only. + +## Traceability + +Maps each REQ-ID to its phase. v1.2 phases continue prior numbering (v1.1 ended at Phase 20) → v1.2 starts at **Phase 21**. _Filled by the roadmapper._ + +| REQ-ID | Phase | Status | +| -------- | ----- | ----------- | +| SETUP-05 | TBD | Not started | +| PROV-01 | TBD | Not started | +| PROV-02 | TBD | Not started | +| PROV-03 | TBD | Not started | +| PROV-04 | TBD | Not started | +| CAL-16 | TBD | Not started | +| CAL-17 | TBD | Not started | +| CAL-18 | TBD | Not started | +| THEME-01 | TBD | Not started | +| TEST-03 | TBD | Not started | +| DEP-01 | TBD | Not started | + +**Coverage:** 11 requirements, mapping pending roadmap creation.