10 KiB
Roadmap: FamilySync
Overview
FamilySync is built in five phases, each delivering an end-to-end user-observable capability. Phase 1 is both the foundation and the highest-risk gate: OIDC auth must work and the CalDAV broker must prove it can read personal Fastmail calendars before any calendar UI is built. Phases 2–3 complete the calendar. Phase 4 delivers shared lists with live co-edit sync. Phase 5 wires up Web Push notifications. The dependency chain is strict: each phase is a prerequisite for the next, except the lists track (Phase 4) which is independent of the calendar write path.
Phases
Phase Numbering:
- Integer phases (1, 2, 3): Planned milestone work
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
Decimal phases appear between their surrounding integers in numeric order.
- Phase 1: Foundation + Broker Spike - Auth, Docker scaffold, CalDAV broker read path, and personal-calendar ACL spike (go/no-go gate) (completed 2026-06-04)
- Phase 2: Calendar Display - Read-only unified color-coded calendar (week/month/day/agenda) built on the confirmed broker
- Phase 3: Event Write-Back + PWA Install - Full event CRUD written back to Fastmail, PWA manifest + service worker, guided iOS install flow
- Phase 4: Shared Lists + Live Sync - Named collaborative lists with item CRUD and real-time SSE co-edit sync
- Phase 5: Web Push Notifications - VAPID push for event reminders, event changes, and list-change alerts
Phase Details
Phase 1: Foundation + Broker Spike
Goal: The app stack is running, both members can authenticate, and the CalDAV broker can read Fastmail calendars — with a confirmed go/no-go decision on personal-calendar cross-account sharing Mode: mvp Depends on: Nothing (first phase) Requirements: AUTH-01, AUTH-02, AUTH-03, CAL-01, CAL-08 Success Criteria (what must be TRUE):
- Both members can reach the app URL, authenticate through Authelia OIDC, and land on the app home page without entering any Fastmail credentials
- Sessions persist across browser restarts — neither member is asked to log in again on the next visit
- Each member is assigned a stable, distinct display color that does not change between sessions
- The broker successfully fetches and caches at least one event from the shared Fastmail calendar via CalDAV PROPFIND/REPORT
- The personal-calendar ACL spike produces a documented go/no-go decision: either the broker token sees the wife's personal calendar after Fastmail share+accept, or the fallback strategy (shared-family-only or per-member app password) is chosen and recorded
Verification status (D-14, 2026-06-04): Code + Gate 1 complete. Gate 1 = stack up (/health live), CAL-01 proven live (503 real events cached via REPORT), CAL-08 = GO (per-member app-password model, see CAL-08-DECISION.md). Gate 2 deferred — criteria 1/2/3 (live Authelia OIDC login over Pangolin, session persistence, distinct colors in a real browser) and the SSE-over-Pangolin smoke test require the operator's Authelia + Pangolin/Newt infra; tracked in 01-HUMAN-UAT.md and docs/deployment.md. The live AUTH smoke (incl. iOS) is folded into Phase 3; the SSE smoke is a hard gate before Phase 4. Phases 2–3 develop behind a documented dev-auth bypass.
Plans: 4 plans Plans:
- 01-01-PLAN.md — Walking skeleton: monorepo scaffold + Docker/MariaDB + Drizzle schema (push) + /health end-to-end slice + Vitest Wave 0 harness
- 01-02-PLAN.md — Authelia OIDC slice: stable identity (iss+sub) + auto-assigned member color + /api/me + authenticated PWA shell (AUTH-01/02/03)
- 01-03-PLAN.md — CalDAV broker slice: AES-256-GCM credential encryption + tsdav broker + ical.js sync (all-day DATE) + ctag poller + /api/events (CAL-01)
- 01-04-PLAN.md — Integration + gate: wire poller/routes, event-proof landing page, CAL-08 spike + go/no-go doc, live Pangolin deploy + SSE smoke test
Phase 2: Calendar Display
Goal: Both members can see a unified, color-coded calendar aggregating all accessible Fastmail calendars across day, week, month, and agenda views — read-only, no write-back yet Mode: mvp Depends on: Phase 1 Requirements: CAL-02, CAL-03, CAL-07 Success Criteria (what must be TRUE):
- Opening the app shows a color-coded calendar where each member's events appear in their assigned color, with shared events distinguishable from personal events
- The user can switch between day, week, month, and agenda views and all events render correctly in each view
- A recurring event (e.g., weekly meeting) displays all its occurrences correctly in the current view window, including correct behavior across DST boundaries
- All-day events (birthdays, holidays) appear as full-day banners on the correct date with no timezone shift
Plans: 5 plans Plans:
- 02-01-PLAN.md — Foundation: schema (hasRrule + calendars.isShared, pushed) + dev-auth bypass + PWA vitest/jsdom harness + ICS fixtures + RED test stubs
- 02-02-PLAN.md — Backend slice: expandOccurrences() (VTIMEZONE/DST + all-day + EXDATE) + windowed/joined/zod-validated /api/events + shared-calendar checkpoint (CAL-02/CAL-07)
- 02-03-PLAN.md — Frontend foundation: CSS token layer + colorUtils + calendarConfig (firstDayOfWeek 0→7) + hydrateEvents (Temporal/PlainDate guard) + Zustand store + windowed fetchEvents
- 02-04-PLAN.md — Vertical slice: CalendarShell mounts Schedule-X, renders real windowed Fastmail events color-coded across all four views (CAL-02/CAL-03)
- 02-05-PLAN.md — UX completion: read-only EventDetailPopover + ColorLegend + nav/toolbar + skeleton/empty/error states + human visual verification
UI hint: yes
Phase 3: Event Write-Back + PWA Install
Goal: Both members can create, edit, and delete events that are written back to the correct Fastmail calendar, and the app is installable to the iPhone and Android home screens with a guided onboarding flow Mode: mvp Depends on: Phase 2 Requirements: CAL-04, CAL-05, CAL-06, CAL-07, PWA-01, PWA-02 Success Criteria (what must be TRUE):
- A member can create a timed or all-day event (including recurring events) in the app and see it appear in the native Fastmail app within the next sync cycle
- A member can edit an existing event's title, time, or description and the change persists correctly in Fastmail
- A member can delete an event and it disappears from all views on the next sync
- On Android, the app shows a browser install prompt and installs to the home screen; on iOS, the app shows a guided "Add to Home Screen" walkthrough with annotated screenshots that a non-technical user can follow independently
- The installed PWA opens full-screen without browser chrome on both iOS and Android
- (Carried from Phase 1 Gate 2, D-14) Live Authelia OIDC login works over the public Pangolin URL — including the iOS standalone-PWA flow: the wife can install to Home Screen and complete login without the redirect breaking out of standalone mode; sessions persist (AUTH-01/02) and members get distinct stable colors (AUTH-03). Verify per
docs/deployment.mdGate 2 checklist; this is the first real external deploy (local Newt test rig is sufficient — Unraid prod is optional until go-live).
Plans: TBD UI hint: yes
Phase 4: Shared Lists + Live Sync
Goal: Both members can create and manage shared named lists with real-time co-edit sync — edits by one member appear for the other without any manual refresh
Mode: mvp
Depends on: Phase 1
⚠️ Entry gate (D-14): The SSE-over-Pangolin smoke test (deferred from Phase 1 Gate 2, issue #1034) MUST pass before building live sync — hold /api/sse/heartbeat open 5+ min through the tunnel without it being cut (see docs/deployment.md). If it FAILS: fix Pangolin idle-timeout/buffering, or plan a reconnect/polling fallback into this phase before proceeding. Do not build the live-sync layer on an unverified transport.
Requirements: LIST-01, LIST-02, LIST-03, LIST-04
Success Criteria (what must be TRUE):
- Either member can create a named list (e.g., "Groceries") and delete a list they no longer need
- Either member can add items to a list, check items off, reorder them by drag-and-drop, and delete individual items
- When one member adds or checks off an item, the other member sees the change appear in the list within a few seconds without refreshing — even if they reconnect after a brief network gap
Plans: TBD UI hint: yes
Phase 5: Web Push Notifications
Goal: Both members receive timely Web Push alerts for upcoming events, event changes made by the other member, and list changes — reliably on both iOS and Android Mode: mvp Depends on: Phase 3, Phase 4 Requirements: NOTIF-01, NOTIF-02, NOTIF-03 Success Criteria (what must be TRUE):
- A member receives a push notification on their phone approximately 15 minutes before a calendar event starts — delivered to the installed PWA, including on iOS
- When the other member adds or changes a calendar event, the first member receives a push notification with the event title and action described in the payload
- When the other member modifies a shared list (adds, checks off, or deletes an item), the first member receives a push notification identifying the list and the change
- After an extended period of app inactivity, push notifications are still delivered (subscription health-check prevents silent revocation on iOS)
Plans: TBD
Progress
Execution Order: Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 Note: Phase 4 depends only on Phase 1 and can begin as soon as Phase 1 is complete. It is serialized here to reduce work-in-progress.
| Phase | Plans Complete | Status | Completed |
|---|---|---|---|
| 1. Foundation + Broker Spike | 4/4 | Complete | 2026-06-04 |
| 2. Calendar Display | 0/? | Not started | - |
| 3. Event Write-Back + PWA Install | 0/? | Not started | - |
| 4. Shared Lists + Live Sync | 0/? | Not started | - |
| 5. Web Push Notifications | 0/? | Not started | - |