90 lines
7.4 KiB
Markdown
90 lines
7.4 KiB
Markdown
# 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 |
|