# 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_
