4.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Development
pnpm dev # Start dev server (http://localhost:3000)
pnpm build # Production build (standalone output)
pnpm lint # Run ESLint
# Database (use pnpm instead of npx)
pnpm prisma migrate dev --name <name> # Create and apply migration
pnpm prisma generate # Regenerate Prisma client
pnpm prisma studio # Open DB GUI
Stack
- Next.js 16 (App Router, standalone output)
- SQLite + Prisma 7 via
@prisma/adapter-better-sqlite3(not the default SQLite adapter) - NextAuth.js v5 (beta.30) — JWT sessions, Credentials provider only
- Tailwind CSS v4 — CSS Variables theming in
src/app/globals.css - Drag & Drop —
@dnd-kitand@hello-pangea/dnd(both present) - pnpm — package manager (use pnpm, not npm/yarn)
Architecture Overview
Workshop Types
There are 5 workshop types: swot (sessions), motivators, year-review, weekly-checkin, weather.
Single source of truth: src/lib/workshops.ts exports WORKSHOPS, WORKSHOP_BY_ID, and helpers. Every place that lists or routes workshop types must use this file.
All types and UI config constants are in src/lib/types.ts (e.g. MOTIVATORS_CONFIG, YEAR_REVIEW_SECTIONS, SWOT_QUADRANTS, EMOTIONS_CONFIG).
Layer Structure
src/
├── actions/ # Next.js Server Actions ('use server') — call services, revalidate paths
├── services/ # Prisma queries + business logic (server-only)
│ ├── database.ts # Prisma singleton (global for dev HMR)
│ ├── session-permissions.ts # Shared permission factories
│ └── session-share-events.ts # Shared share + SSE event handlers
├── app/
│ ├── api/ # Route handlers (SSE subscribe + auth)
│ ├── (auth)/ # Login/register pages
│ └── [workshop]/ # One folder per workshop type
├── components/
│ └── collaboration/ # BaseSessionLiveWrapper + share/live UI
├── hooks/
│ └── useLive.ts # SSE client hook (EventSource + reconnect)
└── lib/
├── workshops.ts # Workshop metadata registry
├── types.ts # All TypeScript types + UI config
└── share-utils.ts # Shared share types
Real-Time Collaboration (SSE)
Each workshop has /api/[path]/[id]/subscribe — a GET route that opens a ReadableStream (SSE). The server polls the DB every 1 second for new events and pushes them to connected clients. Server Actions write events to the DB after mutations.
Client side: useLive hook (src/hooks/useLive.ts) connects to the subscribe endpoint with EventSource, filters out events from the current user (to avoid duplicates), and calls router.refresh() on incoming events.
BaseSessionLiveWrapper (src/components/collaboration/) is the shared wrapper component that wires useLive, CollaborationToolbar, and ShareModal for all workshop session pages.
Shared Permission System
createSessionPermissionChecks(model) in src/services/session-permissions.ts returns canAccess, canEdit, canDelete for any Prisma model that follows the session shape (has userId + shares relation). Team admins have implicit access to their members' sessions.
createShareAndEventHandlers(...) in src/services/session-share-events.ts returns share, removeShare, getShares, createEvent, getEvents — used by all workshop services.
Auth
src/lib/auth.ts— NextAuth config (signIn, signOut, auth exports)src/lib/auth.config.ts— config object (used separately for Edge middleware)src/middleware.ts— protects all routes except/api/auth,_next/static,_next/image,favicon.ico- Session user ID is available via
auth()call server-side; token includesidfield
Database
Prisma client is a singleton in src/services/database.ts. DATABASE_URL env var controls the SQLite file path (default: file:./prisma/dev.db). Schema is at prisma/schema.prisma.
Adding a New Workshop
Pattern followed by all existing workshops:
- Add entry to
WORKSHOPSinsrc/lib/workshops.ts - Add Prisma models (Session, Item, Share, Event) following the existing pattern
- Create service in
src/services/usingcreateSessionPermissionChecksandcreateShareAndEventHandlers - Create server actions in
src/actions/ - Create API route
src/app/api/[path]/[id]/subscribe/route.ts(copy from existing) - Create pages under
src/app/[path]/ - Use
BaseSessionLiveWrapperfor the session live page