Files
familysync/.planning/REQUIREMENTS.md

7.4 KiB

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.

REQ-ID Phase Status
SETUP-05 Phase 21 Not started
PROV-01 Phase 22 Not started
CAL-18 Phase 23 Not started
TEST-03 Phase 24 Not started
CAL-16 Phase 25 Not started
CAL-17 Phase 25 Not started
PROV-02 Phase 25 Not started
PROV-03 Phase 26 Not started
PROV-04 Phase 26 Not started
THEME-01 Phase 27 Not started
DEP-01 Phase 28 Not started

Coverage: 11/11 requirements mapped to exactly one phase — no orphans, no duplicates.

Phase Requirements
Phase 21 — Zero-Setup DB Bootstrap SETUP-05
Phase 22 — Provider Abstraction PROV-01
Phase 23 — Multiple Reminders Per Event CAL-18
Phase 24 — Dev/Mock Provider TEST-03
Phase 25 — Google Calendar Provider CAL-16, CAL-17, PROV-02
Phase 26 — Self-Service Provider Onboarding PROV-03, PROV-04
Phase 27 — PWA Dark Mode THEME-01
Phase 28 — Dependency Updates DEP-01