docs: create roadmap (5 phases)

This commit is contained in:
Lucas Berger
2026-06-03 16:15:27 -04:00
parent a20afd472a
commit ac82d32a36
4 changed files with 431 additions and 25 deletions
+23 -25
View File
@@ -88,36 +88,34 @@ Explicitly excluded. Documented to prevent scope creep. Anti-features sourced fr
## Traceability ## Traceability
Which phases cover which requirements. Populated during roadmap creation.
| Requirement | Phase | Status | | Requirement | Phase | Status |
|-------------|-------|--------| |-------------|-------|--------|
| AUTH-01 | TBD | Pending | | AUTH-01 | Phase 1 | Pending |
| AUTH-02 | TBD | Pending | | AUTH-02 | Phase 1 | Pending |
| AUTH-03 | TBD | Pending | | AUTH-03 | Phase 1 | Pending |
| CAL-01 | TBD | Pending | | CAL-01 | Phase 1 | Pending |
| CAL-02 | TBD | Pending | | CAL-08 | Phase 1 | Pending |
| CAL-03 | TBD | Pending | | CAL-02 | Phase 2 | Pending |
| CAL-04 | TBD | Pending | | CAL-03 | Phase 2 | Pending |
| CAL-05 | TBD | Pending | | CAL-04 | Phase 3 | Pending |
| CAL-06 | TBD | Pending | | CAL-05 | Phase 3 | Pending |
| CAL-07 | TBD | Pending | | CAL-06 | Phase 3 | Pending |
| CAL-08 | TBD | Pending | | CAL-07 | Phase 3 | Pending |
| LIST-01 | TBD | Pending | | PWA-01 | Phase 3 | Pending |
| LIST-02 | TBD | Pending | | PWA-02 | Phase 3 | Pending |
| LIST-03 | TBD | Pending | | LIST-01 | Phase 4 | Pending |
| LIST-04 | TBD | Pending | | LIST-02 | Phase 4 | Pending |
| NOTIF-01 | TBD | Pending | | LIST-03 | Phase 4 | Pending |
| NOTIF-02 | TBD | Pending | | LIST-04 | Phase 4 | Pending |
| NOTIF-03 | TBD | Pending | | NOTIF-01 | Phase 5 | Pending |
| PWA-01 | TBD | Pending | | NOTIF-02 | Phase 5 | Pending |
| PWA-02 | TBD | Pending | | NOTIF-03 | Phase 5 | Pending |
**Coverage:** **Coverage:**
- v1 requirements: 20 total - v1 requirements: 20 total
- Mapped to phases: 0 (set by roadmapper) - Mapped to phases: 20
- Unmapped: 20 ⚠️ (resolved at roadmap step) - Unmapped: 0
--- ---
*Requirements defined: 2026-06-03* *Requirements defined: 2026-06-03*
*Last updated: 2026-06-03 after initial definition* *Last updated: 2026-06-03 — traceability populated by roadmapper*
+99
View File
@@ -0,0 +1,99 @@
# Roadmap: FamilySync
## Overview
FamilySync is built in five phases, each delivering an end-to-end user-observable capability. Phase 1 is both the foundation and the highest-risk gate: OIDC auth must work and the CalDAV broker must prove it can read personal Fastmail calendars before any calendar UI is built. Phases 23 complete the calendar. Phase 4 delivers shared lists with live co-edit sync. Phase 5 wires up Web Push notifications. The dependency chain is strict: each phase is a prerequisite for the next, except the lists track (Phase 4) which is independent of the calendar write path.
## Phases
**Phase Numbering:**
- Integer phases (1, 2, 3): Planned milestone work
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 1: Foundation + Broker Spike** - Auth, Docker scaffold, CalDAV broker read path, and personal-calendar ACL spike (go/no-go gate)
- [ ] **Phase 2: Calendar Display** - Read-only unified color-coded calendar (week/month/day/agenda) built on the confirmed broker
- [ ] **Phase 3: Event Write-Back + PWA Install** - Full event CRUD written back to Fastmail, PWA manifest + service worker, guided iOS install flow
- [ ] **Phase 4: Shared Lists + Live Sync** - Named collaborative lists with item CRUD and real-time SSE co-edit sync
- [ ] **Phase 5: Web Push Notifications** - VAPID push for event reminders, event changes, and list-change alerts
## Phase Details
### Phase 1: Foundation + Broker Spike
**Goal**: The app stack is running, both members can authenticate, and the CalDAV broker can read Fastmail calendars — with a confirmed go/no-go decision on personal-calendar cross-account sharing
**Mode:** mvp
**Depends on**: Nothing (first phase)
**Requirements**: AUTH-01, AUTH-02, AUTH-03, CAL-01, CAL-08
**Success Criteria** (what must be TRUE):
1. Both members can reach the app URL, authenticate through Authelia OIDC, and land on the app home page without entering any Fastmail credentials
2. Sessions persist across browser restarts — neither member is asked to log in again on the next visit
3. Each member is assigned a stable, distinct display color that does not change between sessions
4. The broker successfully fetches and caches at least one event from the shared Fastmail calendar via CalDAV PROPFIND/REPORT
5. The personal-calendar ACL spike produces a documented go/no-go decision: either the broker token sees the wife's personal calendar after Fastmail share+accept, or the fallback strategy (shared-family-only or per-member app password) is chosen and recorded
**Plans**: TBD
### Phase 2: Calendar Display
**Goal**: Both members can see a unified, color-coded calendar aggregating all accessible Fastmail calendars across day, week, month, and agenda views — read-only, no write-back yet
**Mode:** mvp
**Depends on**: Phase 1
**Requirements**: CAL-02, CAL-03, CAL-07
**Success Criteria** (what must be TRUE):
1. Opening the app shows a color-coded calendar where each member's events appear in their assigned color, with shared events distinguishable from personal events
2. The user can switch between day, week, month, and agenda views and all events render correctly in each view
3. A recurring event (e.g., weekly meeting) displays all its occurrences correctly in the current view window, including correct behavior across DST boundaries
4. All-day events (birthdays, holidays) appear as full-day banners on the correct date with no timezone shift
**Plans**: TBD
**UI hint**: yes
### Phase 3: Event Write-Back + PWA Install
**Goal**: Both members can create, edit, and delete events that are written back to the correct Fastmail calendar, and the app is installable to the iPhone and Android home screens with a guided onboarding flow
**Mode:** mvp
**Depends on**: Phase 2
**Requirements**: CAL-04, CAL-05, CAL-06, CAL-07, PWA-01, PWA-02
**Success Criteria** (what must be TRUE):
1. A member can create a timed or all-day event (including recurring events) in the app and see it appear in the native Fastmail app within the next sync cycle
2. A member can edit an existing event's title, time, or description and the change persists correctly in Fastmail
3. A member can delete an event and it disappears from all views on the next sync
4. On Android, the app shows a browser install prompt and installs to the home screen; on iOS, the app shows a guided "Add to Home Screen" walkthrough with annotated screenshots that a non-technical user can follow independently
5. The installed PWA opens full-screen without browser chrome on both iOS and Android
**Plans**: TBD
**UI hint**: yes
### Phase 4: Shared Lists + Live Sync
**Goal**: Both members can create and manage shared named lists with real-time co-edit sync — edits by one member appear for the other without any manual refresh
**Mode:** mvp
**Depends on**: Phase 1
**Requirements**: LIST-01, LIST-02, LIST-03, LIST-04
**Success Criteria** (what must be TRUE):
1. Either member can create a named list (e.g., "Groceries") and delete a list they no longer need
2. Either member can add items to a list, check items off, reorder them by drag-and-drop, and delete individual items
3. When one member adds or checks off an item, the other member sees the change appear in the list within a few seconds without refreshing — even if they reconnect after a brief network gap
**Plans**: TBD
**UI hint**: yes
### Phase 5: Web Push Notifications
**Goal**: Both members receive timely Web Push alerts for upcoming events, event changes made by the other member, and list changes — reliably on both iOS and Android
**Mode:** mvp
**Depends on**: Phase 3, Phase 4
**Requirements**: NOTIF-01, NOTIF-02, NOTIF-03
**Success Criteria** (what must be TRUE):
1. A member receives a push notification on their phone approximately 15 minutes before a calendar event starts — delivered to the installed PWA, including on iOS
2. When the other member adds or changes a calendar event, the first member receives a push notification with the event title and action described in the payload
3. When the other member modifies a shared list (adds, checks off, or deletes an item), the first member receives a push notification identifying the list and the change
4. After an extended period of app inactivity, push notifications are still delivered (subscription health-check prevents silent revocation on iOS)
**Plans**: TBD
## Progress
**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
Note: Phase 4 depends only on Phase 1 and can begin as soon as Phase 1 is complete. It is serialized here to reduce work-in-progress.
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Foundation + Broker Spike | 0/? | Not started | - |
| 2. Calendar Display | 0/? | Not started | - |
| 3. Event Write-Back + PWA Install | 0/? | Not started | - |
| 4. Shared Lists + Live Sync | 0/? | Not started | - |
| 5. Web Push Notifications | 0/? | Not started | - |
+87
View File
@@ -0,0 +1,87 @@
---
gsd_state_version: '1.0'
status: planning
progress:
total_phases: 5
completed_phases: 0
total_plans: 0
completed_plans: 0
percent: 0
---
# Project State
## Project Reference
See: .planning/PROJECT.md (updated 2026-06-03)
**Core value:** One color-coded family calendar (shared + personal) and shared lists from a single low-friction PWA — cross-ecosystem, no app store
**Current focus:** Phase 1 — Foundation + Broker Spike
## Current Position
Phase: 1 of 5 (Foundation + Broker Spike)
Plan: 0 of ? in current phase
Status: Ready to plan
Last activity: 2026-06-03 — Roadmap created
Progress: [░░░░░░░░░░] 0%
## Performance Metrics
**Velocity:**
- Total plans completed: 0
- Average duration: -
- Total execution time: 0 hours
**By Phase:**
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| - | - | - | - |
**Recent Trend:**
- Last 5 plans: -
- Trend: -
*Updated after each plan completion*
## Accumulated Context
### Decisions
Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:
- Phase 1 gate: Personal-calendar CalDAV ACL must be spiked before calendar UI is built. Fallback is shared-family-only if spike fails.
- CalDAV locked: Fastmail does not expose calendars over JMAP. CalDAV via tsdav is the only protocol. No reconsideration.
- Identity: Use oidc_iss + oidc_sub as stable composite key. Never email.
- Real-time transport: Prefer SSE over WebSocket (proxy-resilient through Pangolin). Verify Pangolin SSE pass-through in Phase 1 infra spike.
- Recurring events: Create + display only in v1 (CALDAV:expand on server side). Single-occurrence edit deferred to v1.x.
### Pending Todos
None yet.
### Blockers/Concerns
- Phase 1: Personal-calendar CalDAV ACL behavior on Fastmail is LOW confidence (must spike). Failure degrades unified view to shared-family-only for v1.
- Phase 1: Pangolin SSE/WebSocket pass-through is an open infra question (known issue #1034). Must smoke-test before Phase 4 real-time sync is built.
- Phase 3: iOS install guide is load-bearing for the wife — she will never receive push notifications if she does not install the PWA.
- Phase 5: iOS push subscriptions silently revoked after 3 silent pushes. Subscription health-check and event.waitUntil() are mandatory from day one.
## Deferred Items
| Category | Item | Status | Deferred At |
|----------|------|--------|-------------|
| Calendar | Single-occurrence recurring edit (RECURRENCE-ID) | v1.x | Roadmap |
| Calendar | "This and following" recurring edit | v1.x | Roadmap |
| Calendar | Apple Calendar native subscribe URL docs | v1.x | Roadmap |
| Calendar | Secondary timezone display toggle | v1.x | Roadmap |
| Display | Wall-display / kiosk dashboard | v2 | PROJECT.md |
## Session Continuity
Last session: 2026-06-03
Stopped at: Roadmap created, STATE.md initialized. Ready to plan Phase 1.
Resume file: None
+222
View File
@@ -0,0 +1,222 @@
<!-- GSD:project-start source:PROJECT.md -->
## Project
**FamilySync**
FamilySync is a self-hosted, Dockerized family organization hub for a two-person household, modeled loosely on Skylight. It gives the family one unified, color-coded calendar and shared collaborative lists (groceries, gift ideas), reachable from a single low-friction React PWA — across a mixed Android/Fastmail and Apple ecosystem — built as one custom app on top of the family's existing paid Fastmail account. Email stays with members' existing mail clients and is out of scope.
**Core Value:** The household can see and co-edit one color-coded family calendar (shared + each member's personal) and shared lists from a single low-friction PWA — cross-ecosystem, no app store, no per-member calendar credential juggling.
### Constraints
- **Tech stack**: MariaDB for the database — PostgreSQL is not available in the stack
- **Tech stack**: Redis available (optional, for live list sync / push)
- **Infrastructure**: Unraid host running Docker + Docker Compose
- **Auth**: Authelia (already deployed) — OIDC/OAuth2 for the custom app; all members authenticate through it
- **Calendar backend**: Fastmail (paid, existing) is the single source for all calendars via JMAP/CalDAV
- **Frontend**: React PWA only — no React Native, no App Store
- **Networking**: Split-DNS internal domain, private IPs internally; public exposure via Pangolin/Newt tunnel, no open ports
- **UX**: Must be slick and low-friction for a non-technical Apple member — hard constraint, drives design tradeoffs
- **Scope**: No email features; no forking existing apps
<!-- GSD:project-end -->
<!-- GSD:stack-start source:research/STACK.md -->
## Technology Stack
## Recommended Stack
### 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 |
### 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 |
### 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 |
## Installation
# Backend
# Frontend
# Dev
## Calendar Integration: CalDAV, Not JMAP
- Principal URL: `https://caldav.fastmail.com/dav/principals/user/broker@fastmail.com/`
- `tsdav` performs `PROPFIND` on the principal to discover all calendar collections, then fetches each collection's events via `REPORT` (calendar-query or calendar-multiget).
- One app password covers all calendars owned by that account under the default "Mail, Contacts & Calendars" scope.
- `tsdav` returns raw iCalendar strings. Pass each to `ical.js` for parsing into event objects, then use `rrule` for RRULE expansion into the date range the UI needs.
- Write-back (create/edit/delete): PUT a new `.ics` to the collection URL; DELETE by UID.
- `node-ical`: older fork with weaker RRULE support; ical.js is maintained by Mozilla and is the reference implementation
- Direct `fetch`/`axios` against CalDAV: re-inventing XML namespace handling and PROPFIND parsing; tsdav exists specifically to avoid this
- JMAP: not available for calendars on Fastmail today
## Backend Framework
- First-class TypeScript with RPC-style type sharing (Hono RPC can export typed client for the React frontend — eliminates API drift)
- Built-in SSE streaming helper (`streamSSE`) for live list updates
- WebSocket support via `@hono/node-server`
- Runs on Node.js 22 LTS in Docker with `@hono/node-server`
- Prisma generates a binary engine that adds complexity in Docker images and has weaker MariaDB compatibility signals
- Drizzle uses `mysql2` directly — the same driver you'd use raw; no runtime translation layer
- Drizzle's `mysqlTable` schema is fully MariaDB-compatible (MariaDB is wire-compatible with MySQL; Drizzle's `mysql` dialect works)
- Type inference from schema → query results is the core value proposition; zero runtime overhead
## React PWA Stack
- 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 |
| 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` |
## Authelia OIDC Integration
- `response_types: [code]`
- `grant_types: [authorization_code, refresh_token]`
- `require_pkce: true`, `pkce_challenge_method: S256`
- `token_endpoint_auth_method: client_secret_basic`
## Live List Sync
## 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 |
## 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) |
## 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 |
## Open Questions Flagged for Phase Research
## Sources
- [Fastmail API Documentation](https://www.fastmail.com/dev/) — Confirmed CalDAV-only for calendars; JMAP calendars not available
- [Fastmail App Passwords](https://www.fastmail.help/hc/en-us/articles/360058752854-App-passwords) — Scope covers CalDAV; single password covers all calendars in account
- [Using Fastmail with CalDAV libraries](https://utf9k.net/blog/fastmail-caldav/) — Principal URL pattern, app password auth
- [Fastmail Calendar Sharing](https://www.fastmail.help/hc/en-us/articles/1500000279781-Sharing-calendars-with-other-users) — Sharing is multi-user-account scoped; cross-account sharing unconfirmed
- [tsdav npm](https://www.npmjs.com/package/tsdav) — Version 2.2.2 confirmed
- [ical.js npm](https://www.npmjs.com/package/ical.js) — Version 2.2.1 confirmed; Mozilla-maintained
- [rrule npm](https://www.npmjs.com/package/rrule) — Version 2.8.1 confirmed
- [Hono](https://hono.dev/) — Version 4.12.23; Node.js adapter confirmed
- [Drizzle ORM MySQL](https://orm.drizzle.team/docs/get-started-mysql) — MariaDB via mysql2 confirmed
- [vite-plugin-pwa](https://vite-pwa-org.netlify.app/) — Version 1.3.0; Workbox 7 integration
- [web-push npm](https://www.npmjs.com/package/web-push) — Version 3.6.7
- [Meet Declarative Web Push — WebKit](https://webkit.org/blog/16535/meet-declarative-web-push/) — Safari 18.4+, iOS 18.4+ confirmed
- [PWA iOS Limitations 2026](https://www.magicbell.com/blog/pwa-ios-limitations-safari-support-complete-guide) — iOS 16.4 minimum; home screen required; EU DMA regression
- [Authelia Express.js Integration](https://www.authelia.com/integration/openid-connect/clients/expressjs/) — Authorization code + PKCE flow; client_secret_basic
- [@hono/oidc-auth GitHub](https://github.com/honojs/middleware/tree/main/packages/oidc-auth) — Storage-less JWT session cookies; Version 1.8.3
<!-- GSD:stack-end -->
<!-- GSD:conventions-start source:CONVENTIONS.md -->
## Conventions
Conventions not yet established. Will populate as patterns emerge during development.
<!-- GSD:conventions-end -->
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
## Architecture
Architecture not yet mapped. Follow existing patterns found in the codebase.
<!-- GSD:architecture-end -->
<!-- GSD:skills-start source:skills/ -->
## 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 -->
## GSD Workflow Enforcement
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
Use these entry points:
- `/gsd-quick` for small fixes, doc updates, and ad-hoc tasks
- `/gsd-debug` for investigation and bug fixing
- `/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 -->
## Developer Profile
> 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 -->