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

5.3 KiB

title, date, context
title date context
FamilySync Architecture Decisions 2026-06-02 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