docs: refresh project documentation against current codebase
Publish / publish (push) Successful in 26s
Publish / publish (push) Successful in 26s
This commit is contained in:
+58
-22
@@ -10,7 +10,9 @@ Part of the [FamilySync monorepo](../../README.md).
|
||||
|
||||
- **Calendar broker** — polls Fastmail CalDAV every 5 minutes via `tsdav`; parses iCalendar payloads with `ical.js` and expands recurrence rules with `ical.js`'s `ICAL.RecurExpansion`; writes changes back to Fastmail through an outbox worker
|
||||
- **Collaborative lists** — creates, reorders (fractional indexing), and syncs grocery/gift lists in MariaDB via Drizzle ORM
|
||||
- **OIDC auth** — all `/api/*` routes protected by `@hono/oidc-auth` with authorization-code + PKCE flow against Authelia; `DEV_AUTH_BYPASS=true` skips OIDC for local development
|
||||
- **Auth** — dual-mode: OIDC authorization-code + PKCE flow against Authelia (`@hono/oidc-auth`) for production; local username/password auth (scrypt, JWT session cookie) for no-OIDC or first-boot scenarios. `DEV_AUTH_BYPASS=true` skips both for local development
|
||||
- **Setup wizard** — `/api/setup/*` surface guides first-run configuration of OIDC, VAPID keys, and member credentials before the app is locked
|
||||
- **Admin** — role-gated `/api/admin/*` for member management, credential rotation, and calendar sharing designation
|
||||
- **Live sync** — Server-Sent Events stream list mutations to connected PWA clients in real time
|
||||
- **Push notifications** — web-push (VAPID) delivers reminders for shared timed events to subscribed browsers
|
||||
|
||||
@@ -22,17 +24,27 @@ src/
|
||||
routes/
|
||||
events.ts CalDAV event CRUD endpoints
|
||||
lists.ts List and list-item CRUD endpoints
|
||||
me.ts Authenticated user profile endpoint
|
||||
me.ts Authenticated user profile endpoint + OIDC-link initiation
|
||||
push.ts Push subscription registration
|
||||
sse.ts SSE stream for live list updates
|
||||
health.ts Unauthenticated health check
|
||||
setup.ts First-run setup wizard surface (/api/setup/*)
|
||||
admin.ts Role-gated admin API (members, credentials, calendars)
|
||||
localAuth.ts Local login/logout endpoints (/api/auth/local/*)
|
||||
authMode.ts Pre-auth auth-mode discovery (/api/auth/mode)
|
||||
db/
|
||||
schema.ts Drizzle table definitions (MariaDB/mysql2)
|
||||
client.ts Drizzle client singleton
|
||||
migrations/ SQL migrations generated by drizzle-kit
|
||||
auth/
|
||||
middleware.ts oidcAuthMiddleware + processOAuthCallback
|
||||
middleware.ts oidcAuthMiddleware + processOAuthCallback + oidcConfigFallbackMiddleware
|
||||
devBypass.ts DEV_AUTH_BYPASS passthrough (non-production only)
|
||||
localAuthMiddleware.ts local-session cookie → c.get('user') middleware
|
||||
localCredentials.ts scrypt password hashing and constant-time verification
|
||||
localSession.ts HS256 JWT session-cookie issue / verify / clear helpers
|
||||
linkNonceStore.ts Single-use nonce store for OIDC-link CSRF prevention
|
||||
linkOidc.ts Atomic OIDC-identity binding + local credential removal
|
||||
oidcConfig.ts Centralized OIDC config resolution (env OR app_config)
|
||||
persistSessionCookie.ts Re-issues session cookie as persistent for PWA
|
||||
user.ts User upsert on first login
|
||||
broker/
|
||||
@@ -40,11 +52,12 @@ src/
|
||||
outboxWorker.ts 15-second drain of pending CalDAV writes to Fastmail
|
||||
reminderScheduler.ts 1-minute scan for upcoming shared events → push
|
||||
client.ts tsdav client factory
|
||||
credentialSync.ts Shared validate→encrypt→store→initial-sync helper
|
||||
sync.ts REPORT → ical.js → DB upsert logic
|
||||
write.ts CalDAV PUT/DELETE helpers
|
||||
expand.ts recurrence expansion via ICAL.RecurExpansion
|
||||
expand.ts Recurrence expansion via ICAL.RecurExpansion
|
||||
vevent.ts VEVENT ↔ DB row mapping
|
||||
crypto.ts AES-256-GCM encrypt/decrypt for stored app passwords
|
||||
crypto.ts AES-256-GCM encrypt/decrypt for stored app passwords (APP_PASSWORD_ENCRYPTION_KEY)
|
||||
lib/
|
||||
listEmitter.ts In-process EventEmitter for SSE fan-out
|
||||
listChangeDispatcher.ts Publishes list mutations to listEmitter
|
||||
@@ -53,6 +66,11 @@ src/
|
||||
pushCoalescer.ts Debounces push for rapid successive edits
|
||||
listAccess.ts List permission helpers
|
||||
rank.ts Fractional indexing helpers
|
||||
bootGuards.ts Boot-time env guards (blocks DEV_AUTH_BYPASS in production; enforces LOCAL_SESSION_SECRET)
|
||||
setupGuard.ts isSetupLocked() — prevents re-running the wizard after completion
|
||||
householdTimezone.ts Shared IANA timezone accessor with env fallback
|
||||
outboxTrigger.ts In-process drain signal between routes and outboxWorker
|
||||
requireAdmin.ts DB-enforced admin role middleware
|
||||
```
|
||||
|
||||
## Running in the workspace
|
||||
@@ -107,26 +125,44 @@ Migration files are written to `src/db/migrations/` and checked into source cont
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
| --------------------------- | ------------------- | ---------------------------------------------------------------------- |
|
||||
| `DB_HOST` | Yes | MariaDB host |
|
||||
| `DB_USER` | Yes | MariaDB user |
|
||||
| `DB_PASSWORD` | Yes | MariaDB password |
|
||||
| `DB_NAME` | Yes | MariaDB database name |
|
||||
| `DB_PORT` | No (default `3306`) | MariaDB port |
|
||||
| `OIDC_ISSUER` | Yes (production) | Authelia issuer URL |
|
||||
| `OIDC_CLIENT_ID` | Yes (production) | OIDC client ID |
|
||||
| `OIDC_CLIENT_SECRET` | Yes (production) | OIDC client secret |
|
||||
| `OIDC_AUTH_EXTERNAL_URL` | Yes (production) | External-facing URL for redirect_uri behind Pangolin tunnel |
|
||||
| `VAPID_SUBJECT` | Yes (push) | `mailto:` or `https:` operator identifier |
|
||||
| `VAPID_PUBLIC_KEY` | Yes (push) | VAPID public key |
|
||||
| `VAPID_PRIVATE_KEY` | Yes (push) | VAPID private key |
|
||||
| `CREDENTIAL_ENCRYPTION_KEY` | Yes | AES-256-GCM key for stored Fastmail app passwords |
|
||||
| `DEV_AUTH_BYPASS` | No | Set to `true` (non-production only) to skip OIDC and inject a dev user |
|
||||
| `NODE_ENV` | No | Set to `production` to enforce OIDC unconditionally |
|
||||
| Variable | Required | Description |
|
||||
| ----------------------------- | ------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `DB_HOST` | Yes | MariaDB host |
|
||||
| `DB_USER` | Yes | MariaDB user |
|
||||
| `DB_PASSWORD` | Yes | MariaDB password |
|
||||
| `DB_NAME` | Yes | MariaDB database name |
|
||||
| `DB_PORT` | No (default `3306`) | MariaDB port |
|
||||
| `OIDC_ISSUER` | Yes (production) | Authelia issuer URL |
|
||||
| `OIDC_CLIENT_ID` | Yes (production) | OIDC client ID |
|
||||
| `OIDC_CLIENT_SECRET` | Yes (production) | OIDC client secret |
|
||||
| `OIDC_AUTH_EXTERNAL_URL` | Yes (production) | External-facing URL for redirect_uri behind Pangolin tunnel |
|
||||
| `OIDC_REDIRECT_URI` | No | Explicit redirect URI (overrides the `${OIDC_AUTH_EXTERNAL_URL}/callback` default) |
|
||||
| `VAPID_SUBJECT` | Yes (push) | `mailto:` or `https:` operator identifier |
|
||||
| `VAPID_PUBLIC_KEY` | Yes (push) | VAPID public key |
|
||||
| `VAPID_PRIVATE_KEY` | Yes (push) | VAPID private key |
|
||||
| `APP_PASSWORD_ENCRYPTION_KEY` | Yes | AES-256-GCM key (64-char hex) for stored Fastmail app passwords |
|
||||
| `LOCAL_SESSION_SECRET` | Yes (local auth) | HS256 signing key for local-session JWT cookies (min 32 chars) |
|
||||
| `LOCAL_SESSION_EXPIRES` | No (default `86400`)| Local session lifetime in seconds |
|
||||
| `DEV_AUTH_BYPASS` | No | Set to `true` (non-production only) to skip OIDC and inject a dev user |
|
||||
| `NODE_ENV` | No | Set to `production` to enforce OIDC unconditionally |
|
||||
| `TZ` | No | IANA timezone fallback when household_timezone is not set in app_config |
|
||||
|
||||
> **Note:** `CREDENTIAL_ENCRYPTION_KEY` was renamed to `APP_PASSWORD_ENCRYPTION_KEY`. Update any existing `.env` files if upgrading from an earlier phase.
|
||||
|
||||
See [../../docs/CONFIGURATION.md](../../docs/CONFIGURATION.md) for the full reference.
|
||||
|
||||
## Authentication modes
|
||||
|
||||
The API supports two non-exclusive auth modes, determined at startup:
|
||||
|
||||
| Mode | When active | How it works |
|
||||
| ---- | ----------- | ------------ |
|
||||
| **Local** | Always (default) | `POST /api/auth/local/login` with username + password; issues an HS256 JWT `local-session` cookie. Requires `LOCAL_SESSION_SECRET`. |
|
||||
| **OIDC** | When `OIDC_ISSUER` + `OIDC_CLIENT_ID` are set (env or app_config) | `@hono/oidc-auth` authorization-code + PKCE against Authelia. Local users can upgrade to OIDC via `POST /api/me/link-oidc`. |
|
||||
| **Dev bypass** | `DEV_AUTH_BYPASS=true` in non-production | Skips both guards and injects a synthetic dev user. Blocked in `NODE_ENV=production` by boot guard. |
|
||||
|
||||
`GET /api/auth/mode` returns `{ localEnabled, oidcEnabled }` before authentication — the PWA uses this to decide which login form to show.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests live in `tests/` (integration, route, broker unit) and `test/setup.ts` (global setup/teardown).
|
||||
|
||||
Reference in New Issue
Block a user