---
title: "CLAUDE.md — Scrum4Me"
status: active
audience: [ai-agent]
language: nl
last_updated: 2026-05-11
---

# CLAUDE.md — Scrum4Me

Desktop-first Scrum-app voor solo developers en kleine teams. Hiërarchie: product → PBI → story → taak. Zie [README.md](./README.md) voor setup.

---

## Orientatie

| Bestand | Waarvoor |
|---|---|
| `docs/INDEX.md` | Gegenereerde index van alle docs — begin hier |
| `docs/specs/functional.md` | Acceptatiecriteria, user flows |
| `docs/architecture.md` | Breadcrumb → 6 topische arch-bestanden |
| `docs/api/rest-contract.md` | REST API contract voor Claude Code |
| `docs/design/styling.md` | **Lees vóór elk component** — MD3-tokens, shadcn |
| `docs/adr/` | Architecture Decision Records — tech-keuzes (base-ui vs Radix, sort-order, demo-policy, …) |
| `docs/architecture/` | 6 topische architecture-bestanden (data-model, auth, sprint-execution, …) — uitwerking van `docs/architecture.md` |
| `docs/runbooks/plan-to-pbi-flow.md` | **Na goedgekeurd plan** — PBI/Story/Task aanmaken via MCP, zónder direct uitvoeren |

---

## Hoe werk vinden

1. Branch aanmaken: `git checkout -b feat/<batch-slug>` — nog **geen** `gh pr create`
2. `mcp__scrum4me__get_claude_context` → pak de next story
3. Voer taken uit in `sort_order`; update status per taak
4. Lees het relevante patroon en styling vóór je begint
5. Verifieer: `npm run verify && npm run build` — `verify` = lint + typecheck + test
6. Commit per laag: `git add -A && git commit` — **geen** `git push` — zie [docs/runbooks/branch-and-commit.md](./docs/runbooks/branch-and-commit.md)
7. Herhaal stap 2–6 per story; branch blijft dezelfde
8. Queue leeg → `git push -u origin <branch>` + `gh pr create`

Volledige MCP-tool documentatie: [docs/runbooks/mcp-integration.md](./docs/runbooks/mcp-integration.md)

---

## Hardstop regels

- **Styling:** nooit `bg-blue-500`; altijd MD3-tokens (`bg-primary`, `bg-status-done`, …)
- **UI:** gebruik `@base-ui/react` met `render`-prop, niet Radix `asChild`
- **Push:** commits accumuleren lokaal per taak (`git add -A && git commit`); push + PR pas bij lege queue of na expliciete gebruikersbevestiging — zie [branch-and-commit.md](./docs/runbooks/branch-and-commit.md)
- **Demo:** drie lagen — proxy.ts + server action + UI disabled knop
- **Proxy:** `proxy.ts` in repo-root (géén `middleware.ts`) onverzegelt de iron-session, redirect niet-geauthenticeerde users op `/dashboard|/products|/ideas`, en blokkeert niet-GET API-writes voor demo-users behalve `/api/cron/*`
- **Enum:** DB UPPER_SNAKE ↔ API lowercase — uitsluitend via `lib/task-status.ts`
- **Foutcodes:** 400 = parse-fout, 422 = Zod-validatie, 403 = demo-token
- **Server/client grens:** `*-server.ts` bevat DB/node-only; nooit importeren in client component
- **Worker/jobs:** `ClaudeJob` queue (`QUEUED → CLAIMED → RUNNING → DONE|FAILED|SKIPPED`); MCP-worker claimt via `wait_for_job` en sluit met `update_job_status` — zie [worker-idempotency.md](./docs/runbooks/worker-idempotency.md)
- **Model/mode per ClaudeJob:** kind-default → product → job-snapshot → `task.requires_opus`. Resolver in `scrum4me-mcp/src/lib/job-config.ts` (en gespiegeld in `lib/job-config.ts`) — zie [job-model-selection.md](./docs/runbooks/job-model-selection.md)
- **Deployment:** `npm run verify && npm run build` vóór elke PR. Selectieve deploy-controle (labels + path-filter): zie [docs/runbooks/deploy-control.md](./docs/runbooks/deploy-control.md)

---

## Stack

| Laag | Technologie |
|---|---|
| Framework | Next.js 16.2 (App Router) + React 19.2 — PPR/Cache Components beschikbaar |
| Taal | TypeScript strict |
| Styling | Tailwind CSS v4 + shadcn/ui + MD3 via `app/styles/theme.css` |
| State | Zustand + dnd-kit |
| DB | Prisma v7.8 + PostgreSQL (Neon) |
| Auth | iron-session + bcryptjs |
| Test | Vitest (`__tests__/`, config in `vitest.config.ts`) |
| Utilities | Zod, Sonner, Sharp, Vercel Analytics |

---

## Patterns quickref

| Patroon | Bestand |
|---|---|
| iron-session | `docs/patterns/iron-session.md` |
| Prisma singleton | `docs/patterns/prisma-client.md` |
| Server Action (auth + Zod) | `docs/patterns/server-action.md` |
| Route Handler (REST) | `docs/patterns/route-handler.md` |
| Workspace-store + realtime (PBI-74) | `docs/patterns/workspace-store.md` |
| Zustand optimistic update | `docs/patterns/zustand-optimistic.md` |
| Float sort_order / drag-and-drop | `docs/patterns/sort-order.md` |
| Proxy / route protection | `docs/patterns/proxy.md` |
| QR-pairing | `docs/patterns/qr-login.md` |
| Claude ↔ user vraagkanaal | `docs/patterns/claude-question-channel.md` |
| Entity Dialog (verplicht) | `docs/patterns/dialog.md` |
| Realtime NOTIFY-payload | `docs/patterns/realtime-notify-payload.md` |
| Story met UI-component | `docs/patterns/story-with-ui-component.md` |
| Web Push | `docs/patterns/web-push.md` |
| Job-config resolver (PBI-67) | `lib/job-config.ts` ↔ `scrum4me-mcp/src/lib/job-config.ts` |
| Debug-id op component-root | `docs/patterns/debug-id.md` |
| Debug-labels (BEM) | `docs/patterns/debug-labels.md` |
| Demo client-state (PBI-80) | `docs/patterns/demo-client-state.md` |

---

## Env vars

```bash
DATABASE_URL=""    # postgresql://...
DIRECT_URL=""      # pooler-bypass voor LISTEN/NOTIFY
SESSION_SECRET=""  # min 32 chars
CRON_SECRET=""     # Bearer-secret /api/cron/*
```

Volledig schema: `lib/env.ts`. Canonieke lijst: `.env.example` — bevat ook web-push (`VAPID_*`, `INTERNAL_PUSH_SECRET`), Sentry (`SENTRY_*`) en optioneel `ANTHROPIC_API_KEY`.

---

## MCP & cron

- **MCP-server (extern):** standalone Node-proces in `~/Development/scrum4me-mcp/` — Prisma-schema gesynced via `sync-schema.sh`. 30+ tools (`get_claude_context`, `wait_for_job`, `update_task_status`, …)
- **Bewuste duplicaten:** `lib/job-config.ts` (deze repo) en `scrum4me-mcp/src/lib/job-config.ts` (externe MCP) bevatten dezelfde resolver-logica; dit voorkomt dat de MCP-server Next-deps importeert. **Wijzig beide** bij elke job-config aanpassing
- **Cron (vercel.json):**
  - `/api/cron/expire-questions` — dagelijks 04:00 UTC
  - `/api/cron/cleanup-agent-artifacts` — dagelijks 03:00 UTC
- **Realtime:** SSE op `/api/realtime/*`, gevoed door PostgreSQL `LISTEN`/`NOTIFY` op kanaal `scrum4me_changes` (vereist `DIRECT_URL` voor pooler-bypass)

---

## Scrum-terminologie

PBI (niet: Feature/Epic) · Story (niet: Ticket) · Sprint Goal (niet: Objective)

---

## Verificatie

```bash
npm run verify && npm run build   # verify = lint + typecheck + test
```

Worker job-status protocol (wanneer `DONE` / `SKIPPED` / `FAILED`): zie [docs/runbooks/worker-idempotency.md](./docs/runbooks/worker-idempotency.md).

### Scripts

| Commando | Doel |
|---|---|
| `npm run dev` | Next dev op poort 3000 (`predev` kill-port draait automatisch) |
| `npm test` | Vitest eenmalig (`vitest run`) |
| `npm run test:watch` | Vitest watch-mode |
| `npm test -- <pad>` | Eén bestand draaien — bv. `npm test -- lib/env` |
| `npm run seed` | Prisma seed via `prisma/seed.ts` |
| `npm run create-admin` | Admin-user toevoegen (`scripts/create-admin.ts`) |
| `npm run db:insert-milestone` | Milestone-script (`scripts/insert-milestone.ts`) |
| `npm run db:sync-model-prices` | Sync Anthropic-model-prijzen — vereist `ANTHROPIC_API_KEY` |
| `npm run docs` | Regenereer `docs/INDEX.md` + check links |
| `npm run diagrams` | Mermaid → SVG (`public/diagrams/architecture-{light,dark}.svg`) |

> Vitest sluit `.claude/**` uit (relevant voor worktrees). `server-only` wordt via alias gemockt naar `tests/stubs/server-only.ts`, zodat `*-server.ts` modules laadbaar zijn in jsdom-tests.
