128 lines
4.4 KiB
Markdown
128 lines
4.4 KiB
Markdown
<!-- generated-by: gsd-doc-writer -->
|
|
# FamilySync
|
|
|
|
A self-hosted family organization hub for a two-person household. One color-coded calendar view across all family members' Fastmail calendars, plus shared collaborative lists (groceries, gift ideas) — delivered as a React PWA with no app store required.
|
|
|
|
## What It Does
|
|
|
|
- **Unified calendar** — aggregates each member's Fastmail CalDAV calendars into a single color-coded view via tsdav + ical.js
|
|
- **Shared lists** — collaborative grocery and gift-idea lists with live sync via Server-Sent Events
|
|
- **PWA** — installable on iOS (Home Screen) and Android; push notifications via VAPID
|
|
- **Single sign-on** — all auth flows through your existing Authelia OIDC deployment
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 22 LTS
|
|
- pnpm 11.5.1 (`corepack enable pnpm`)
|
|
- Docker + Docker Compose (for MariaDB, Redis, and production deployment)
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
git clone <repo-url> familysync
|
|
cd familysync
|
|
pnpm install
|
|
```
|
|
|
|
Copy the environment template and fill in values:
|
|
|
|
```bash
|
|
cp .env.example .env # then fill in values — see Environment Variables below
|
|
```
|
|
|
|
Required environment variables (set in `.env` or your Docker host):
|
|
|
|
| Variable | Description |
|
|
|---|---|
|
|
| `DB_PASSWORD` | MariaDB password for the `familysync` user |
|
|
| `DB_ROOT_PASSWORD` | MariaDB root password |
|
|
| `OIDC_ISSUER` | Authelia OIDC issuer URL |
|
|
| `OIDC_CLIENT_ID` | OIDC client ID (default: `familysync`) |
|
|
| `OIDC_CLIENT_SECRET` | OIDC client secret |
|
|
| `OIDC_REDIRECT_URI` | Callback URL registered in Authelia |
|
|
| `OIDC_AUTH_SECRET` | Random secret for session cookie signing |
|
|
| `APP_PASSWORD_ENCRYPTION_KEY` | Key used to encrypt stored Fastmail app passwords |
|
|
| `VAPID_PUBLIC_KEY` | VAPID public key (`npx web-push generate-vapid-keys --json`) |
|
|
| `VAPID_PRIVATE_KEY` | VAPID private key (never commit) |
|
|
| `VAPID_SUBJECT` | VAPID subject (`mailto:you@example.com`) |
|
|
|
|
## Quick Start
|
|
|
|
**Development (with hot-reload API and Vite HMR):**
|
|
|
|
```bash
|
|
# Start backing services
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml up mariadb redis
|
|
|
|
# Run migrations
|
|
pnpm --filter @familysync/api db:migrate
|
|
|
|
# Start API (in one terminal)
|
|
pnpm dev:api
|
|
|
|
# Start PWA (in another terminal)
|
|
pnpm dev:pwa
|
|
```
|
|
|
|
**Production (Docker Compose):**
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
The API listens on port 3000. The PWA build is served separately (Vite `preview` or a static host in front of the API container).
|
|
|
|
## Monorepo Structure
|
|
|
|
```
|
|
apps/
|
|
api/ Hono backend — CalDAV sync, OIDC auth, lists API, push notifications
|
|
pwa/ React 19 PWA — calendar view, lists UI, service worker
|
|
docker-compose.yml Production services (API, MariaDB 11, Redis 7)
|
|
docker-compose.dev.yml Dev overrides (bind-mount src/, expose DB/Redis ports)
|
|
```
|
|
|
|
## Commands
|
|
|
|
| Command | What it does |
|
|
|---|---|
|
|
| `pnpm dev:api` | Start API in watch mode (`dist/` must be built first) |
|
|
| `pnpm dev:pwa` | Start Vite dev server with HMR |
|
|
| `pnpm build` | Build both api and pwa |
|
|
| `pnpm test` | Run API test suite (vitest) |
|
|
| `pnpm lint` | Lint all workspaces |
|
|
| `pnpm typecheck` | Type-check all workspaces |
|
|
| `pnpm --filter @familysync/api db:generate` | Generate Drizzle migration from schema changes |
|
|
| `pnpm --filter @familysync/api db:migrate` | Apply pending migrations to MariaDB |
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|---|---|
|
|
| Backend runtime | Node.js 22 + TypeScript, Hono 4.12.23 |
|
|
| Database ORM | Drizzle ORM 0.45.2 on MariaDB 11 (via mysql2) |
|
|
| Auth | `@hono/oidc-auth` 1.8.3 — authorization code + PKCE against Authelia |
|
|
| Calendar | tsdav 2.2.2 (CalDAV) + ical.js 2.2.1 against Fastmail |
|
|
| Push | web-push 3.6.7 (VAPID) |
|
|
| Live sync | Server-Sent Events + Redis 7 pub/sub |
|
|
| Frontend | React 19, Vite 8, vite-plugin-pwa 1.3, TanStack Query 5, Zustand 5 |
|
|
| Calendar UI | Schedule-X 4.6 |
|
|
|
|
## Calendar Integration
|
|
|
|
FamilySync reads and writes calendars via CalDAV against Fastmail — not JMAP (not available for Fastmail calendars). Configure your Fastmail app password under the "Mail, Contacts & Calendars" scope. The principal URL follows the pattern:
|
|
|
|
```
|
|
https://caldav.fastmail.com/dav/principals/user/<your-fastmail-address>/
|
|
```
|
|
|
|
Store the app password in the database via the `/me` endpoint after first login.
|
|
|
|
## Deployment
|
|
|
|
See [`docs/deployment.md`](docs/deployment.md) for Unraid/Docker Compose deployment notes including the Pangolin/Newt tunnel configuration.
|
|
|
|
## License
|
|
|
|
Private — not open source.
|