Files
familysync/.planning/notes/familysync-architecture.md
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

114 lines
5.3 KiB
Markdown

---
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