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:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
+67 -63
View File
@@ -30,41 +30,41 @@ FamilySync is a self-hosted, Dockerized family organization hub for a two-person
### Core Technologies
| Technology | Version | Purpose | Why Recommended |
|------------|---------|---------|-----------------|
| Node.js + TypeScript | 22 LTS | Backend runtime | First-class typing, same language as frontend, largest CalDAV/OIDC library ecosystem |
| Hono | 4.12.23 | HTTP framework | Web-Standards-native, first-class TypeScript, built-in SSE helper, WebSocket via `@hono/node-server`; lighter than Express and better ergonomics than Fastify for this size |
| Drizzle ORM | 0.45.2 | MariaDB query layer | Type-safe SQL, zero runtime overhead, native `mysql2` driver support, schema-as-code migrations via `drizzle-kit` |
| mysql2 | 3.22.4 | MariaDB driver | The only maintained native MariaDB/MySQL driver; Drizzle targets it explicitly |
| React 19 | 19.x | PWA frontend | Required by project; concurrent features, stable |
| Vite | 8.0.x | Build tooling | De-facto standard for React PWAs; fast HMR, native ESM |
| vite-plugin-pwa | 1.3.0 | Service worker + manifest | Zero-config Workbox integration, handles install prompt, offline cache, background sync scaffolding |
| Technology | Version | Purpose | Why Recommended |
| -------------------- | ------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Node.js + TypeScript | 22 LTS | Backend runtime | First-class typing, same language as frontend, largest CalDAV/OIDC library ecosystem |
| Hono | 4.12.23 | HTTP framework | Web-Standards-native, first-class TypeScript, built-in SSE helper, WebSocket via `@hono/node-server`; lighter than Express and better ergonomics than Fastify for this size |
| Drizzle ORM | 0.45.2 | MariaDB query layer | Type-safe SQL, zero runtime overhead, native `mysql2` driver support, schema-as-code migrations via `drizzle-kit` |
| mysql2 | 3.22.4 | MariaDB driver | The only maintained native MariaDB/MySQL driver; Drizzle targets it explicitly |
| React 19 | 19.x | PWA frontend | Required by project; concurrent features, stable |
| Vite | 8.0.x | Build tooling | De-facto standard for React PWAs; fast HMR, native ESM |
| vite-plugin-pwa | 1.3.0 | Service worker + manifest | Zero-config Workbox integration, handles install prompt, offline cache, background sync scaffolding |
### Supporting Libraries
| Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------|
| tsdav | 2.2.2 | CalDAV client for Node.js | All calendar reads and writes against Fastmail CalDAV endpoint; handles PROPFIND, REPORT, PUT, DELETE |
| ical.js | 2.2.1 | iCalendar (.ics) parsing | Parse raw VCALENDAR/VEVENT payloads returned by tsdav; handles VTIMEZONE, RDATE, EXDATE |
| rrule | 2.8.1 | Recurrence rule expansion | Expand RRULE strings into concrete event occurrences for the calendar view; ical.js's built-in expansion is less ergonomic for UI consumption |
| web-push | 3.6.7 | Server-side VAPID push | Generate VAPID keys, sign and dispatch push messages to browser push services (APNs for iOS, FCM for Android) |
| @hono/oidc-auth | 1.8.3 | OIDC session middleware for Hono | Storage-less JWT session cookies; authorization-code + PKCE flow; works with any RFC-compliant OIDC provider including Authelia |
| openid-client | 6.8.4 | Low-level OIDC primitives | If `@hono/oidc-auth` proves insufficient (e.g., custom token introspection), use this as the lower-level escape hatch |
| ioredis | 5.11.0 | Redis client | Pub/sub for broadcasting list-change events to SSE connections across Node processes |
| zod | 3.24.x | Schema validation | Validate API request bodies and CalDAV event payloads before writing back to Fastmail |
| @hono/zod-validator | 0.8.0 | Hono middleware for Zod | Validate request body/query in route handlers with Zod schemas |
| @tanstack/react-query | 5.101.0 | Server state + caching | Manages calendar and list data fetching, background refetch, stale-while-revalidate; pairs with SSE for live list updates |
| zustand | 5.0.14 | Client state | UI-only state (selected date range, color assignments, drawer open/closed); keep server state in React Query |
| drizzle-kit | 0.31.10 | Schema migrations | Generates and runs MariaDB migrations from Drizzle schema definitions |
| Library | Version | Purpose | When to Use |
| --------------------- | ------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| tsdav | 2.2.2 | CalDAV client for Node.js | All calendar reads and writes against Fastmail CalDAV endpoint; handles PROPFIND, REPORT, PUT, DELETE |
| ical.js | 2.2.1 | iCalendar (.ics) parsing | Parse raw VCALENDAR/VEVENT payloads returned by tsdav; handles VTIMEZONE, RDATE, EXDATE |
| rrule | 2.8.1 | Recurrence rule expansion | Expand RRULE strings into concrete event occurrences for the calendar view; ical.js's built-in expansion is less ergonomic for UI consumption |
| web-push | 3.6.7 | Server-side VAPID push | Generate VAPID keys, sign and dispatch push messages to browser push services (APNs for iOS, FCM for Android) |
| @hono/oidc-auth | 1.8.3 | OIDC session middleware for Hono | Storage-less JWT session cookies; authorization-code + PKCE flow; works with any RFC-compliant OIDC provider including Authelia |
| openid-client | 6.8.4 | Low-level OIDC primitives | If `@hono/oidc-auth` proves insufficient (e.g., custom token introspection), use this as the lower-level escape hatch |
| ioredis | 5.11.0 | Redis client | Pub/sub for broadcasting list-change events to SSE connections across Node processes |
| zod | 3.24.x | Schema validation | Validate API request bodies and CalDAV event payloads before writing back to Fastmail |
| @hono/zod-validator | 0.8.0 | Hono middleware for Zod | Validate request body/query in route handlers with Zod schemas |
| @tanstack/react-query | 5.101.0 | Server state + caching | Manages calendar and list data fetching, background refetch, stale-while-revalidate; pairs with SSE for live list updates |
| zustand | 5.0.14 | Client state | UI-only state (selected date range, color assignments, drawer open/closed); keep server state in React Query |
| drizzle-kit | 0.31.10 | Schema migrations | Generates and runs MariaDB migrations from Drizzle schema definitions |
### Development Tools
| Tool | Purpose | Notes |
|------|---------|-------|
| TypeScript 5.x | Strict typing across backend + frontend | `strict: true`; share types between packages via a `packages/shared` workspace |
| ESLint + Prettier | Lint + format | Standard config; no bikeshedding needed |
| Docker Compose | Local dev + production parity | Match Unraid stack exactly in dev |
| Vitest | Unit + integration tests | Vite-native, same config as frontend |
| Tool | Purpose | Notes |
| ----------------- | --------------------------------------- | ------------------------------------------------------------------------------ |
| TypeScript 5.x | Strict typing across backend + frontend | `strict: true`; share types between packages via a `packages/shared` workspace |
| ESLint + Prettier | Lint + format | Standard config; no bikeshedding needed |
| Docker Compose | Local dev + production parity | Match Unraid stack exactly in dev |
| Vitest | Unit + integration tests | Vite-native, same config as frontend |
## Installation
@@ -101,14 +101,14 @@ FamilySync is a self-hosted, Dockerized family organization hub for a two-person
- TanStack Query owns all server-side state: calendar events, lists, user profile. It handles background refetch, cache invalidation, and loading states. Use `queryClient.invalidateQueries` from SSE event handlers to keep list data live.
- Zustand owns pure UI state: selected month, color assignments per calendar, drawer states. Do not put server data in Zustand.
| Requirement | Detail |
|-------------|--------|
| Minimum iOS version | 16.4 — push is silently unavailable on earlier versions |
| Installation required | PWA **must** be added to Home Screen; push does not work from Safari browser tabs |
| User gesture | `pushManager.subscribe()` must be called inside a tap handler, not on page load |
| Requirement | Detail |
| --------------------- | -------------------------------------------------------------------------------------- |
| Minimum iOS version | 16.4 — push is silently unavailable on earlier versions |
| Installation required | PWA **must** be added to Home Screen; push does not work from Safari browser tabs |
| User gesture | `pushManager.subscribe()` must be called inside a tap handler, not on page load |
| EU users on iOS 17.4+ | PWAs may open in Safari tabs instead of standalone mode due to DMA; affects push reach |
| Silent push | Not supported on iOS; all push messages must display a visible notification |
| Background sync | Not supported on iOS; no `BackgroundSync` or `PeriodicBackgroundSync` |
| Silent push | Not supported on iOS; all push messages must display a visible notification |
| Background sync | Not supported on iOS; no `BackgroundSync` or `PeriodicBackgroundSync` |
## Authelia OIDC Integration
@@ -121,39 +121,39 @@ FamilySync is a self-hosted, Dockerized family organization hub for a two-person
## Alternatives Considered
| Recommended | Alternative | Why Not |
|-------------|-------------|---------|
| Hono | Express | No native TypeScript ergonomics; no built-in SSE; larger ecosystem but more boilerplate |
| Hono | Fastify | Good choice but heavier plugin model; Hono's Web Standards alignment is better for this size |
| Drizzle | Prisma | Binary engine complicates Docker; weaker explicit MariaDB support; heavier |
| tsdav | Raw fetch + xml2js | CalDAV XML namespace handling is tedious; tsdav is the established TypeScript CalDAV client |
| ical.js | node-ical | node-ical is a fork that has diverged; ical.js is the Mozilla-maintained reference implementation |
| @hono/oidc-auth | express-openid-connect | express-openid-connect is Express-specific; Hono middleware is the correct fit |
| SSE | WebSockets | WebSockets are bidirectional; list sync is server→client only; SSE is simpler and proxy-friendly |
| CalDAV | JMAP | JMAP calendars not available on Fastmail as of 2026 |
| Recommended | Alternative | Why Not |
| --------------- | ---------------------- | ------------------------------------------------------------------------------------------------- |
| Hono | Express | No native TypeScript ergonomics; no built-in SSE; larger ecosystem but more boilerplate |
| Hono | Fastify | Good choice but heavier plugin model; Hono's Web Standards alignment is better for this size |
| Drizzle | Prisma | Binary engine complicates Docker; weaker explicit MariaDB support; heavier |
| tsdav | Raw fetch + xml2js | CalDAV XML namespace handling is tedious; tsdav is the established TypeScript CalDAV client |
| ical.js | node-ical | node-ical is a fork that has diverged; ical.js is the Mozilla-maintained reference implementation |
| @hono/oidc-auth | express-openid-connect | express-openid-connect is Express-specific; Hono middleware is the correct fit |
| SSE | WebSockets | WebSockets are bidirectional; list sync is server→client only; SSE is simpler and proxy-friendly |
| CalDAV | JMAP | JMAP calendars not available on Fastmail as of 2026 |
## What NOT to Use
| Avoid | Why | Use Instead |
|-------|-----|-------------|
| JMAP for calendars | Not implemented by Fastmail; spec not finalized | CalDAV via tsdav |
| Prisma | Binary engine, weaker MariaDB compat, larger footprint in Docker | Drizzle ORM |
| oidc-client-ts | Browser-side OIDC library; wrong layer for a backend-session app | @hono/oidc-auth |
| node-ical | Older fork of ical.js, less maintained, weaker RRULE handling | ical.js |
| Create React App | Deprecated February 2025 | Vite |
| PostgreSQL | Not in the Unraid stack; hard constraint | MariaDB |
| NestJS | Massive framework overhead for a two-user household app | Hono |
| Firebase/FCM as push broker | Third-party dependency; VAPID direct push works without it | web-push (VAPID) |
| Avoid | Why | Use Instead |
| --------------------------- | ---------------------------------------------------------------- | ---------------- |
| JMAP for calendars | Not implemented by Fastmail; spec not finalized | CalDAV via tsdav |
| Prisma | Binary engine, weaker MariaDB compat, larger footprint in Docker | Drizzle ORM |
| oidc-client-ts | Browser-side OIDC library; wrong layer for a backend-session app | @hono/oidc-auth |
| node-ical | Older fork of ical.js, less maintained, weaker RRULE handling | ical.js |
| Create React App | Deprecated February 2025 | Vite |
| PostgreSQL | Not in the Unraid stack; hard constraint | MariaDB |
| NestJS | Massive framework overhead for a two-user household app | Hono |
| Firebase/FCM as push broker | Third-party dependency; VAPID direct push works without it | web-push (VAPID) |
## Version Compatibility
| Package | Compatible With | Notes |
|---------|-----------------|-------|
| drizzle-orm@0.45.x | mysql2@3.x | Use `drizzle-orm/mysql2` import path; mysql2@3.x uses Promises API by default |
| vite-plugin-pwa@1.3.x | Vite@8.x, Workbox@7.x | vite-plugin-pwa 0.16+ requires Node 16+; 1.x tracks Vite 6+ |
| @hono/oidc-auth@1.8.x | hono@4.x, oauth4webapi | Peer-depends on hono 4.x |
| ical.js@2.x | rrule@2.8.x | Use together: ical.js parses the RRULE string, pass to `new RRule(RRule.parseString(...))` |
| web-push@3.6.x | Node.js 18+ | VAPID uses Web Crypto; works in Node.js 18+ natively |
| Package | Compatible With | Notes |
| --------------------- | ---------------------- | ------------------------------------------------------------------------------------------ |
| drizzle-orm@0.45.x | mysql2@3.x | Use `drizzle-orm/mysql2` import path; mysql2@3.x uses Promises API by default |
| vite-plugin-pwa@1.3.x | Vite@8.x, Workbox@7.x | vite-plugin-pwa 0.16+ requires Node 16+; 1.x tracks Vite 6+ |
| @hono/oidc-auth@1.8.x | hono@4.x, oauth4webapi | Peer-depends on hono 4.x |
| ical.js@2.x | rrule@2.8.x | Use together: ical.js parses the RRULE string, pass to `new RRule(RRule.parseString(...))` |
| web-push@3.6.x | Node.js 18+ | VAPID uses Web Crypto; works in Node.js 18+ natively |
## Open Questions Flagged for Phase Research
@@ -193,6 +193,7 @@ FamilySync is a self-hosted, Dockerized family organization hub for a two-person
## Architecture
Architecture not yet mapped. Follow existing patterns found in the codebase.
<!-- GSD:architecture-end -->
<!-- GSD:skills-start source:skills/ -->
@@ -200,6 +201,7 @@ Architecture not yet mapped. Follow existing patterns found in the codebase.
## Project Skills
No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, `.github/skills/`, or `.codex/skills/` with a `SKILL.md` index file.
<!-- GSD:skills-end -->
<!-- GSD:workflow-start source:GSD defaults -->
@@ -215,6 +217,7 @@ Use these entry points:
- `/gsd-execute-phase` for planned phase work
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
<!-- GSD:workflow-end -->
<!-- GSD:profile-start -->
@@ -223,4 +226,5 @@ Do not make direct repo edits outside a GSD workflow unless the user explicitly
> Profile not yet configured. Run `/gsd-profile-user` to generate your developer profile.
> This section is managed by `generate-claude-profile` -- do not edit manually.
<!-- GSD:profile-end -->