* docs(dialog-pattern): add generic entity-dialog spec Introduceert docs/patterns/dialog.md als bron-of-truth voor elke create/edit/detail-dialog in Scrum4Me, ongeacht het achterliggende dataobject. Bevat 14 secties: uitgangspunten, stack, component- architectuur, layout, validatie, drielaagse demo-policy, submission, dialog-gedrag, theming, footer, triggers/URL-state, per-entiteit profile-template, out-of-scope, en een verificatie-checklist. Registreert het patroon in CLAUDE.md "Implementatiepatronen"-tabel zodat Claude (en mensen) de spec verplicht raadplegen voor elke nieuwe dialog. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(dialog-pattern): convert task spec + add pbi/story entity-profiles Reduceert docs/scrum4me-task-dialog.md van 507 naar ~140 regels: alle gedeelde regels verhuisd naar docs/patterns/dialog.md, dit document bevat nu alleen Task-specifieke velden, URL-pattern, status-veld, server actions, triggers en bewuste out-of-scope-keuzes. Voegt twee nieuwe entity-profielen toe voor bestaande dialogen: - docs/scrum4me-pbi-dialog.md (PbiDialog: state-based, code+title-rij, PbiStatusSelect, geen delete in v1) - docs/scrum4me-story-dialog.md (StoryDialog: state-based, header met status/priority badges, inline activity-log, demo-readonly-fallback, inline-delete-confirm i.p.v. AlertDialog) Beide profielen documenteren expliciet de "Bekende gaps t.o.v. generieke spec" zodat opvolgende PR's de afwijkingen kunnen rechtzetten of bewust kunnen accorderen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Added pdevelopment docs * docs(plans): add docs-restructure plan for AI-optimized lookup Audit of existing 39 doc files (~10.700 lines) and a phased restructure proposal aimed at minimising the tokens an AI agent has to read to find the right reference. Captures resolved decisions on language (English), ADR template (Nygard default with MADR escape-hatch), index generator (node script), and folder taxonomy. Proposal status — fase 1 to follow. * docs(adr): add ADR scaffolding (templates, README, meta-ADR) Set up docs/adr/ as the canonical home for architecture decisions: - templates/nygard.md — default four-section format (Status, Context, Decision, Consequences) for one-way-door decisions. - templates/madr.md — MADR v4 with YAML front-matter and explicit Considered Options for decisions where rejected alternatives matter. - README.md — naming convention (NNNN-kebab-case), template-selection guidance (Nygard default; MADR for auth, queue mechanics, agent integration), status lifecycle, and ADR roster. - 0000-record-architecture-decisions.md — meta-ADR establishing the practice itself, in Nygard format. Backfilling existing implicit decisions (base-ui-over-radix, float sort_order, demo-user three-layer policy, etc.) is fase 6 of the docs-restructure plan. * feat(docs): add docs index generator + initial INDEX.md scripts/generate-docs-index.mjs walks docs/**/*.md, parses YAML front-matter (or first H1 fallback) and a Nygard-style ## Status section, then writes docs/INDEX.md with grouped tables for ADRs, Specs, Plans (with archive subsection), Patterns, and Other. Pure Node 20 (no external deps); idempotent — running it twice produces byte-identical output. Excludes adr/templates/, the ADR README, INDEX.md itself, and any *_*.md sidecar file. Wire-up: - package.json: docs:index → node scripts/generate-docs-index.mjs Initial run indexed 35 docs across the existing structure; the generated INDEX.md is committed so the table is reviewable in the PR before hooking generation into a pre-commit step. * chore: ignore Obsidian vault and personal sidecar files Add .obsidian/ (Obsidian vault config) and _*.md (personal sidecar notes) to .gitignore so the docs/ tree can serve as canonical source of truth while still being usable as an Obsidian vault for personal authoring. The docs index generator already excludes the same _*.md pattern from INDEX.md. * docs(plans): add PBI bulk-create spec for docs-restructure Machine-parseable spec for an executor that calls the scrum4me MCP (create_pbi → create_story → create_task) to seed the docs-restructure work into the DB. - Section 1 (Context) is the PBI description; serves as task-context via mcp__scrum4me__get_claude_context. - Section 2 lists the 6 resolved decisions (English, MD3+styling merged, solo-paneel merged, .Plans archived, Nygard ADR default, node index script). - Section 3 records what already shipped on this branch so the executor doesn't duplicate the ADR scaffolding or index generator. - Section 4 carries the structured YAML graph: 1 PBI, 8 stories (one per phase), 39 tasks. product_id is REPLACE_ME — fill before running. - YAML validated with PyYAML; field schema sanity-checked. * docs(junk-cleanup): remove stub patterns/test.md * docs(junk-cleanup): archive .Plans/ to docs/plans/archive/ * docs(front-matter): add YAML front-matter to docs/ root * docs(front-matter): add YAML front-matter to patterns/ * docs(front-matter): add YAML front-matter to plans + agent files * docs(index): regenerate INDEX.md after front-matter pass * docs(naming): drop scrum4me- prefix from doc filenames * docs(naming): lowercase API.md and MD3 filenames * docs(naming): rename plan file to kebab-case ASCII * docs(naming): rename middleware.md to proxy.md (next 16) * docs(naming): polish CLAUDE.md doc-index after renames * docs(taxonomy): scaffold topical folders under docs/ * docs(taxonomy): move spec files into docs/specs/ * docs(taxonomy): move design/api/qa/backlog/assets into folders * docs(taxonomy): move agent-instruction-audit into decisions/ * docs(split): break architecture.md into 6 topical files * docs(split): merge solo-paneel-spec into specs/functional.md * docs(split): merge md3-color-scheme into design/styling * docs(trim): extract branch/commit rules into runbook * docs(trim): extract MCP integration into runbook * docs(adr): add 0001-base-ui-over-radix * docs(adr): add 0002-float-sort-order * docs(adr): add 0003-one-branch-per-milestone * docs(adr): add 0004-status-enum-mapping * docs(adr): add 0005-iron-session-over-nextauth * docs(adr): add 0006-demo-user-three-layer-policy * docs(adr): add 0007-claude-question-channel-design * docs(adr): add 0008-agent-instructions-in-claude-md + update README index * docs(index): regenerate after ADR 0001-0008 * docs(glossary): add docs/glossary.md * chore(docs): regenerate INDEX.md in pre-commit hook * docs(readme): link INDEX + glossary + agent instructions * feat(docs): add doc-link checker script * chore(docs): wire docs:check-links and docs npm scripts * ci(docs): block merge on broken doc links * docs(links): fix broken cross-references after restructure --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21 KiB
| title | status | audience | language | last_updated | ||
|---|---|---|---|---|---|---|
| Scrum4Me — API Test Plan | active |
|
nl | 2026-05-03 |
Scrum4Me — API Test Plan
Versie: 1.0
Datum: 25 april 2026
Auteur: Jan Peter Visser
Status: Draft
1. Introduction
This document describes the test plan and test planning for the Scrum4Me API endpoints — the integration surface that Claude Code and external agents use to interact with the application. It covers strategy, scope, test cases, tooling, exit criteria, and a phased execution schedule.
The API consists of 7 endpoints that form the Definition of Done checkpoint: all 7 must pass curl-level verification before the project ships.
2. Objectives
| # | Objective |
|---|---|
| O-1 | Verify that all 7 API endpoints return correct responses for valid input |
| O-2 | Verify that unauthenticated requests are rejected with 401 |
| O-3 | Verify that demo users cannot perform write operations (403) |
| O-4 | Verify that cross-user access is impossible at every endpoint |
| O-5 | Verify that all Zod validation schemas reject malformed input with 400 |
| O-6 | Verify edge cases: resource-not-found (404), empty result sets, boundary values |
| O-7 | Produce executable curl scripts that satisfy the DoD requirement |
3. Scope
3.1 In scope
| Endpoint | Method | Auth type | Write | Demo check |
|---|---|---|---|---|
/api/products |
GET | Bearer token | No | No |
/api/products/:id/next-story |
GET | Bearer token | No | No |
/api/sprints/:id/tasks |
GET | Bearer token | No | No |
/api/stories/:id/tasks/reorder |
PATCH | Bearer token | Yes | Yes |
/api/stories/:id/log |
POST | Bearer token | Yes | Yes |
/api/tasks/:id |
PATCH | Bearer token | Yes | Yes |
/api/todos |
POST | Bearer token | Yes | Yes |
3.2 Out of scope
/api/profile/avatar(GET/POST) — session-cookie auth, separate concern- Server Actions (
actions/*.ts) — UI-layer, covered by separate acceptance testing - Frontend components and pages
- Database migrations and schema changes
- Performance and load testing
4. Test Strategy
4.1 Layers
The strategy uses two complementary test layers. Together they satisfy both the automated regression requirement and the DoD curl requirement.
┌─────────────────────────────────────────────────────────────────────┐
│ Layer 1 — Vitest Unit Tests (automated, mocked) │
│ Fast, deterministic, no external DB required │
│ Covers: auth, demo block, cross-user isolation, input validation │
├─────────────────────────────────────────────────────────────────────┤
│ Layer 2 — Curl Scripts (manual, real DB) │
│ Executable against localhost:3000 with seeded test data │
│ Covers: happy paths, response shape, DoD compliance │
└─────────────────────────────────────────────────────────────────────┘
No Playwright, no Jest — Vitest is already configured and the existing __tests__/api/security.test.ts establishes the mock pattern to follow.
4.2 Vitest approach
All unit tests mock two dependencies only:
vi.mock('@/lib/prisma', () => ({
prisma: { /* model methods as vi.fn() */ }
}))
vi.mock('@/lib/api-auth', () => ({
authenticateApiRequest: vi.fn()
}))
This approach:
- Tests route handler logic in isolation
- Keeps tests fast (no network/DB)
- Follows the pattern already validated in
security.test.ts - Does not fall into the mock/prod divergence trap because the mocked boundary (
authenticateApiRequest+prisma) is stable and narrow
4.3 Curl approach
A single shell script scripts/test-api.sh with:
- A
TOKENvariable set at the top (obtained from a seeded user via the UI) - One function per endpoint, each printing pass/fail based on HTTP status
- Run order that follows the Lars flow (read → write → verify)
4.4 Test data
The existing seed (prisma/seed.ts) creates:
lars— full-permission user, used as the primary test actordemo— read-only user, used for demo-block tests
A second regular user (tester) must be created manually (or added to the seed) to test cross-user isolation scenarios.
5. Test Cases
The following tables list every test case by endpoint. Each case has an ID, description, input, expected HTTP status, and which layer covers it.
TC format
| Field | Meaning |
|---|---|
| ID | Unique identifier, e.g. TC-P-01 (P = products) |
| Layer | V = Vitest, C = Curl |
| Input | What is sent |
| Expected | HTTP status + key response fields |
5.1 GET /api/products
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-P-01 | V | No token | No Authorization header | 401 |
| TC-P-02 | V | Invalid token | Bearer invalid123 |
401 |
| TC-P-03 | V | Revoked token | Valid hash but revoked_at set |
401 |
| TC-P-04 | V | Valid token, owns 2 products | Valid token, 2 products in DB | 200, array of 2 |
| TC-P-05 | V | Valid token, is team member | Valid token, member of product owned by other user | 200, includes that product |
| TC-P-06 | V | Valid token, no products | Valid token, no products in DB | 200, empty array |
| TC-P-07 | V | Archived products excluded | 1 active + 1 archived product | 200, array of 1 |
| TC-P-08 | V | Cross-user: other user's products not returned | Token for user A, products owned by user B | 200, empty array |
| TC-P-09 | C | Happy path (lars) | Lars' token | 200, ≥1 product |
5.2 GET /api/products/:id/next-story
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-NS-01 | V | No token | No Authorization header | 401 |
| TC-NS-02 | V | Invalid token | Bearer invalid |
401 |
| TC-NS-03 | V | Product not found / not accessible | Valid token, unknown product id | 404 |
| TC-NS-04 | V | No active sprint | Valid token, product with no ACTIVE sprint | 404 |
| TC-NS-05 | V | Active sprint, no IN_SPRINT stories | Valid token, sprint exists but 0 stories | 404 |
| TC-NS-06 | V | Returns highest-priority story | Valid token, 3 IN_SPRINT stories with tasks | 200, story with tasks array |
| TC-NS-07 | V | Cross-user: other user's product | Token for user A, product owned by user B | 404 |
| TC-NS-08 | C | Happy path (lars, active sprint) | Lars' token + DevPlanner product id | 200, story object |
5.3 GET /api/sprints/:id/tasks?limit=10
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-ST-01 | V | No token | No Authorization header | 401 |
| TC-ST-02 | V | Invalid token | Bearer invalid |
401 |
| TC-ST-03 | V | Sprint not found / not accessible | Valid token, unknown sprint id | 404 |
| TC-ST-04 | V | Cross-user: other user's sprint | Token for user A, sprint in user B's product | 404 |
| TC-ST-05 | V | Default limit applied | No ?limit param |
200, ≤10 tasks |
| TC-ST-06 | V | Custom limit respected | ?limit=3, sprint has 5 tasks |
200, exactly 3 tasks |
| TC-ST-07 | V | Limit boundary: limit=1 | Sprint has multiple tasks | 200, exactly 1 task |
| TC-ST-08 | V | Sprint with 0 tasks | Valid sprint, no tasks | 200, empty array |
| TC-ST-09 | C | Happy path (lars) | Lars' token + active sprint id + ?limit=10 |
200, tasks array |
5.4 PATCH /api/stories/:id/tasks/reorder
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-RO-01 | V | No token | No Authorization header | 401 |
| TC-RO-02 | V | Invalid token | Bearer invalid |
401 |
| TC-RO-03 | V | Demo user | Valid token, isDemo: true |
403 |
| TC-RO-04 | V | Story not found / not accessible | Valid token, unknown story id | 404 |
| TC-RO-05 | V | Cross-user: other user's story | Token for user A, story in user B's product | 404 |
| TC-RO-06 | V | Empty task_ids array | { "task_ids": [] } |
400 |
| TC-RO-07 | V | task_ids not array | { "task_ids": "abc" } |
400 |
| TC-RO-08 | V | task_ids contains IDs from different story | Valid token, mixed-story task IDs | 400 |
| TC-RO-09 | V | Happy path | Valid token + valid task_ids in new order | 200 |
| TC-RO-10 | C | Happy path (lars) | Lars' token + story id + ordered task ids | 200 |
5.5 POST /api/stories/:id/log
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-L-01 | V | No token | No Authorization header | 401 |
| TC-L-02 | V | Invalid token | Bearer invalid |
401 |
| TC-L-03 | V | Demo user | Valid token, isDemo: true |
403 |
| TC-L-04 | V | Story not found / not accessible | Valid token, unknown story id | 404 |
| TC-L-05 | V | Cross-user: other user's story | Token for user A, story in user B's product | 404 |
| TC-L-06 | V | Missing type field |
{ "content": "..." } |
400 |
| TC-L-07 | V | Unknown type value |
{ "type": "UNKNOWN", "content": "..." } |
400 |
| TC-L-08 | V | IMPLEMENTATION_PLAN — missing content | { "type": "IMPLEMENTATION_PLAN" } |
400 |
| TC-L-09 | V | IMPLEMENTATION_PLAN — happy path | { "type": "IMPLEMENTATION_PLAN", "content": "Approach: ..." } |
201 |
| TC-L-10 | V | TEST_RESULT — missing status | { "type": "TEST_RESULT", "content": "..." } |
400 |
| TC-L-11 | V | TEST_RESULT — invalid status | { "type": "TEST_RESULT", "content": "...", "status": "UNKNOWN" } |
400 |
| TC-L-12 | V | TEST_RESULT — happy path PASSED | { "type": "TEST_RESULT", "content": "...", "status": "PASSED" } |
201 |
| TC-L-13 | V | TEST_RESULT — happy path FAILED | { "type": "TEST_RESULT", "content": "...", "status": "FAILED" } |
201 |
| TC-L-14 | V | COMMIT — missing commit_hash | { "type": "COMMIT", "content": "...", "commit_message": "..." } |
400 |
| TC-L-15 | V | COMMIT — missing commit_message | { "type": "COMMIT", "content": "...", "commit_hash": "abc1234" } |
400 |
| TC-L-16 | V | COMMIT — happy path | { "type": "COMMIT", "content": "...", "commit_hash": "abc1234", "commit_message": "feat: ..." } |
201 |
| TC-L-17 | C | IMPLEMENTATION_PLAN (lars) | Lars' token + story id + IMPLEMENTATION_PLAN body | 201 |
| TC-L-18 | C | TEST_RESULT PASSED (lars) | Lars' token + story id + TEST_RESULT body | 201 |
| TC-L-19 | C | COMMIT (lars) | Lars' token + story id + COMMIT body | 201 |
5.6 PATCH /api/tasks/:id
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-T-01 | V | No token | No Authorization header | 401 |
| TC-T-02 | V | Invalid token | Bearer invalid |
401 |
| TC-T-03 | V | Demo user | Valid token, isDemo: true |
403 |
| TC-T-04 | V | Task not found | Valid token, unknown task id | 404 |
| TC-T-05 | V | Cross-user: task in other user's product | Token for user A, task in user B's product | 404 |
| TC-T-06 | V | Invalid status value | { "status": "UNKNOWN" } |
400 |
| TC-T-07 | V | Empty body (no recognized fields) | {} |
400 |
| TC-T-08 | V | Update status only | { "status": "IN_PROGRESS" } |
200 |
| TC-T-09 | V | Update implementation_plan only | { "implementation_plan": "Step 1: ..." } |
200 |
| TC-T-10 | V | Update both fields | { "status": "DONE", "implementation_plan": "..." } |
200 |
| TC-T-11 | V | Team member can update task | Token for team member (not owner), valid task | 200 |
| TC-T-12 | C | Update status to IN_PROGRESS (lars) | Lars' token + task id + { "status": "IN_PROGRESS" } |
200 |
| TC-T-13 | C | Update status to DONE (lars) | Lars' token + task id + { "status": "DONE" } |
200 |
5.7 POST /api/todos
| ID | Layer | Scenario | Input | Expected |
|---|---|---|---|---|
| TC-TD-01 | V | No token | No Authorization header | 401 |
| TC-TD-02 | V | Invalid token | Bearer invalid |
401 |
| TC-TD-03 | V | Demo user | Valid token, isDemo: true |
403 |
| TC-TD-04 | V | Missing title | { "product_id": "..." } |
400 |
| TC-TD-05 | V | Empty title | { "title": "" } |
400 |
| TC-TD-06 | V | Without product_id (global todo) | { "title": "My todo" } |
201 |
| TC-TD-07 | V | With valid product_id | { "title": "My todo", "product_id": "..." } |
201 |
| TC-TD-08 | V | With product_id not accessible to user | { "title": "...", "product_id": "<other user's product>" } |
403 or 404 |
| TC-TD-09 | C | Happy path without product (lars) | Lars' token + { "title": "Test todo" } |
201 |
| TC-TD-10 | C | Happy path with product (lars) | Lars' token + { "title": "...", "product_id": "..." } |
201 |
6. Test Files
| File | Endpoints covered | Layer |
|---|---|---|
__tests__/api/security.test.ts |
products (GET), tasks/:id (PATCH) — already exists, extend | V |
__tests__/api/products.test.ts |
GET /api/products — happy paths + edge cases | V |
__tests__/api/next-story.test.ts |
GET /api/products/:id/next-story | V |
__tests__/api/sprint-tasks.test.ts |
GET /api/sprints/:id/tasks | V |
__tests__/api/story-log.test.ts |
POST /api/stories/:id/log | V |
__tests__/api/reorder.test.ts |
PATCH /api/stories/:id/tasks/reorder | V |
__tests__/api/tasks.test.ts |
PATCH /api/tasks/:id | V |
__tests__/api/todos.test.ts |
POST /api/todos | V |
scripts/test-api.sh |
All 7 endpoints | C |
7. Exit Criteria
The test phase is complete when all of the following are met:
| Criterion | Target |
|---|---|
| All Vitest tests pass | npm test exits 0 |
| No test is skipped or pending | 0 skipped |
| All curl scripts return expected HTTP codes | 100% pass rate on scripts/test-api.sh |
| Demo user blocked on all 4 write endpoints | Verified via TC-RO-03, TC-L-03, TC-T-03, TC-TD-03 |
| Cross-user access impossible | Verified via TC-P-08, TC-NS-07, TC-ST-04, TC-RO-05, TC-L-05, TC-T-05, TC-TD-08 |
| Security review passed | No cross-user data leak found in any endpoint |
8. Risks & Mitigations
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Mock divergence: mocked Prisma behavior differs from real DB | Medium | High | Keep mocked boundary narrow (only prisma.* calls, not business logic); validate happy paths with curl against real DB |
| Seed data insufficient for cross-user tests | Medium | Medium | Add a second test user tester to prisma/seed.ts |
| API token not available during curl tests | Low | High | Document token creation step clearly in test-api.sh header |
| Zod schema changes break test expectations | Low | Low | Vitest tests will catch this immediately on next npm test run |
| Reorder scope validation not fully covered | Medium | High | TC-RO-08 explicitly tests mixed-story IDs; add to security review checklist |
9. Dependencies
prisma/seed.tsmust create (or document creation of) a second user for cross-user testsscripts/directory must exist before running the curl script- A valid API token must be obtained from a seeded
larsuser session before running curl tests npm testmust be runnable without a live database (all Vitest tests mock Prisma)
Test Planning
Overview
| Phase | What | Duration | Start | End |
|---|---|---|---|---|
| P0 | Setup & shared infrastructure | 0.5 day | 2026-04-28 | 2026-04-28 |
| P1 | Security & auth layer (Vitest) | 1 day | 2026-04-29 | 2026-04-29 |
| P2 | Per-endpoint unit tests (Vitest) | 2 days | 2026-04-30 | 2026-05-01 |
| P3 | Curl scripts | 0.5 day | 2026-05-02 | 2026-05-02 |
| P4 | Review, edge cases, DoD verification | 0.5 day | 2026-05-05 | 2026-05-05 |
Total: 4.5 days
Phase 0 — Setup & Infrastructure (2026-04-28)
Goal: Everything required to write and run tests is in place.
Tasks
| ID | Task | Deliverable |
|---|---|---|
| P0-1 | Add tester user to prisma/seed.ts with no shared products |
Updated seed file |
| P0-2 | Create scripts/ directory with test-api.sh skeleton (TOKEN var, helper functions, empty cases) |
scripts/test-api.sh |
| P0-3 | Verify npm test runs cleanly on security.test.ts |
Green CI |
| P0-4 | Create __tests__/api/ test file skeletons (empty describe blocks) for each new file |
7 new .test.ts files |
Done when: npm test passes, all skeleton files exist, seed creates 3 users (demo, lars, tester).
Phase 1 — Security & Auth Layer (2026-04-29)
Goal: All auth (401), demo-block (403), and cross-user isolation test cases pass for all endpoints.
Tasks
| ID | Task | Test cases | File |
|---|---|---|---|
| P1-1 | Extend security.test.ts — add missing endpoints to auth/demo/cross-user coverage |
TC-NS-01–03,07 / TC-ST-01–04 / TC-RO-01–05 / TC-L-01–05 / TC-TD-01–03,08 | security.test.ts |
| P1-2 | Verify all 401 cases return { error: 'Unauthorized' } |
TC-P-01–03 etc. | security.test.ts |
| P1-3 | Verify all 403 demo cases return { error: 'Niet beschikbaar in demo-modus' } |
TC-RO-03, TC-L-03, TC-T-03, TC-TD-03 | security.test.ts |
| P1-4 | Verify cross-user returns empty array or 404 (not 403) for read endpoints | TC-P-08, TC-NS-07, TC-ST-04 | security.test.ts |
Done when: All P1 test cases green, 0 skipped. Security test file covers all 7 endpoints.
Phase 2 — Per-Endpoint Unit Tests (2026-04-30 – 2026-05-01)
Goal: Happy paths, input validation, and edge cases covered per endpoint.
Day 1 (2026-04-30) — Read endpoints
| ID | Task | Test cases | File |
|---|---|---|---|
| P2-1 | products.test.ts — happy paths, empty result, archived filter |
TC-P-04–07,09 | products.test.ts |
| P2-2 | next-story.test.ts — happy path, no sprint, no stories |
TC-NS-04–06,08 | next-story.test.ts |
| P2-3 | sprint-tasks.test.ts — happy path, limit param, empty sprint |
TC-ST-05–09 | sprint-tasks.test.ts |
Day 2 (2026-05-01) — Write endpoints
| ID | Task | Test cases | File |
|---|---|---|---|
| P2-4 | story-log.test.ts — all 3 log types, each field validation |
TC-L-06–16 | story-log.test.ts |
| P2-5 | reorder.test.ts — happy path, empty array, mixed-story IDs |
TC-RO-06–09 | reorder.test.ts |
| P2-6 | tasks.test.ts — status update, plan update, both, invalid status, team member access |
TC-T-06–11 | tasks.test.ts |
| P2-7 | todos.test.ts — with/without product_id, empty title |
TC-TD-04–07 | todos.test.ts |
Done when: All Vitest files pass, npm test exits 0 with ≥60 test cases across all files.
Phase 3 — Curl Scripts (2026-05-02)
Goal: scripts/test-api.sh covers all 7 endpoints and all curl test cases pass against localhost.
Tasks
| ID | Task | Test cases | |
|---|---|---|---|
| P3-1 | Implement curl script for GET endpoints (products, next-story, sprint-tasks) | TC-P-09, TC-NS-08, TC-ST-09 | |
| P3-2 | Implement curl script for write endpoints (reorder, log ×3, tasks ×2, todos ×2) | TC-RO-10, TC-L-17–19, TC-T-12–13, TC-TD-09–10 | |
| P3-3 | Add negative cases to curl script: no token (401), demo token (403) | TC-P-01, TC-TD-03 | |
| P3-4 | Run full script against seeded local DB, fix any failures | All C cases | |
| P3-5 | Document token acquisition steps in scripts/README.md or script header |
Done when: bash scripts/test-api.sh prints all PASS, no failures.
Phase 4 — Review & DoD Verification (2026-05-05)
Goal: Test suite is complete, DoD exit criteria are all met.
Tasks
| ID | Task |
|---|---|
| P4-1 | Run full npm test — verify 0 failures, 0 skipped |
| P4-2 | Run scripts/test-api.sh against staging/Neon DB — verify all PASS |
| P4-3 | Walk through security review checklist (cross-user access per endpoint) |
| P4-4 | Verify demo user is blocked on all 4 write endpoints via curl |
| P4-5 | Update __tests__/lars-flow-checklist.md to reference the new curl script |
| P4-6 | Add test instructions to README (npm test, bash scripts/test-api.sh) |
| P4-7 | Commit test files per commit strategy (separate commits per layer) |
Done when: All exit criteria from section 7 are met. Test plan status → Approved.
Commit Plan
Following the strict commit strategy, test work is committed in these layers:
chore(tests): add tester user to prisma seed
test(security): extend security.test.ts to cover all 7 endpoints
test(products): add unit tests for GET /api/products
test(next-story): add unit tests for GET /api/products/:id/next-story
test(sprint-tasks): add unit tests for GET /api/sprints/:id/tasks
test(story-log): add unit tests for POST /api/stories/:id/log
test(reorder): add unit tests for PATCH /api/stories/:id/tasks/reorder
test(tasks): add unit tests for PATCH /api/tasks/:id
test(todos): add unit tests for POST /api/todos
chore(scripts): add test-api.sh curl test script
docs(tests): update README with test instructions
Summary Timeline
Week of 2026-04-28
Mon 28 Apr │ P0 — Setup & infrastructure
Tue 29 Apr │ P1 — Security & auth layer (Vitest)
Wed 30 Apr │ P2 Day 1 — Read endpoint unit tests
Thu 01 May │ P2 Day 2 — Write endpoint unit tests
Fri 02 May │ P3 — Curl scripts
Week of 2026-05-05
Mon 05 May │ P4 — Review, DoD verification, commit