commit 16db88dabf013b2aa643dca0403021b3df928912 Author: Lucas Berger Date: Wed Jun 3 14:34:58 2026 -0400 initial commit diff --git a/.planning/notes/familysync-architecture.md b/.planning/notes/familysync-architecture.md new file mode 100644 index 0000000..c74dcef --- /dev/null +++ b/.planning/notes/familysync-architecture.md @@ -0,0 +1,112 @@ +--- +title: FamilySync Architecture Decisions +date: 2026-06-02 +context: Exploration + verification sessions — reasoning captured before project kickoff +--- + +# FamilySync Architecture Decisions + +## What we're building + +A self-hosted family organization hub, modeled loosely on Skylight, with two concerns: +1. **Shared calendar** — one family calendar everyone can see and edit, surfaced natively + where possible and in a custom app everywhere else +2. **Shared collaborative lists** — grocery lists, gift ideas, anything co-edited +3. **Family display** — Skylight-style always-on view + mobile-accessible dashboard + +Email is **out of scope** — members keep using their existing mail clients unchanged. + +## Household + +- **Primary user (me):** Fastmail account, Android, uses the Fastmail app +- **Other members (e.g. wife):** Apple (iPhone/Mac) +- Wife adoption is a hard UX constraint — must be slick and low-friction + +## Infrastructure + +- **Host**: Unraid running Docker containers + Docker Compose +- **Auth**: Authelia (already deployed) — OIDC/OAuth2 for the custom app +- **DNS**: Split-DNS internal domain, private IPs internally +- **Public exposure**: Pangolin/Newt tunnel (no open ports) +- **Database**: MariaDB (preferred), Redis available, PostgreSQL not available +- **Existing service leveraged**: Fastmail (paid) — used as the calendar host + +## Stack decisions (verified) + +### Calendar → Fastmail (NOT self-hosted) + +The shared family calendar lives on Fastmail. Self-hosting the calendar data was evaluated and +explicitly rejected as unnecessary — Fastmail already provides a CalDAV/JMAP server everyone can +reach. + +- **Me (Android/Fastmail):** native in the Fastmail app, read-write. Nothing to install. +- **Custom app:** holds a Fastmail JMAP/CalDAV token; reads AND writes the shared calendar as the + broker for everyone else. +- **Apple members:** use the PWA by default (app writes to Fastmail on their behalf — no Fastmail + account needed). Optional: add the Fastmail calendar via CalDAV to native Apple Calendar for + native read-write. Not required. + +**Why not Baikal (self-hosted CalDAV)?** It was the prior pick, now dropped. The Fastmail Android +app cannot display a self-hosted CalDAV calendar, so Baikal bought *me* nothing on Android — it +only helped Apple members, who are equally served by the PWA. Fastmail-hosted gives the whole +household native-or-PWA access with one fewer self-hosted service. + +**Reversibility:** if self-hosted calendar is ever wanted, Baikal slots in as source of truth and +the app reads from it instead of Fastmail. Nothing else changes. + +### Lists → custom app backend (MariaDB) + +Shared lists live directly in the custom app's MariaDB, served via the app's own API to the PWA. +Redis optional for live/push updates. + +**Why not Vikunja?** Prior pick, now dropped. Native cross-ecosystem list sync is impossible here +(Apple Reminders is CalDAV VTODO; Fastmail has no real tasks product; Google Tasks isn't CalDAV). +So lists must live in the app regardless. Since the custom backend is being built anyway, a list +table in its own MariaDB is trivial — whereas Vikunja means another container, another schema, and +another Authelia SSO integration to maintain for features (assignees, gantt, recurring) not needed +for "groceries + gift ideas." Reversible later if richer task management is wanted. + +### Display + aggregation → custom app (the actual product) + +- Aggregates the Fastmail shared calendar (+ optionally each member's personal calendars) into a + unified, color-coded family view — the Skylight magic; nothing off-the-shelf does this. +- Owns the shared lists. +- Authelia OIDC for app login (true SSO; no separate calendar credential problem since Baikal is gone). +- Serves the React PWA + the wall-display view. + +### Frontend → React PWA + +- Runs as a kiosk URL on a wall-mounted display (future state) +- Installable on iPhone/Android via "Add to Home Screen" — no App Store +- Wife onboards by visiting one URL — the universal surface for everyone +- Single codebase for all surfaces (display, phone, desktop) + +## What we decided NOT to do + +- **No self-hosted calendar server (Baikal)** — Fastmail hosts the calendar +- **No Vikunja** — lists live in the custom backend +- **No DAVx5** — not needed +- **No forking** — value is the aggregation/display layer, not the backends +- **No React Native / App Store** — PWA gives app-like experience without publishing overhead +- **No PostgreSQL** — not in the existing stack +- **No email features** — out of scope + +## Net result + +You build **one thing** — the custom app (backend + MariaDB + React PWA) behind Authelia — on top +of Fastmail you already pay for. Far lighter than the prior Baikal + Vikunja + PWA design, and the +lowest-friction path for non-technical household members (one PWA). + +## Open questions + +- Fastmail API: JMAP vs CalDAV for the app's calendar read/write — which is cleaner to build against? +- Aggregating Apple members' *personal* calendars into the display — via shared CalDAV/ICS, or skip + and only show the shared family calendar? +- PWA push notifications: sufficient for family alerts, or need something else? + +## Resolved questions + +- **Calendar host**: Fastmail (self-hosting rejected as unnecessary) +- **Calendar server (Baikal vs Radicale)**: moot — calendar moved to Fastmail +- **Lists backend (Vikunja)**: dropped — lists live in the custom app's MariaDB +- **Email**: out of scope diff --git a/.planning/research/questions.md b/.planning/research/questions.md new file mode 100644 index 0000000..f457374 --- /dev/null +++ b/.planning/research/questions.md @@ -0,0 +1,46 @@ +# Research Questions + +## Open + +### RQ-003 — Fastmail calendar API: JMAP vs CalDAV +**Question**: For the custom app to read AND write the shared family calendar on Fastmail, is JMAP +or CalDAV the cleaner integration? Can a scoped Fastmail API token grant calendar read-write without +exposing the full account? + +**Why it matters**: The app brokers calendar access for all Apple members via the PWA, so reliable +programmatic read-write to the Fastmail calendar is core. JMAP is Fastmail-native and modern; CalDAV +is the interoperable standard. + +**Suggested approach**: Check Fastmail JMAP Calendars docs + API token scoping. Confirm event +create/update/delete works via token. Compare to CalDAV (sabre-dav style) effort. + +--- + +## Resolved + +### RQ-001 — Vikunja MariaDB compatibility — SUPERSEDED +Vikunja was dropped from the architecture (lists now live in the custom app's own MariaDB). The +MariaDB findings still apply to the custom app itself: use MariaDB 10.6+, set `utf8mb4` collation, +pin versions before upgrades. + +--- + +### RQ-002 — CalDAV server: Radicale vs Baikal — SUPERSEDED +Both dropped. The shared calendar now lives on **Fastmail**, not a self-hosted CalDAV server. +Rationale: the Fastmail Android app cannot display a self-hosted CalDAV calendar, so Baikal gave the +primary (Android/Fastmail) user no native benefit — it only helped Apple members, who are equally +served by the PWA. Fastmail-hosted removes a self-hosted service while keeping native access for the +Fastmail user and PWA access for everyone. + +Original finding (retained for reversibility): if self-hosting the calendar is ever required, **Baikal** +(`ckulka/baikal`) is the pick over Radicale — Radicale has no native shared-calendar write support. + +--- + +### Calendar host decision — RESOLVED +Self-hosting the calendar data was evaluated and rejected. Fastmail (already paid for) hosts the +shared family calendar. Other household members are Apple — they reach it via the PWA (default) or +native Apple Calendar over CalDAV (optional). + +### Email scope — RESOLVED +Out of scope. Members keep existing mail clients unchanged. diff --git a/.planning/todos/pending/kickoff-new-project.md b/.planning/todos/pending/kickoff-new-project.md new file mode 100644 index 0000000..1f0f6f4 --- /dev/null +++ b/.planning/todos/pending/kickoff-new-project.md @@ -0,0 +1,31 @@ +--- +title: Kick off FamilySync with /gsd:new-project +date: 2026-06-02 +priority: high +--- + +# Kick off FamilySync with /gsd:new-project + +Run `/gsd:new-project` to formalize the architecture decisions into a PROJECT.md, REQUIREMENTS.md, +and ROADMAP.md with phase breakdown. + +Architecture is verified and settled (see `.planning/notes/familysync-architecture.md`). + +## Pre-work before running + +- [ ] (Optional) Answer RQ-003: Fastmail calendar API — JMAP vs CalDAV for app read/write +- [ ] Review `.planning/notes/familysync-architecture.md` — feed this into the project questionnaire + +## Context to bring into the session + +- Family hub modeled on Skylight. Owner on Fastmail/Android; other members Apple. Wife adoption is + a hard UX constraint (one slick PWA). +- **Calendar**: hosted on Fastmail (NOT self-hosted). Custom app brokers read/write via JMAP/CalDAV + token. Owner native in Fastmail app; Apple members via PWA. +- **Lists + display**: one self-hosted custom app — backend + MariaDB, aggregates calendars into a + Skylight-style view, owns shared lists, serves React PWA (phones + wall-display kiosk). +- **Auth**: Authelia OIDC for the app. +- **Infra**: Unraid + Docker Compose + Pangolin/Newt + split-DNS. MariaDB + Redis. +- **Dropped**: Baikal, Vikunja, DAVx5 (see architecture note for why). +- **Out of scope**: email. **Excluded**: PostgreSQL, App Store/React Native, forking. +- Net: build ONE app on top of existing Fastmail. diff --git a/README b/README new file mode 100644 index 0000000..e69de29