4e38b5a791
Full Next.js App Router application with: - AI-graded lesson checkpoints (BKT/Elo mastery tracking) - Auth.js v5: credentials, Google, GitHub, generic OIDC - Anonymous-session-first with migrate-on-signin - Admin panel: users, blueprints, reports, site settings - Password reset + email verification (nodemailer/SMTP) - Site config: require_auth + signups_enabled flags - server-only guards on all DB/generation/verification modules - PostgreSQL 16 + pgvector, Redis cache, Drizzle ORM - 271 unit tests (Vitest), golden-eval harness, Playwright e2e stubs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
102 lines
7.7 KiB
Markdown
102 lines
7.7 KiB
Markdown
# CLAUDE.md — Curio
|
||
|
||
Repo context for Claude Code. Read this every session. Keep it current: if a convention changes, update this file in the same commit. Full product/architecture/design reference: `docs/curio-specification.md`.
|
||
|
||
## What Curio is (one paragraph)
|
||
|
||
Curio is a curiosity-led **mastery tutor**. A learner states intent → gets a Journey of bounded ~10-minute **Lessons** → each Lesson is short readable AI-generated explanation segments punctuated by **production checkpoints** (predict / explain-back / solve) → the AI **diagnoses** the learner's free-text response against pre-verified rubrics and a per-concept misconception library, gives targeted feedback, and gates advancement on demonstrated mastery. The moat is **diagnosis** (inferring *what* a learner misunderstands and *why*), not content generation.
|
||
|
||
## Decided stack — single language (TypeScript), do not substitute without asking
|
||
|
||
- **App:** Next.js (App Router) + TypeScript — RSC reading surface + Route Handlers (API) + native streaming/SSE
|
||
- **LLM:** Vercel AI SDK (provider-agnostic, streaming, schema-constrained structured output). Generator and grader configured to **different** models/providers.
|
||
- **Contracts:** Zod — shared across API I/O, LLM outputs, DB-derived types
|
||
- **DB:** PostgreSQL 16 + pgvector (single store, source of truth)
|
||
- **ORM/migrations:** Drizzle ORM + drizzle-kit
|
||
- **Cache/buffer:** Redis — a cache/buffer in *front* of Postgres, never load-bearing for availability
|
||
- **Background jobs:** Route Handlers + the `job` ledger table for the slice; **BullMQ** (Redis) when scale arrives — jobs spend money, so they must be **idempotent** with durable Postgres state
|
||
- **Styling/motion:** Tailwind + CSS custom properties (design tokens); motion via CSS transitions + **View Transitions API** (no animation library); honor `prefers-reduced-motion`
|
||
- **Observability:** Langfuse (or OpenTelemetry) for LLM call tracing
|
||
- **Rate limiting:** edge limiter (e.g. Upstash) on the cold-start generation endpoint
|
||
- **Tests:** Vitest (unit, LLM mocked) + golden-eval runner (real-model, CI) + Playwright (e2e)
|
||
- **Local infra:** docker-compose (postgres+pgvector, redis)
|
||
|
||
## Repo structure
|
||
|
||
```
|
||
curio/
|
||
CLAUDE.md
|
||
docker-compose.yml
|
||
docs/curio-specification.md
|
||
src/
|
||
app/ # Next.js App Router: reading surface + api/ route handlers
|
||
components/
|
||
lib/
|
||
llm/ # provider-agnostic client (Vercel AI SDK) + versioned prompt registry
|
||
generation/ # RAG-grounded content generation
|
||
verification/ # content cascade (T0–T2) + response grading
|
||
memory/ # mastery (BKT/Elo) + spaced repetition
|
||
intent/ # intent normalization + blueprint lookup
|
||
db/ # drizzle schema, queries, migrations
|
||
schemas/ # zod contracts (shared)
|
||
styles/ # design tokens
|
||
jobs/ # BullMQ workers (deferred until P3)
|
||
tests/golden/ # frozen eval sets: content verification + response grading
|
||
e2e/ # playwright
|
||
```
|
||
|
||
## Architectural invariants — violating these is a bug
|
||
|
||
1. **All LLM access goes through `src/lib/llm/client.ts`.** Never call a provider/AI-SDK model directly elsewhere. Generator and grader pull their model from config; they must differ.
|
||
2. **Prompts live in the versioned registry** (`src/lib/llm/prompts/`), never inline. Each has an id + version.
|
||
3. **Contracts are Zod schemas** in `src/schemas/`, shared by the LLM layer, the API, and the UI. LLM structured output is validated against them.
|
||
4. **The serve path reads from the Redis buffer; jobs generate.** No synchronous content generation in request handlers except the documented cold-start gate. Postgres is the source of truth — a Redis outage degrades latency, not availability.
|
||
5. **Generated content stores provenance** (`source_chunk_ids`) so verification and grading are *grounded* against sources, not free-judged.
|
||
6. **Grading is constrained.** The grader evaluates against a pre-verified rubric + reference answer + misconception library. Verdict ∈ {`mastered`,`partial`,`misconception`,`uncertain`}. It **must** support `uncertain` (abstain → reveal). **Bias against false-fail** — telling a correct learner they're wrong is the worst error.
|
||
7. **Verification is a cascade.** T0 structural (free) → T1 cheap-model → T2 strong-model (adversarial, at blueprint promotion). Expensive checks amortized once per blueprint, never per serve.
|
||
8. **Paid background jobs are idempotent** (idempotency key + durable `job` state). A retry must never regenerate-and-rebill.
|
||
9. **Per-session token budget is enforced in code.** The ~10-min Lesson bound is a real cap.
|
||
10. **Content is versioned** by `(intent_key, content_version, model_version)`; invalidation is lazy.
|
||
|
||
## Design invariants (see spec §7)
|
||
|
||
- **Thesis:** a calm, editorial reading surface that comes alive only when the learner responds. Not gamified, not a dashboard, not a chat-bubble app.
|
||
- **Signature:** diagnosis-as-**marginalia** — feedback threaded against the learner's own words, pointing at the `evidence_span` that tripped them. Spend the design's boldness here; keep everything else quiet.
|
||
- **Motion** is meaning, not decoration: reserved for the diagnosis moment (a brief "considering" beat → feedback eases in). CSS/View Transitions only.
|
||
- **Reading is the product:** humanist reading serif, generous measure (~62–68ch) and leading; display face used with restraint; tokens centralized in `src/styles/`.
|
||
- **Quality floor (non-negotiable):** responsive to mobile, visible keyboard focus, reduced-motion respected, WCAG-AA contrast (including every diagnosis-state color).
|
||
- **Before building any UI, run the frontend-design two-pass process** (plan tokens → critique for genericness → build). Avoid AI-default looks (cream+serif+terracotta, near-black+acid accent, broadsheet hairlines).
|
||
- Copy is design material: warm, specific, plain, on the learner's side; never gamified or condescending.
|
||
|
||
## Commands
|
||
|
||
```bash
|
||
docker compose up -d # postgres+pgvector, redis
|
||
pnpm install # or npm
|
||
pnpm db:generate && pnpm db:migrate
|
||
pnpm dev # Next.js
|
||
pnpm test # vitest (unit; LLM mocked)
|
||
pnpm test:golden # real-model eval harness (CI-gated)
|
||
pnpm test:e2e # playwright
|
||
pnpm lint && pnpm format # eslint + prettier
|
||
```
|
||
|
||
## Testing rules
|
||
|
||
- Write/extend tests **with** each change; run the suite before declaring a task done.
|
||
- **Mock the LLM in unit tests** (deterministic fixtures). Real-model calls only in the golden-eval suite.
|
||
- Golden evals (`tests/golden/`) are the bar for the moat: response-grading accuracy (track **false-fail rate**) + content-verification accuracy. Don't regress them; add cases on new failure modes.
|
||
- Migrations: never edit an applied drizzle migration; add a new one.
|
||
|
||
## Out of scope — do NOT build unless explicitly asked
|
||
|
||
Gamification (XP/badges/leaderboards), infinite feed / social, multi-provider fallback orchestration, knowledge graph, voice, PDF ingestion, accounts (MVP is anonymous-session-first). If a task seems to require one of these, stop and ask.
|
||
|
||
## Working agreement
|
||
|
||
- **Plan before coding** for anything non-trivial; surface architecture- or design-affecting choices before implementing.
|
||
- Small, focused commits per task. One ticket = one logical change.
|
||
- Keep Route Handlers thin; logic lives in `src/lib/`.
|
||
- Run the frontend-design planning pass before UI tickets.
|
||
- If you change a convention here, update this file in the same commit.
|
||
- When unsure between two reasonable designs, ask rather than guess — especially on the grading/verification path and the diagnosis UI. |