Files
familysync/.planning/codebase/STRUCTURE.md
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

19 KiB

Codebase Structure

Analysis Date: 2026-06-09

Directory Layout

familysync/
├── apps/
│   ├── api/
│   │   ├── src/
│   │   │   ├── index.ts                     # Hono app + HTTP server + broker startup
│   │   │   ├── auth/
│   │   │   │   ├── middleware.ts            # OIDC guard via @hono/oidc-auth
│   │   │   │   ├── user.ts                  # Identity upsert + color assignment
│   │   │   │   └── devBypass.ts             # DEV_AUTH_BYPASS middleware (local dev)
│   │   │   ├── db/
│   │   │   │   ├── client.ts                # mysql2 + Drizzle instance
│   │   │   │   ├── schema.ts                # Drizzle table definitions
│   │   │   │   └── migrations/              # drizzle-kit migration files
│   │   │   ├── routes/
│   │   │   │   ├── events.ts                # GET /api/events (windowed), POST/PATCH/DELETE (enqueue)
│   │   │   │   ├── me.ts                    # GET /api/me (current user)
│   │   │   │   ├── health.ts                # GET /health (unauthenticated)
│   │   │   │   └── sse.ts                   # GET /api/sse/heartbeat (SSE test)
│   │   │   └── broker/
│   │   │       ├── poller.ts                # 5-min cron: PROPFIND → ctag detect
│   │   │       ├── sync.ts                  # REPORT → ical.js → upsert (per-calendar)
│   │   │       ├── outboxWorker.ts          # 15-sec cron: drain pending writes to Fastmail
│   │   │       ├── write.ts                 # PUT/DELETE builders for tsdav
│   │   │       ├── expand.ts                # Server-side RRULE expansion
│   │   │       ├── vevent.ts                # VEVENT builder + RRULE extraction
│   │   │       ├── client.ts                # tsdav client factory
│   │   │       ├── crypto.ts                # AES-256-GCM encrypt/decrypt
│   │   │       └── spike.ts                 # Proof-of-concept (unused, historical)
│   │   ├── tests/
│   │   │   ├── routes/                      # Unit tests for route handlers
│   │   │   ├── broker/                      # Unit tests for broker modules
│   │   │   ├── auth/                        # Unit tests for auth
│   │   │   ├── fixtures/                    # Test data factories
│   │   │   └── helpers/                     # Test utilities (mock db, etc.)
│   │   ├── package.json                     # Backend dependencies
│   │   ├── tsconfig.json                    # TypeScript config (strict mode)
│   │   └── dist/                            # Compiled JavaScript (gitignored)
│   └── pwa/
│       ├── src/
│       │   ├── main.tsx                     # Vite entry point
│       │   ├── App.tsx                      # Root component (CalendarShell)
│       │   ├── components/
│       │   │   ├── CalendarShell.tsx        # Schedule-X wiring + TanStack Query + Zustand
│       │   │   ├── AppNav.tsx               # Header/sidebar navigation
│       │   │   ├── EventDetailPopover.tsx   # Event detail display + edit/delete actions
│       │   │   ├── EventForm.tsx            # Create/edit event modal
│       │   │   ├── DeleteConfirmationDialog.tsx # Delete confirm modal
│       │   │   ├── SyncStateToast.tsx       # Write-back status toast
│       │   │   ├── ColorLegend.tsx          # Calendar color legend
│       │   │   ├── InstallPrompt.tsx        # PWA install prompt
│       │   │   ├── SkeletonCalendar.tsx     # Loading skeleton
│       │   │   ├── ErrorBoundary.tsx        # Error boundary wrapper
│       │   │   └── *.test.tsx               # Component tests
│       │   ├── api/
│       │   │   ├── client.ts                # Typed fetch wrappers (fetchMe, fetchEvents, fetchCreateEvent, etc.)
│       │   │   └── client.test.ts           # API client tests
│       │   ├── store/
│       │   │   └── calendarStore.ts         # Zustand UI-state store
│       │   ├── lib/
│       │   │   ├── hydrateEvents.ts         # Occurrence[] → Schedule-X CalendarType[]
│       │   │   ├── calendarConfig.ts        # Schedule-X config builder
│       │   │   ├── colorUtils.ts            # Hex color utilities
│       │   │   ├── eventDateTime.ts         # Date/time formatting + parsing
│       │   │   ├── loginRedirect.ts         # OIDC redirect handler (maybeRedirectToLogin)
│       │   │   └── *.test.ts                # Utility tests
│       │   └── styles/
│       │       └── tokens.ts                # CSS-in-JS design tokens (colors, spacing)
│       ├── public/
│       │   ├── index.html                   # PWA shell HTML
│       │   ├── manifest.webmanifest         # PWA metadata
│       │   ├── sw.js                        # Service worker entry (generated by vite-plugin-pwa)
│       │   ├── icon-192.png                 # PWA icon (192x192)
│       │   └── icon-512.png                 # PWA icon (512x512)
│       ├── package.json                     # Frontend dependencies
│       ├── tsconfig.json                    # TypeScript config
│       ├── vite.config.ts                   # Vite + vite-plugin-pwa configuration
│       └── dist/                            # Built PWA (gitignored)
├── packages/
│   └── shared/                              # Shared types (currently placeholder)
├── package.json                             # Monorepo root (pnpm workspaces)
├── pnpm-lock.yaml                          # Dependency lock file
└── .planning/
    └── codebase/                            # This document

Directory Purposes

apps/api/src/ — Backend HTTP server and background broker

  • Routes respond to client requests (GET reads cache only; POST/PATCH/DELETE enqueue outbox)
  • Broker runs background jobs (poller syncs with Fastmail; outbox worker drains writes)
  • Auth handles OIDC session + user identity upsert
  • DB defines schema and provides Drizzle ORM client

apps/pwa/src/ — React PWA frontend

  • Components render UI and handle user interactions
  • API wraps typed fetch calls to backend endpoints
  • Store owns UI-only state (view selection, modal open/close) via Zustand
  • Lib provides utilities for date handling, color assignment, event hydration, login redirect
  • Public contains PWA manifest, service worker config, and static assets
  • Styles defines design tokens (colors, spacing, typography)

apps/api/tests/ — Unit tests for backend

  • Routes test endpoint validation, authorization, DB queries
  • Broker test CalDAV sync logic, RRULE expansion, outbox draining
  • Auth test user upsert, color assignment, OIDC claim handling
  • Fixtures provide test data factories (mock users, credentials, events)
  • Helpers provide test utilities (mock Drizzle, mock tsdav clients)

packages/shared/ — Shared types (future expansion for N-member)

  • Currently a placeholder; will contain cross-app TypeScript interfaces when multi-member features need shared definitions

Key File Locations

Entry Points:

File Purpose
apps/api/src/index.ts Hono app definition, middleware stack, route registration, broker startup
apps/pwa/src/main.tsx Vite entry point; React.createRoot, hydrate App
apps/pwa/src/App.tsx Root component; renders CalendarShell

Configuration:

File Purpose
apps/api/package.json Backend dependencies (Hono, Drizzle, tsdav, ical.js, rrule, node-cron, zod, @hono/zod-validator, @hono/oidc-auth, mysql2)
apps/pwa/package.json Frontend dependencies (React 19, Vite, @tanstack/react-query, Zustand, @schedule-x/react, lucide-react, etc.)
apps/api/tsconfig.json strict: true; lib: es2022; module: es2022
apps/pwa/tsconfig.json strict: true; jsx: react-jsx; lib: es2022, dom
apps/pwa/vite.config.ts Vite plugins (react, VitePWA); dev proxy to :3000; PWA manifest config

Core Logic:

File Purpose
apps/api/src/db/schema.ts Drizzle table definitions (users, member_credentials, calendars, calendar_events, calendar_outbox)
apps/api/src/routes/events.ts GET /api/events (windowed + expanded), write endpoints (POST/PATCH/DELETE), sync-status polling, writable-calendars
apps/api/src/broker/poller.ts 5-min background job; PROPFIND → ctag change detection
apps/api/src/broker/sync.ts REPORT → ical.js parse → calendar_events upsert; prune deletes
apps/api/src/broker/outboxWorker.ts 15-sec drain pending outbox rows; PUT/DELETE to Fastmail; exponential backoff
apps/api/src/broker/expand.ts ical.js RecurExpansion; emit concrete occurrences (with VTIMEZONE + RRULE handled)
apps/pwa/src/components/CalendarShell.tsx TanStack Query (events, me), Zustand (range, view), Schedule-X wiring
apps/pwa/src/store/calendarStore.ts Zustand store; selectedView, openEventId, calendarRange, eventFormOpen, deleteDialogOpen
apps/pwa/src/api/client.ts Typed fetch wrappers; MeResponse, CalendarOccurrence, CreateEventPayload interfaces
apps/pwa/src/lib/hydrateEvents.ts Occurrence[] → Schedule-X CalendarEvent[] with Temporal.ZonedDateTime conversion

Testing:

File Purpose
apps/api/tests/routes/events.test.ts Unit tests for route handlers (validation, ownership checks, SQL correctness)
apps/api/tests/broker/expand.test.ts Unit tests for RRULE expansion (VTIMEZONE, EXDATE, DST)
apps/pwa/src/components/CalendarShell.test.tsx Component integration test; mocked React Query + Zustand
apps/pwa/src/lib/hydrateEvents.test.ts Unit tests for Temporal conversion logic

Naming Conventions

Files:

Pattern Example Where
Kebab-case for route/route groups events.ts, health.ts apps/api/src/routes/
Kebab-case for modules poller.ts, sync.ts, outbox-worker.ts (or camelCase outboxWorker.ts) apps/api/src/broker/
PascalCase for React components CalendarShell.tsx, EventDetailPopover.tsx apps/pwa/src/components/
Kebab-case for utility functions hydrateEvents.ts, colorUtils.ts apps/pwa/src/lib/
.test.ts / .test.tsx for tests events.test.ts, CalendarShell.test.tsx Colocated with source

Functions:

Pattern Example
camelCase for functions fetchEvents, expandOccurrences, upsertUser, syncCalendar
PascalCase for React components CalendarShell, EventForm, SyncStateToast
UPPER_CASE for module-level constants MAX_WINDOW_DAYS, COLOR_PALETTE, TRANSIENT_STATUSES
Leading $ for Drizzle special methods .$returningId(), .onDuplicateKeyUpdate()

Variables:

Pattern Example
camelCase for variables currentUserId, calendarRange, eventsQuery
is/has prefix for booleans isShared, hasRrule, eventFormOpen
Trailing Id for foreign keys userId, calendarId, groupId
Descriptive names for arrays seenUids, usedColors, occurrences

Types:

Pattern Example
PascalCase for interfaces CalendarOccurrence, MeResponse, CreateEventPayload
PascalCase for type aliases RecurrencePreset, BreakpointGroup
Trailing Schema for Zod/validation eventsQuerySchema, eventFieldsSchema
Trailing Response for API responses MeResponse, OccurrencesResponse

Where to Add New Code

New Feature:

Feature Type Primary Code Tests Configuration
Calendar event operation (read-only) apps/api/src/routes/events.ts (new GET endpoint) apps/api/tests/routes/events.test.ts apps/pwa/src/api/client.ts (new fetchFn)
Calendar event operation (write) apps/api/src/routes/events.ts (new POST/PATCH/DELETE) + apps/api/src/broker/write.ts (new builder) Route tests + outbox drain tests apps/pwa/src/components/EventForm.tsx (new field)
Recurring event handling apps/api/src/broker/expand.ts (expansion logic) apps/api/tests/broker/expand.test.ts N/A (no UI change needed)
Shared list sync apps/api/src/routes/lists.ts (new router) + apps/api/src/broker/listsSync.ts (if background job needed) apps/api/tests/routes/lists.test.ts apps/pwa/src/api/client.ts (new interfaces)
UI component (calendar display) apps/pwa/src/components/ apps/pwa/src/components/*.test.tsx N/A
UI component (modal/dialog) apps/pwa/src/components/ + apps/pwa/src/store/calendarStore.ts (add state if needed) Component test N/A

New Endpoint:

  1. Create router file in apps/api/src/routes/ (or add to existing)
  2. Define Zod schema for input validation
  3. Implement handler(s): call resolveUserId, validate input, check authorization, query DB or enqueue outbox
  4. Mount in apps/api/src/index.ts via app.route('/api/...', newRouter)
  5. Export typed fetch function from apps/pwa/src/api/client.ts
  6. Call from CalendarShell or component via useQuery/useMutation
  7. Write unit tests in apps/api/tests/routes/

New Component:

  1. Create .tsx file in apps/pwa/src/components/
  2. Use TanStack Query for server state (via useQuery hook)
  3. Use Zustand selectors for UI state (via useCalendarStore)
  4. Export from CalendarShell or parent component
  5. Add .test.tsx file with Vitest + React Testing Library
  6. Mock useQuery and useCalendarStore in tests

New Utility:

  1. Create .ts file in apps/pwa/src/lib/ (frontend) or apps/api/src/broker/ (backend)
  2. Export functions with clear names and JSDoc comments
  3. Add .test.ts file with test cases
  4. Import where needed (no circular dependencies)

Special Directories

apps/api/src/db/migrations/:

  • Purpose: drizzle-kit-generated SQL migration files
  • Generated: Yes (via drizzle-kit generate:mysql)
  • Committed: Yes (must be version-controlled for reproducibility)
  • How to add: Run drizzle-kit generate:mysql after modifying schema.ts; commit the .sql file
  • How to apply: Run drizzle-kit migrate:mysql to execute pending migrations against MariaDB

apps/pwa/public/:

  • Purpose: PWA static assets served at root (manifest.webmanifest, service worker, icons, index.html)
  • Generated: sw.js and registerSW.js are generated by vite-plugin-pwa; others are committed
  • Committed: Yes (except dist/ and generated service worker code — PWA plugin handles registration)
  • How to add: Place assets here; vite build copies to dist/ and serves at /

apps/api/dist/ and apps/pwa/dist/:

  • Purpose: Compiled output (JavaScript, CSS, bundled PWA)
  • Generated: Yes (via build scripts)
  • Committed: No (gitignored)

node_modules/:

  • Purpose: pnpm-installed dependencies
  • Generated: Yes (via pnpm install)
  • Committed: No (gitignored; use pnpm-lock.yaml for reproducibility)

.planning/codebase/:

  • Purpose: Auto-generated codebase analysis documents (this file, ARCHITECTURE.md, TESTING.md, etc.)
  • Generated: Yes (by /gsd-map-codebase orchestrator)
  • Committed: Yes (reference documentation for future phases)

Structure analysis: 2026-06-09