This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
bun run dev # Dev server on port 3000
bun run build # Production build
bun run test # Typecheck (tsc --noEmit) + run tests
bun run deploy # Build + wrangler deploy (manual fallback only — see Deployment below)
bun run cf-typegen # Regenerate worker-configuration.d.ts after wrangler.jsonc changes
bun run db:generate # Generate Drizzle migration from schema changes
bun run db:migrate:local # Apply migrations to local D1
bun run db:migrate:remote # Apply migrations to remote D1TanStack Start full-stack React app on Cloudflare Workers. D1 (SQLite) for storage, Workers AI (Gemma) for Korean NLP, Cron Triggers for deadline auto-confirmation.
- Organizer creates event at
/new→ gets admin URL + shared respond URL - Participants visit
/{eventId}, identify with email+name, input availability via NL or calendar grid - Cron runs every 5 min → finds expired pending events → runs optimal-time algorithm → confirms or cancels
Use createServerFn from @tanstack/react-start with .validator(). Access Cloudflare bindings via import { env } from 'cloudflare:workers' — env.DB for D1, env.AI for Workers AI.
All dates stored as UTC ISO strings. Convert with dayjs.utc() and .tz(timezone). Cell keys in the calendar grid use H:mm format (no zero-padding) — must be consistent everywhere or pre-10am cells break.
File-based: src/routes/$eventId/index.tsx → /{eventId}. Admin pages use ?token= query param for auth. Route params via Route.useLoaderData(), search params via Route.useSearch().
Pushes to main auto-deploy to Cloudflare Workers via the GitHub integration configured in the Cloudflare dashboard (Workers Builds). Do not run bun run deploy after a push — it is only a manual fallback for when the auto-deploy pipeline is unavailable.
- D1 parameter limit (~100): Batch inserts in chunks of 10. See
submitAvailabilityinparticipants.ts. - Time format consistency: Calendar grid cell keys use
"YYYY-MM-DD H:mm"(single-digit hours). UsingHH:mmanywhere breaks cells before 10am. - Drizzle column references: When querying participants/slots, use
eq(participants.eventId, ...)noteq(events.id, ...). TypeScript won't catch this since both aretextcolumns. Tests inevents.test.tsguard against this. - Migration NOT NULL columns: SQLite can't add NOT NULL columns without defaults to existing tables. Add
DEFAULT ''in migration SQL when needed.