Files
familysync/.planning/REQUIREMENTS.md
T
Lucas Berger 982438dc10 style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
2026-06-11 20:35:18 -04:00

93 lines
8.3 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.
# Requirements: FamilySync — v1.1 "Operability & Polish"
**Defined:** 2026-06-10
**Milestone:** v1.1 (continues from v1.0 MVP, shipped 2026-06-10)
**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.1 makes that app **configurable, administrable, and maintainable** without hand-editing env files or the database.
REQ-IDs continue v1.0 numbering (CAL ≤12, NOTIF ≤3 already used). New categories: ADMIN, SETUP, CI, TEST.
## v1.1 Requirements
Each requirement maps to exactly one roadmap phase (see Traceability).
### Calendar — Per-event reminders & write-back latency
- [ ] **CAL-13**: User can choose a reminder lead time when creating or editing an event from a preset list (None / 5m / 10m / 15m / 30m / 1h / 2h / 1d / 2d), with **"None" as the default**; the choice is serialized as a VALARM on the event written back to Fastmail.
- [ ] **CAL-14**: Editing an event **preserves any existing reminder/VALARM** set in another client (Fastmail or native) — reminders are never silently stripped on round-trip.
- [ ] **CAL-15**: A created, edited, or deleted event reaches Fastmail within ~2 seconds (event-driven outbox drain) instead of up to ~15s, while preserving the optimistic-202 accept and all outbox durability guarantees (create-before-delete ordering, drain concurrency guard, fresh-etag-before-PUT, per-uid exactly-once).
### Notifications — Variable-lead reminder scheduling
- [ ] **NOTIF-04**: An event reminder push fires at the event's **chosen lead time**, not a hardcoded 15-minute lead.
- [ ] **NOTIF-05**: An event with **no reminder set produces no reminder push** (no default 15-min fire).
- [ ] **NOTIF-06**: An all-day event's reminder fires at a sensible local time (9 AM on the alert day), not at midnight, and reminder delivery remains exactly-once across catch-up scans and rescheduled events.
### Administration — Settings section (role-gated)
> Role-agnostic design: ship operator-only (`is_admin`), but the role check is member-count-agnostic so more admins can be added later without rework.
- [ ] **ADMIN-01**: An admin can view household members and update (rotate / re-enter) a member's Fastmail app password from the UI; the credential is validated against CalDAV before saving and stored encrypted (existing `APP_PASSWORD_ENCRYPTION_KEY` path) — the password is never displayed, logged, or echoed.
- [ ] **ADMIN-02**: An admin can designate which synced calendar is the shared family calendar (set `calendars.is_shared`) from the UI, replacing the manual DB write.
- [ ] **ADMIN-03**: Admin Settings routes and UI are gated by a role check; a non-admin member cannot reach or invoke them.
### Setup — First-run configuration wizard
- [ ] **SETUP-01**: On first run (no admin/credentials configured), the operator is guided through a setup wizard to define bootstrap configuration (app/external URL, OIDC client, session secret, encryption key, VAPID keypair, MariaDB connection, first member's Fastmail app password) instead of hand-editing `.env` / `docker-compose.yml`.
- [ ] **SETUP-02**: The wizard **validates each input before completing** — DB connectivity test, VAPID private key decodes to 32 bytes and pairs with the public key, OIDC discovery resolves, and the Fastmail app password reaches CalDAV (PROPFIND).
- [ ] **SETUP-03**: The wizard generates secrets (session secret, encryption key, VAPID keypair) for the operator to copy into env; secrets are **never written to the database or returned in a response body**.
- [ ] **SETUP-04**: Once setup is complete, the setup endpoints are no longer accessible (guard checked on every invocation, not only at startup).
### CI — Gitea continuous integration
- [x] **CI-01**: Every pull request targeting `main` runs full regression — lint, typecheck (both apps), unit tests, API integration tests against a MariaDB service container, **and the Phase 7 mobile Playwright harness as a UI-regression step (CI brings up the API + PWA dev servers + MariaDB service container with `DEV_AUTH_BYPASS` in the runner and runs the harness specs headlessly against the authed PWA)** — and the result gates the merge.
- [x] **CI-02**: On merge to `main`, the API Docker image is built and published to the Gitea container registry.
### Test — Mobile-emulated authed browser harness
- [x] **TEST-01**: The assistant can drive the PWA in a **mobile-emulated viewport** (device profile + mobile UA + touch) for automated UI/layout verification.
- [x] **TEST-02**: Automated runs reach the **authenticated** PWA via the existing `DEV_AUTH_BYPASS` on the host-side dev stack (no manual login, no Authelia/OIDC mocking). Targets the dev build; real prod-service-worker mobile testing is out of scope (see below). The harness specs are also consumed by Phase 8 (Gitea CI) as the PR UI-regression step.
## Future Requirements (deferred, not in v1.1)
- **Multiple reminders per event** (2× VALARM) — stretch; deferred to v1.2.
- **Self-service provider onboarding** (backlog 999.5) — a member adds their _own_ Fastmail app password on first login. v1.1 covers this admin-managed (ADMIN-01); self-service deferred.
- **Calendar provider abstraction** (backlog 999.1) — provider interface so Fastmail is one of several backends.
- **Android PWA install walkthrough** verified on a real device (carried from v1.0).
- **Wizard re-run / reconfigure** flow after first setup.
## Out of Scope (explicit exclusions)
- **Notification-preferences UI, reminder snooze** — over-build for a 2-member household; the per-event selector (CAL-13) is sufficient.
- **Admin audit log, health dashboard, user-management/CRUD** — scope creep for a tiny self-hosted app.
- **Real-device iOS push / standalone CI** — remains a human/device gate, as in v1.0; the mobile harness covers responsive layout + authed flows only, not iOS-Safari-standalone behavior.
- **Mobile testing against the prod service-worker build past real Authelia** — `DEV_AUTH_BYPASS` only reaches the dev build (no real SW). A reusable Authelia storage-state to drive the prod-SW PWA is deferred; not worth the complexity for v1.1's layout/flow goal.
- **Redis pub/sub for the outbox drain** — the drain is single-process by design; an in-process EventEmitter is correct. (Redis stays for list SSE.)
- **node-cron** — silently skips ticks in the long-lived process; schedulers stay on `setInterval`.
- **drizzle-kit push** — emits a false destructive diff on populated MariaDB; migrations use generate+migrate.
## Traceability
Maps each REQ-ID to its phase. v1.1 phases continue v1.0 numbering (v1.0 ended at Phase 6) → v1.1 starts at Phase 7. **Coverage: 17/17 v1.1 requirements mapped, no orphans, no duplicates.**
| REQ-ID | Phase | Status |
| -------- | -------------------------------- | -------- |
| TEST-01 | Phase 7 (Mobile Test Harness) | Complete |
| TEST-02 | Phase 7 (Mobile Test Harness) | Complete |
| CI-01 | Phase 8 (Gitea CI) | Complete |
| CI-02 | Phase 8 (Gitea CI) | Complete |
| CAL-15 | Phase 9 (Faster Write-Back) | Pending |
| ADMIN-01 | Phase 10 (Admin Role & Settings) | Pending |
| ADMIN-02 | Phase 10 (Admin Role & Settings) | Pending |
| ADMIN-03 | Phase 10 (Admin Role & Settings) | Pending |
| CAL-13 | Phase 11 (Per-Event Reminders) | Pending |
| CAL-14 | Phase 11 (Per-Event Reminders) | Pending |
| NOTIF-04 | Phase 11 (Per-Event Reminders) | Pending |
| NOTIF-05 | Phase 11 (Per-Event Reminders) | Pending |
| NOTIF-06 | Phase 11 (Per-Event Reminders) | Pending |
| SETUP-01 | Phase 12 (Initial Setup Wizard) | Pending |
| SETUP-02 | Phase 12 (Initial Setup Wizard) | Pending |
| SETUP-03 | Phase 12 (Initial Setup Wizard) | Pending |
| SETUP-04 | Phase 12 (Initial Setup Wizard) | Pending |
**DB foundation note:** The v1.1 schema migration (`users.is_admin`, `calendar_events.reminder_lead_minutes`, `app_config` table) is not a standalone requirement — it is carried by **Phase 10 (Admin Role & Settings)** (which owns is_admin + app_config) and consumed by **Phase 11 (Per-Event Reminders)** (reminder_lead_minutes) and **Phase 12 (Initial Setup Wizard)** (app_config.setup_complete). Folded per ARCHITECTURE.md ordering rather than created as a migration-only phase. This makes Phase 10 the head of the admin chain (10 → 11, 10 → 12).