From 198b85186cf895907a57adb49b51a5c8a7f7db0d Mon Sep 17 00:00:00 2001 From: Thomas Ruoff Date: Tue, 3 Mar 2026 21:08:33 +0100 Subject: [PATCH] add CLAUDE.md with project conventions and architecture docs Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bbe9750 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,67 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## About + +A Next.js booking system for a local scouts van. Users submit booking requests; an admin approves/rejects them. Authentication is restricted to a small allowlist. + +## Commands + +```bash +npm run dev # Start dev server with Turbopack +npm run build # Production build +npm run lint # ESLint +npm test # Run Jest tests +npm run test:watch # Jest in watch mode +``` + +## Architecture + +### Tech Stack +- **Next.js** (Pages Router) with TypeScript +- **MongoDB/Mongoose** for persistence +- **better-auth** for authentication (replaced next-auth) +- **Google Calendar API** for syncing bookings +- **Tailwind CSS v4** for styling +- **MDX** for static content pages (impressum, privacy, terms) + +### Authentication +Auth is handled by `better-auth` via `lib/auth.ts` (server) and `lib/auth-client.ts` (client). The API route is `pages/api/auth/[...all].ts`. Access is restricted: only a specific `ADMIN_EMAIL` and a hardcoded allowlist of GitHub user IDs (`GITHUB_USERS_GRANTED`) can log in. Protected pages use the `withAuth` HOC (`helpers/withAuth.tsx`), which wraps pages in the `` component that redirects unauthenticated users to GitHub OAuth. + +### Data Flow: Bookings +1. `db/booking.ts` — Mongoose model (`IBooking`). Dates stored as `YYYY-MM-DD` strings. The `days` array is auto-computed from `startDate`/`endDate` in a pre-validate hook. On save, a Google Calendar event is created (or deleted on cancel/reject) via the pre-save hook. +2. `db/index.ts` — Database connection and query helpers (`getBookedDays`, `createBooking`, `patchBooking`, etc.). `getBookedDays` merges days from MongoDB and Google Calendar. +3. `lib/googlecalendar.ts` — Google Calendar integration using a service account. Reads env var `GOOGLE_SERVICE_ACCOUNT_KEY_JSON` (JSON string). + +### Booking Status Lifecycle +`BOOKING_STATUS` enum (in `db/enums.ts`): `requested` → `confirmed` | `rejected` | `canceled` + +### Key Environment Variables +- `MONGO_URI` — MongoDB connection string +- `ADMIN_EMAIL` — Only email allowed to log in +- `BETTER_AUTH_SECRET` — Auth secret key +- `BETTER_AUTH_URL` — Auth base URL (defaults to `http://localhost:3000`) +- `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` — GitHub OAuth app (optional) +- `NEXT_PUBLIC_GITHUB_ENABLED` — Set to enable GitHub OAuth login on the client +- `SMTP_USER` / `SMTP_PASS` / `FROM_EMAIL` — Email via wirtanen.uberspace.de:465 +- `GOOGLE_CALENDAR_ID` — Calendar to sync bookings into +- `GOOGLE_SERVICE_ACCOUNT_KEY_JSON` — Service account credentials (JSON string) + +### Date Handling +Frontend dates use `dd.MM.yyyy`; backend/DB uses `yyyy-MM-dd`. Helpers in `helpers/date.ts` (`dateFormatFrontend`, `dateFormatBackend`, `dateParseFrontend`, `dateParseBackend`). Timezone-aware "now" uses `nowInTz()` defaulting to `Europe/Berlin`. + +### Page Structure +- `/` — Public landing page with calendar showing booked days +- `/book` — Multi-step booking form (context in `context/book.tsx`) +- `/bookings/[uuid]` — Public booking confirmation/details page +- `/admin` — Admin dashboard (auth-protected via `withAuth`) +- `/admin/bookings/[uuid]` — Admin booking management +- `/prices`, `/impressum`, `/privacy`, `/terms` — Static/MDX pages + +### API Routes +- `POST /api/bookings` — Create booking +- `GET/PATCH /api/bookings/[uuid]` — Get or update booking +- `GET /api/daysbooked` — Returns booked days array (JSON) +- `GET /api/daysbooked.ics` — Returns booked days as iCal feed +- `/api/auth/[...all]` — better-auth handler