A live, scenario-based practice-exam platform for the Claude Certified Architect (CCA) Foundations exam. Every question is generated on demand by Claude, anchored to a realistic production scenario, and explained option by option.
Built with Next.js (App Router) + TypeScript. All Claude API calls happen server-side; the browser never sees your key.
Honesty disclaimer. These are original approximations of the exam's published format — not leaked or reproduced exam content. Question style, difficulty, and structure are modeled on the public description of the exam. Always verify the current format on Anthropic's official certification pages.
This repo ships with no API key, and any fork should too. Each developer or student who clones it supplies their own:
- Create a key at console.anthropic.com (Settings → API Keys).
- Provide it in your own environment — locally in
.env.local, or in your hosting dashboard's environment variables.
The key is read only inside the server-side generation route (app/api/sessions/[id]/blocks/[index]/route.ts), via the ANTHROPIC_API_KEY environment variable. It is never bundled into client JavaScript, never logged, and .gitignore keeps .env* files (except .env.example) out of git.
If the key is missing at request time, the app shows a friendly setup screen explaining exactly how to configure it — it does not crash.
The app now persists accounts, exam sessions, generated questions, and score history in Postgres. The easiest path is to run Postgres via Docker and the app with npm run dev:
npm install
cp .env.example .env.local # set ANTHROPIC_API_KEY and AUTH_SECRET
make db # start only Postgres (docker compose up -d db)
npm run devOpen http://localhost:3000, create an account, and start an exam.
Required environment (.env.local):
ANTHROPIC_API_KEY— your key (server-side only; never sent to the browser).AUTH_SECRET— secret for signing the session cookie. Generate one withopenssl rand -hex 32.DATABASE_URL— Postgres connection string. The defaultpostgres://cca:cca@localhost:5432/ccamatches the bundledmake dbservice.ANTHROPIC_MODEL(optional) — model used to generate questions (defaultclaude-sonnet-4-6— fast & cheap; setclaude-opus-4-8for highest quality but slower generation).ANTHROPIC_EFFORT(optional) — thinking effort:low|medium|high|max(defaultmedium). Lower is faster.ANTHROPIC_TIMEOUT_MS(optional) — per-generation timeout (default 120000).
The schema is created automatically on first use (CREATE TABLE IF NOT EXISTS), so there's no separate migration step.
- Accounts. A lightweight username/password login (passwords hashed with scrypt, session in a signed httpOnly cookie). It is intentionally minimal — enough to scope your exams to you on a locally-run instance.
- Saved & resumable sessions. Every exam is a row keyed by a UUID. Generated scenario blocks (questions, correct answers, explanations) are stored as they're produced, so pausing and resuming never regenerates them — you don't pay tokens twice. Resume from the profile page.
- Score history. Overall and per-domain scores are snapshotted when an exam finishes, powering the profile stats.
- AI performance coach. On the profile page, Claude reads your aggregated stats and returns a coaching report — verdict vs the 720 bar, weakest domains with concrete sub-topics to drill, and a short study plan.
This app needs a Node server runtime — it cannot be hosted on GitHub Pages or any static-only host, because the question-generation endpoint runs server-side.
- Push your fork to GitHub and import it at vercel.com/new.
- Provision a serverless Postgres (e.g. Neon) and copy its connection string.
- In Project → Settings → Environment Variables, add
ANTHROPIC_API_KEY,AUTH_SECRET, andDATABASE_URL(and optionallyANTHROPIC_MODEL). - Deploy. Redeploy after changing env vars.
Other Node hosts (Netlify, Railway, Render, etc.) work the same way — set the same environment variables and point DATABASE_URL at a reachable Postgres.
The app ships with a multi-stage Dockerfile that builds Next.js in standalone mode for a small runtime image, plus a docker-compose.yml.
Compose runs both the app and a Postgres service (with a persistent volume), wired together automatically.
cp .env.example .env.local # set ANTHROPIC_API_KEY and AUTH_SECRET
docker compose up --build -d # or: make upOpen http://localhost:3000. Tail logs with make logs, open a DB shell with make db-shell, stop with make down. make db-reset drops the data volume (wiping all accounts and sessions).
docker build -t cca-exam-simulator . # or: make docker-build
docker run -d -p 3000:3000 \
--env-file .env.local cca-exam-simulator # or: make docker-runmake docker-run starts the container detached (in the background) and returns immediately — check it with docker ps, tail logs with make docker-logs, and stop/remove it with make docker-stop.
Note: plain Docker runs the app image alone, without a database, so accounts and saved exams won't work. For the full stack (app + Postgres) use make up (Docker Compose). The key is passed in at runtime via --env-file / Compose env_file — it is never baked into the image. The container runs as an unprivileged nextjs user.
- Create a (local) account, then choose a Full mock (60 questions, weighted toward Domain 1, 120-minute timer) or a Single domain set (12 questions).
- Questions are generated in scenario blocks of 4–6. The frontend requests one block at a time and prefetches the next while you answer, so there's no visible wait after the first block.
- Each question gives an immediate verdict, an explanation of all four options, and a running score (overall + per domain).
- Every exam is saved server-side in Postgres, so you can pause and resume from the profile page — even days later. Already-generated blocks are reused, so resuming never re-spends tokens.
- For a full mock, the 120-minute clock starts only once the first scenario is ready — generation time doesn't eat into your exam time.
- Results show a per-domain breakdown, an estimated scaled score (a simple linear estimate on the 100–1,000 scale vs. the ~720 pass bar), and the weakest domains to re-drill. Finished scores feed the profile stats and the AI coach.
| Code | Domain | Weight | Questions |
|---|---|---|---|
| D1 | Agentic Architecture & Orchestration | 27% | 16 |
| D2 | Tool Design & MCP Integration | 18% | 11 |
| D3 | Claude Code Configuration & Workflows | 20% | 12 |
| D4 | Prompt Engineering & Structured Output | 20% | 12 |
| D5 | Context Management & Reliability | 15% | 9 |
Questions are generated live, so each session uses Claude API tokens billed to your key. Cost and speed depend on the model — claude-sonnet-4-6 by default (fast and cheap); switch ANTHROPIC_MODEL to claude-opus-4-8 for the highest-quality (but slower, pricier) questions. Single-domain sets cost proportionally less than a full 60-question mock.
Generated blocks are persisted per session, so resuming a paused exam re-spends no tokens — you only pay to generate each scenario once. The AI performance coach is a separate, small request you trigger from the profile page.
The API route applies a simple in-memory, per-IP limit (10 block-generations per minute) so a publicly deployed instance doesn't drain your key from a single client. This state lives in the server process's memory: it resets on redeploy and is not shared across multiple instances/regions. For serious multi-instance traffic, swap it for a durable store (e.g. Redis/Upstash) — see lib/rate-limit.ts.
| Command | What it does |
|---|---|
npm run dev |
Start the dev server |
npm run build |
Production build |
npm start |
Run the production build |
npm run lint |
Lint |
npm test |
Run the lightweight unit tests (JSON extractor, validators, generate flow) |
The tests run TypeScript source directly via Node's native type stripping (Node ≥ 23.6; CI pins Node 24).
A Makefile wraps the npm scripts plus the Docker workflow. Run make help (the default target) to list everything.
| Command | What it does |
|---|---|
make install |
Install npm dependencies |
make dev |
Start the dev server (http://localhost:3000) |
make build |
Production build |
make start |
Run the production build |
make lint |
Lint the codebase |
make test |
Run the unit tests |
| Command | What it does |
|---|---|
make docker-build |
Build the production Docker image |
make docker-run |
Run the image (reads .env.local for ANTHROPIC_API_KEY) |
make docker-stop |
Stop the running container |
make docker-logs |
Tail logs from the running container |
| Command | What it does |
|---|---|
make up |
Build and start via docker compose (detached) |
make down |
Stop and remove compose services |
make logs |
Tail compose logs |
| Command | What it does |
|---|---|
make db |
Start only the Postgres service (for make dev) |
make db-shell |
Open a psql shell in the Postgres container |
make db-reset |
Drop the Postgres data volume (destroys all users/sessions) |
| Command | What it does |
|---|---|
make help |
Show all available targets |
make clean |
Remove build artifacts (.next, node_modules/.cache) |
Override the image name, container name, or port via variables, e.g. make docker-run PORT=8080.
app/
api/auth/{register,login,logout,me}/route.ts # username/password auth
api/sessions/route.ts # create / list exam sessions
api/sessions/[id]/route.ts # load (resume) / autosave progress
api/sessions/[id]/blocks/[index]/route.ts # get-or-generate a block (cached → no tokens)
api/stats/interpretation/route.ts # AI performance coach
page.tsx # landing page (auth-aware)
login/, register/, profile/ # auth pages + profile (sessions, stats, coach)
exam/page.tsx # exam runner
prompts/
cca-foundations-system-prompt.md # operational system prompt (loaded at runtime)
cca-foundations-exam-simulator.md # original chat-style prompt (reference)
coach-system-prompt.md # AI coach system prompt
lib/
db.ts # Postgres pool + idempotent schema bootstrap
auth.ts # scrypt hashing + signed session cookie
users.ts, sessions.ts # user / exam-session / block persistence
anthropic.ts # server-only Claude client + generate/retry/logging
coach.ts # AI interpretation of performance stats
exam-prompt.ts, load-prompt.ts # prompt loading (fs + fallback)
json-extract.ts, validate.ts, request-validation.ts, rate-limit.ts, http.ts
domains.ts, score.ts, types.ts
components/ # client UI (exam runner, results, profile, auth, …)
scripts/test.mjs # lightweight test runner
MIT — see LICENSE.
