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.
This commit is contained in:
@@ -9,23 +9,23 @@ A member reaches the app over the real Pangolin tunnel, authenticates through Au
|
||||
|
||||
## Architectural Decisions
|
||||
|
||||
| Decision | Choice | Rationale |
|
||||
|---|---|---|
|
||||
| Monorepo | pnpm workspace, `apps/api` + `apps/pwa` | Shared TypeScript, single repo; matches RESEARCH recommended structure |
|
||||
| Backend framework | Hono 4.12.23 on Node 22 (@hono/node-server) | Locked in CLAUDE.md; Web-Standards-native, built-in streamSSE, RPC type sharing |
|
||||
| Data layer | MariaDB 11 + Drizzle ORM 0.45.2 via mysql2 3.22.4 | Locked stack; no PostgreSQL; type-safe SQL, no binary engine (vs Prisma) |
|
||||
| Schema apply | `drizzle-kit push` against live MariaDB | Greenfield Phase 1; push is the [BLOCKING] gate before verification (Drizzle types come from schema.ts, not the live DB) |
|
||||
| Auth | Authelia OIDC via @hono/oidc-auth 1.8.3 (authorization-code + PKCE S256, client_secret_basic) | Authelia already deployed; backend confidential client holds refresh token (D-12), no iframe |
|
||||
| Identity | `oidc_iss + oidc_sub` composite key, never email | D-10 — email is mutable in Authelia |
|
||||
| Member color | Auto-assigned round-robin from a curated accessible palette, persisted on the user row | D-06 — stable across sessions, no settings UI in v1 |
|
||||
| Calendar access | CalDAV via tsdav 2.2.2; per-member Fastmail app passwords | D-02/D-09 — JMAP unavailable on Fastmail; per-member app passwords eliminate cross-account ACL risk |
|
||||
| Credential storage | AES-256-GCM (node:crypto), key from `APP_PASSWORD_ENCRYPTION_KEY` env, backend-only | D-04 — encrypted at rest, never exposed to frontend |
|
||||
| Calendar cache | `calendar_events`: raw VEVENT blob + `dtstart_utc` (timed) / `dtstart_date` (all-day) split; ctag/sync-token polling | D-13 — all-day never coerced to DATETIME (Pitfall 3); cache-first reads |
|
||||
| Background sync | node-cron 4 every 5 min, ctag change detection | RESEARCH poller pattern; sync-token with ctag fallback from day one |
|
||||
| Real-time transport | SSE (`streamSSE`); WebSocket rejected | Pangolin WS upgrade known-broken (issue #1034); SSE smoke-tested in Phase 1 to de-risk Phase 4 |
|
||||
| Frontend | Vite 8 + React 19; TanStack Query (server state) + Zustand (UI state) | Locked stack; React Query owns server data, Zustand UI-only |
|
||||
| Deployment target | Docker Compose on Unraid, public via Pangolin/Newt tunnel (same parent domain as Authelia) | D-07 — validate real OIDC/HTTPS/cookie topology from day one |
|
||||
| Directory layout | `apps/api/src/{auth,broker,db,routes}`; broker is a hard module boundary | RESEARCH structure; only `broker/` imports tsdav + Fastmail credentials |
|
||||
| Decision | Choice | Rationale |
|
||||
| ------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Monorepo | pnpm workspace, `apps/api` + `apps/pwa` | Shared TypeScript, single repo; matches RESEARCH recommended structure |
|
||||
| Backend framework | Hono 4.12.23 on Node 22 (@hono/node-server) | Locked in CLAUDE.md; Web-Standards-native, built-in streamSSE, RPC type sharing |
|
||||
| Data layer | MariaDB 11 + Drizzle ORM 0.45.2 via mysql2 3.22.4 | Locked stack; no PostgreSQL; type-safe SQL, no binary engine (vs Prisma) |
|
||||
| Schema apply | `drizzle-kit push` against live MariaDB | Greenfield Phase 1; push is the [BLOCKING] gate before verification (Drizzle types come from schema.ts, not the live DB) |
|
||||
| Auth | Authelia OIDC via @hono/oidc-auth 1.8.3 (authorization-code + PKCE S256, client_secret_basic) | Authelia already deployed; backend confidential client holds refresh token (D-12), no iframe |
|
||||
| Identity | `oidc_iss + oidc_sub` composite key, never email | D-10 — email is mutable in Authelia |
|
||||
| Member color | Auto-assigned round-robin from a curated accessible palette, persisted on the user row | D-06 — stable across sessions, no settings UI in v1 |
|
||||
| Calendar access | CalDAV via tsdav 2.2.2; per-member Fastmail app passwords | D-02/D-09 — JMAP unavailable on Fastmail; per-member app passwords eliminate cross-account ACL risk |
|
||||
| Credential storage | AES-256-GCM (node:crypto), key from `APP_PASSWORD_ENCRYPTION_KEY` env, backend-only | D-04 — encrypted at rest, never exposed to frontend |
|
||||
| Calendar cache | `calendar_events`: raw VEVENT blob + `dtstart_utc` (timed) / `dtstart_date` (all-day) split; ctag/sync-token polling | D-13 — all-day never coerced to DATETIME (Pitfall 3); cache-first reads |
|
||||
| Background sync | node-cron 4 every 5 min, ctag change detection | RESEARCH poller pattern; sync-token with ctag fallback from day one |
|
||||
| Real-time transport | SSE (`streamSSE`); WebSocket rejected | Pangolin WS upgrade known-broken (issue #1034); SSE smoke-tested in Phase 1 to de-risk Phase 4 |
|
||||
| Frontend | Vite 8 + React 19; TanStack Query (server state) + Zustand (UI state) | Locked stack; React Query owns server data, Zustand UI-only |
|
||||
| Deployment target | Docker Compose on Unraid, public via Pangolin/Newt tunnel (same parent domain as Authelia) | D-07 — validate real OIDC/HTTPS/cookie topology from day one |
|
||||
| Directory layout | `apps/api/src/{auth,broker,db,routes}`; broker is a hard module boundary | RESEARCH structure; only `broker/` imports tsdav + Fastmail credentials |
|
||||
|
||||
## Stack Touched in Phase 1
|
||||
|
||||
@@ -41,7 +41,7 @@ A member reaches the app over the real Pangolin tunnel, authenticates through Au
|
||||
- Wife's app password onboarding flow + her credential — Phase 2 (encrypted credential table built now to support it)
|
||||
- Event write-back (create/edit/delete) to Fastmail — Phase 3
|
||||
- PWA manifest + service worker + guided iOS install — Phase 3
|
||||
- Shared lists + live SSE co-edit sync (the SSE *transport* is only smoke-tested here) — Phase 4
|
||||
- Shared lists + live SSE co-edit sync (the SSE _transport_ is only smoke-tested here) — Phase 4
|
||||
- Web Push notifications (VAPID) — Phase 5
|
||||
- User-pickable color picker (settings UI) — deferred, v1.x
|
||||
- Single-occurrence recurring edits — never in v1
|
||||
|
||||
Reference in New Issue
Block a user