Files
iag-dev-evaluator/CLAUDE.md

3.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

pnpm dev          # Start dev server
pnpm build        # Production build
pnpm lint         # ESLint
pnpm typecheck    # tsc --noEmit

pnpm test                    # Vitest unit tests (run once)
pnpm test:e2e                # Playwright E2E (requires dev server running)

pnpm db:generate  # Regenerate Prisma client after schema changes
pnpm db:push      # Sync schema to DB (dev, no migration files)
pnpm db:migrate   # Apply migrations (production)
pnpm db:seed      # Seed with sample data
pnpm db:studio    # Open Prisma Studio

Package manager: pnpm.

Coding conventions

Server-first by default

This codebase maximises server-side rendering and minimises client-side JavaScript:

  • All pages are server components by default. Never add "use client" to a page file.
  • Data fetching always happens server-side in src/lib/server-data.ts — never fetch() from the client, never call Prisma from a client component.
  • All mutations use server actions (src/actions/) — never create new API routes for mutations. The only remaining API routes are the export endpoints and auth (see below).
  • "use client" is only added to components that genuinely need browser APIs or React state (forms, interactive widgets). Keep the surface area small.
  • Auth checks happen in every server action via const session = await auth() before touching the DB.

Data flow pattern

  • Server page calls src/lib/server-data.ts functions (which call auth() + Prisma internally)
  • Page passes serialized data as props to client components in src/components/
  • Client components call server actions (src/actions/) for mutations
  • Server actions call revalidatePath() to trigger cache invalidation

Auth

src/auth.ts — NextAuth v5 with Credentials provider (email + bcrypt password). JWT strategy with id and role added to the token. Two roles: evaluator (default) and admin.

src/middleware.ts — Protects all routes. Admin routes redirect non-admins. Auth routes redirect logged-in users to /dashboard.

Access control

src/lib/evaluation-access.tscanAccessEvaluation() is the single source of truth. An evaluation is accessible if: user is admin, user is the evaluator, evaluation is shared with the user (EvaluationShare), or isPublic is true (read-only).

Database

SQLite in dev (DATABASE_URL=file:./dev.db), swap to Postgres for production. Schema lives in prisma/schema.prisma. Key relations:

  • EvaluationTemplateTemplateDimension[]
  • EvaluationDimensionScore[] (one per dimension, @@unique([evaluationId, dimensionId]))
  • EvaluationEvaluationShare[] (many users)
  • EvaluationAuditLog[]

TemplateDimension.suggestedQuestions is stored as a JSON string (array). TemplateDimension.rubric is stored as a "1:X;2:Y;..." string. Both are parsed client-side.

API routes (remaining)

Only exports and auth use API routes:

  • GET /api/export/csv?id= and GET /api/export/pdf?id= — use src/lib/export-utils.ts
  • POST /api/ai/suggest-followupsstub, returns deterministic suggestions; replace with real LLM call if needed
  • POST /api/auth/signup — user registration

Key types

src/types/next-auth.d.ts extends Session.user with id and role. Always use session.user.id (never session.user.email) as the user identifier in server actions.

JWT staleness

session.user.name comes from the JWT token frozen at login time. If a page needs the user's current name (or any other mutable profile field), query Prisma directly using session.user.id — do not rely on the session object for those values.