ST-509: selectie-checkbox voor bulk-archivering (archiveSelectedTodosAction), aparte rij-klik voor detail-kaart, paginatelling toegevoegd. ST-510: done-toggle in kaart, promote-knoppen in kaart (→ PBI / → Story), updateTodoAction dekt title + product_id + done. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
392 lines
31 KiB
Markdown
392 lines
31 KiB
Markdown
# Scrum4Me — Implementatie Backlog
|
||
|
||
**Versie:** 0.1 — april 2026
|
||
**Volgt op:** Functionele Specificatie v0.2, Architectuur v0.1
|
||
|
||
---
|
||
|
||
## MVP-definitie
|
||
|
||
De MVP is klaar wanneer Lars — de primaire persona — de volledige cyclus kan doorlopen: een product aanmaken, een Product Backlog opbouwen met PBI's en stories, een Sprint plannen, taken aanmaken, en Claude Code de volgende story laten ophalen, implementeren en vastleggen — allemaal zonder hulp of handleiding. De app draait stabiel op Vercel en is volledig lokaal opzetbaar via één README.
|
||
|
||
---
|
||
|
||
## Milestone-overzicht
|
||
|
||
| Milestone | Doel | Tasks |
|
||
|---|---|---|
|
||
| M0: Foundation | Project, database, auth, navigatieshell | ST-001 – ST-008 |
|
||
| M1: Producten & Product Backlog | Producten, PBI's, gesplitst scherm | ST-101 – ST-110 |
|
||
| M2: Stories & Drag-and-drop | Stories als blokken, dnd-kit, Zustand | ST-201 – ST-210 |
|
||
| M3: Sprint Backlog & Sprint Planning | Sprint aanmaken, stories slepen, taken | ST-301 – ST-312 |
|
||
| M4: Claude Code REST API | Alle endpoints, tokenbeheer | ST-401 – ST-410 |
|
||
| M5: Todo-lijst | Todo CRUD, promotie naar PBI/story; Data Table + detail-kaart | ST-501 – ST-506, ST-509 – ST-510 |
|
||
| M6: Polish & Launch-ready | Foutafhandeling, toegankelijkheid, CI/CD, beveiliging | ST-601 – ST-612 |
|
||
|
||
---
|
||
|
||
## Backlog
|
||
|
||
### M0: Foundation
|
||
|
||
- [ ] **ST-001** Project scaffolding
|
||
- `create-next-app` met TypeScript strict, Tailwind CSS, App Router; installeer shadcn/ui, Zustand, dnd-kit, iron-session, bcrypt, Zod; configureer path aliases (`@/`)
|
||
- Done when: `npm run dev` start zonder fouten; `npm run lint` geeft geen errors; shadcn `Button` rendert op een testpagina
|
||
|
||
- [ ] **ST-002** Prisma v7 setup + `prisma.config.ts`
|
||
- Installeer Prisma v7 + `@prisma/adapter-pg`; schrijf `prisma.config.ts` met `DATABASE_URL` via Zod-gevalideerde env; schrijf `lib/prisma.ts` singleton
|
||
- Done when: `npx prisma db push` slaagt; Prisma Client importeerbaar in een testbestand zonder fouten
|
||
|
||
- [ ] **ST-003** Database schema migratie (volledige initiële migratie)
|
||
- Schrijf het volledige `schema.prisma` op basis van het architectuurdocument: `User`, `UserRole`, `ApiToken`, `Product`, `Pbi`, `Story`, `StoryLog`, `Sprint`, `Task`, `Todo`; alle enums, indexes, cascade deletes
|
||
- Done when: `npx prisma migrate dev --name init` slaagt; alle tabellen zichtbaar in DB-client; `npx prisma validate` geeft geen fouten
|
||
|
||
- [ ] **ST-004** Seed met testdata
|
||
- Schrijf `prisma/seed.ts` op basis van het Product Backlog document (devplanner-product-backlog.md); seed één gebruiker, één product (Scrum4Me zelf), alle PBI's en stories als testdata; voeg demo-gebruiker toe
|
||
- Done when: `npx prisma db seed` slaagt; DB bevat alle PBI's en stories uit het backlog-document; demo-gebruiker aanwezig
|
||
|
||
- [ ] **ST-005** Environment variabelen + `lib/env.ts`
|
||
- Schrijf Zod-schema voor alle env vars (`DATABASE_URL`, `DIRECT_URL`, `SESSION_SECRET`, `NODE_ENV`); exporteer gevalideerd `env` object; schrijf `.env.example` met instructies
|
||
- Done when: app gooit een begrijpelijke fout bij ontbrekende env var; `.env.example` volledig gedocumenteerd
|
||
|
||
- [ ] **ST-006** Authenticatie — registratie en inloggen
|
||
- Schrijf `lib/auth.ts` (registreer met bcrypt hash, verifieer bij inloggen); schrijf `lib/session.ts` (iron-session config); implementeer `/register` en `/login` pagina's met Server Actions; sla `{ userId, isDemo }` op in sessiecookie
|
||
- Done when: registreren → ingelogde sessie → redirect `/dashboard`; inloggen met verkeerde credentials geeft generieke foutmelding; sessie blijft actief na paginaverversing
|
||
|
||
- [ ] **ST-007** Route-beveiliging via `proxy.ts`
|
||
- Schrijf `proxy.ts` die sessiecookie-aanwezigheid controleert; redirect naar `/login` bij alle `/dashboard`, `/products/*`, `/todos`, `/settings/*` routes zonder sessiecookie; authenticated users worden van `/login` en `/register` doorgestuurd naar `/dashboard`; volledige sessievalidatie gebeurt server-side in de app layout
|
||
- Done when: directe navigatie naar `/dashboard` zonder sessie redirect naar `/login`; ingelogde gebruiker op `/login` redirect naar `/dashboard`
|
||
|
||
- [ ] **ST-008** Navigatieshell + dashboard-layout
|
||
- Schrijf `app/(app)/layout.tsx` met navigatiebalk (logo, productenlink, todolink, instellingen, uitlogknop); implementeer uitlog Server Action; implementeer `/dashboard` als lege productenlijstpagina met "Maak je eerste product aan" lege staat; zet demo-badge zichtbaar als `isDemo === true`
|
||
- Done when: volledige auth-flow (register → login → dashboard → logout → login) werkt end-to-end; demo-gebruiker ziet badge in navigatie
|
||
|
||
---
|
||
|
||
### M1: Producten & Product Backlog
|
||
|
||
- [ ] **ST-101** Product aanmaken
|
||
- `/products/new` pagina met formulier (naam, beschrijving, repo URL, definition of done); `createProduct` Server Action met Zod-validatie; uniekheidscontrole op naam per gebruiker; redirect naar `/products/[id]` na aanmaken
|
||
- Done when: product aangemaakt en zichtbaar op dashboard; dubbele naam geeft inline validatiefout; lege naam blokkeert submit
|
||
|
||
- [ ] **ST-102** Productenlijst op dashboard
|
||
- Haal actieve producten op via Prisma Server Component; toon naam, beschrijving (ingekort 80 tekens), repo-link; lege staat met CTA; klikken opent Product Backlog
|
||
- Done when: twee producten zichtbaar na aanmaken; gearchiveerd product niet zichtbaar in standaardlijst
|
||
|
||
- [ ] **ST-103** Product bewerken en archiveren
|
||
- Bewerkformulier (naam, beschrijving, repo URL, DoD) via Server Action; archiveerknop met bevestigingsdialoog; hersteloptie voor gearchiveerde producten; "toon gearchiveerd"-filter op dashboard
|
||
- Done when: naam bijwerken persisteert; archiveren verbergt product; herstel maakt het weer zichtbaar
|
||
|
||
- [ ] **ST-104** Gesplitst scherm layout component (`SplitPane`)
|
||
- Bouw herbruikbaar `<SplitPane>` Client Component met versleepbare horizontale splitter; sla splitter-positie op in `localStorage` per sleutel; standaard 40/60 verhouding; minimale panelbreedte 200px; responsive fallback naar tabs op < 1024px
|
||
- Done when: splitter versleepbaar en positie behouden na paginaverversing; tabs getoond op smal scherm
|
||
|
||
- [ ] **ST-105** Navigatiebar-component per paneel
|
||
- Bouw herbruikbaar `<PanelNavBar>` component met slots voor knoppen (aanmaken, filter, verwijderen); consistent design voor linker- en rechterpaneel
|
||
- Done when: navigatiebar herbruikt in minimaal twee gesplitste schermen zonder duplicatie
|
||
|
||
- [ ] **ST-106** PBI aanmaken en weergeven
|
||
- Linkerpaneel van `/products/[id]`: haal PBI's op gegroepeerd op prioriteit en sort_order; "PBI aanmaken" knop opent inline formulier (titel, prioriteit); `createPbi` Server Action; nieuw PBI verschijnt onderaan de juiste prioriteitsgroep
|
||
- Done when: PBI aangemaakt en zichtbaar in juiste prioriteitsgroep; lege staat toont prompt
|
||
|
||
- [ ] **ST-107** PBI prioriteitsgroepen met visuele scheiding
|
||
- Render PBI's gegroepeerd per prioriteit (1–4) met gelabelde scheidingslijn per groep (bijv. "Kritiek", "Hoog"); lege groepen zijn niet zichtbaar; prioriteitsbadge per PBI
|
||
- Done when: vier prioriteitsgroepen correct gerenderd met labels; PBI met prioriteit 1 staat boven prioriteit 4
|
||
|
||
- [ ] **ST-108** PBI bewerken en verwijderen
|
||
- Inline bewerkingsmodus via dubbelklik of contextmenu (titel, omschrijving, prioriteit); `updatePbi` Server Action; verwijderen met bevestigingsdialoog inclusief waarschuwing cascade; `deletePbi` Server Action
|
||
- Done when: titelbewering opgeslagen zonder paginaverversing; verwijderen cascade-verwijdert stories (verifieerbaar in DB)
|
||
|
||
- [ ] **ST-109** PBI selecteren → stories laden
|
||
- Klikken op PBI in linkerpaneel toont bijbehorende stories rechts via `useSelectionStore`; geselecteerd PBI visueel gemarkeerd; lege staat rechts als geen stories
|
||
- Done when: klikken op PBI A toont stories van A rechts; klikken op PBI B schakelt direct over
|
||
|
||
- [ ] **ST-110** PBI filter
|
||
- Filterknop in linkerpaneel navigatiebar; dropdown voor prioriteit (1–4, alle); filter werkt realtime op gerenderde lijst; actief filter zichtbaar als badge; wissen via ×-knop
|
||
- Done when: filter op prioriteit 1 verbergt alle andere PBI's; wissen herstelt volledige lijst
|
||
|
||
---
|
||
|
||
### M2: Stories & Drag-and-drop
|
||
|
||
- [ ] **ST-201** `usePlannerStore` Zustand-store
|
||
- Schrijf `stores/planner-store.ts` met `pbiOrder`, `storyOrder`, `taskOrder`; `init*`, `reorder*`, `rollback*` actions; TypeScript strict types
|
||
- Done when: store importeerbaar in een Client Component; `initPbis` vult order; `reorderPbis` muteert order; `rollbackPbis` herstelt vorige staat
|
||
|
||
- [ ] **ST-202** `useSelectionStore` Zustand-store
|
||
- Schrijf `stores/selection-store.ts` met `selectedPbiId`, `selectedStoryId`, setters en `clearSelection`
|
||
- Done when: selectie in linkerpaneel via store zichtbaar in rechterpaneel zonder prop drilling
|
||
|
||
- [ ] **ST-203** dnd-kit setup + PBI drag-and-drop
|
||
- Installeer dnd-kit; wrap linkerpaneel in `DndContext` + `SortableContext`; implementeer `useSortable` per PBI-rij; `onDragEnd`: bereken nieuwe `sort_order` via float-gemiddelde; optimistisch updaten via `usePlannerStore`; `reorderPbisAction` Server Action; rollback bij fout
|
||
- Done when: PBI versleepbaar binnen prioriteitsgroep; volgorde opgeslagen na loslaten; UI rollback bij gesimuleerde server-fout
|
||
|
||
- [ ] **ST-204** PBI drag-and-drop over prioriteitsgrens
|
||
- Uitbreiding ST-203: slepen over een prioriteitsgrens wijzigt `priority` van het PBI; `sort_order` wordt onderaan de doelgroep geplaatst; `updatePbiPriority` Server Action
|
||
- Done when: PBI naar prioriteit 2 slepen vanuit prioriteit 3 wijzigt zowel prioriteit als volgorde
|
||
|
||
- [ ] **ST-205** Story aanmaken en weergeven als blokken
|
||
- Rechterpaneel van Product Backlog: haal stories op voor geselecteerd PBI; render als blokken (~10% schermbreedte, horizontaal); elk blok toont titel (ingekort), prioriteitsbadge, statusbadge; "Story aanmaken" knop; `createStory` Server Action
|
||
- Done when: drie stories zichtbaar als blokken; nieuw blok verschijnt in juiste prioriteitsgroep
|
||
|
||
- [ ] **ST-206** Story prioriteitsgroepen met visuele scheiding
|
||
- Groepeer story-blokken per prioriteit; gekleurde band of scheidingslijn per groep; blokken horizontaal gerangschikt per rij; nieuwe rij bij overloop
|
||
- Done when: stories van vier prioriteiten correct gescheiden weergegeven
|
||
|
||
- [ ] **ST-207** Story drag-and-drop (horizontaal, binnen en tussen groepen)
|
||
- dnd-kit horizontale `SortableContext` per prioriteitsgroep; `onDragEnd`: herrangschikking via float-gemiddelde in `storyOrder`; slepen naar andere groep wijzigt prioriteit; optimistisch via `usePlannerStore`; `reorderStoriesAction` Server Action; rollback bij fout
|
||
- Done when: story versleepbaar binnen groep en naar andere groep; volgorde en prioriteit persistent na loslaten
|
||
|
||
- [ ] **ST-208** Story detail-modal / slide-over
|
||
- Klikken op storyblok opent slide-over of modal met titel, omschrijving, acceptatiecriteria, statusbadge, activiteitenlog (leeg bij nieuwe story); bewerkformulier voor titel/omschrijving/acceptatiecriteria; `updateStory` Server Action
|
||
- Done when: klikken op blok opent detail; bewerken persisteert; sluiten keert terug naar backlog
|
||
|
||
- [ ] **ST-209** Story verwijderen
|
||
- Verwijderknop in story-detail of contextmenu; bevestigingsdialoog met waarschuwing cascade (taken); `deleteStory` Server Action; blok verdwijnt optimistisch uit het rechterpaneel
|
||
- Done when: story verwijderd incl. cascade-taken (verifieerbaar in DB); blok direct verdwenen uit UI
|
||
|
||
- [ ] **ST-210** Story filter in rechterpaneel
|
||
- Filterknop in rechterpaneel navigatiebar; filter op status (OPEN, IN_SPRINT, DONE) en prioriteit; realtime; actief filter als badge; wissbaar
|
||
- Done when: filter op OPEN verbergt IN_SPRINT stories
|
||
|
||
---
|
||
|
||
### M3: Sprint Backlog & Sprint Planning
|
||
|
||
- [ ] **ST-301** `useSprintStore` Zustand-store
|
||
- Schrijf `stores/sprint-store.ts`; `initSprint`, `addStoryToSprint`, `removeStoryFromSprint`, `reorderSprintStories`, `rollbackSprint`
|
||
- Done when: store beheert sprint-story-volgorde onafhankelijk van planner-store
|
||
|
||
- [ ] **ST-302** Sprint aanmaken
|
||
- "Sprint starten" knop op productpagina (zichtbaar als geen actieve Sprint); modal met Sprint Goal invoerveld; `createSprint` Server Action; max. 1 actieve Sprint per product afgedwongen in service-laag
|
||
- Done when: Sprint aangemaakt met Goal; tweede sprint aanmaken terwijl eerste actief is geeft foutmelding
|
||
|
||
- [ ] **ST-303** Sprint Backlog scherm — layout
|
||
- `/products/[id]/sprint` pagina; `SplitPane` met Sprint Backlog links (stories in Sprint op volgorde) en rechts de Product Backlog stories gegroepeerd per PBI (inklapbaar); Sprint Goal zichtbaar bovenaan; lege staat links met instructie
|
||
- Done when: pagina rendert correct; Sprint Goal zichtbaar; beide panelen tonen juiste data
|
||
|
||
- [ ] **ST-304** Story vanuit Product Backlog naar Sprint slepen
|
||
- dnd-kit drag vanuit rechterpaneel naar linkerpaneel; `onDragEnd`: `addStoryToSprint` in store; story krijgt badge "In Sprint" in Product Backlog; `addStoryToSprintAction` Server Action (zet `sprint_id` + status `IN_SPRINT`); rollback bij fout
|
||
- Done when: story gesleept naar Sprint verschijnt links en toont "In Sprint" badge rechts; persistent na herlaad
|
||
|
||
- [ ] **ST-305** Sprint Backlog story volgorde aanpassen
|
||
- dnd-kit verticale `SortableContext` in linkerpaneel; herrangschikking via float-gemiddelde in `useSprintStore`; `reorderSprintStoriesAction` Server Action
|
||
- Done when: volgorde in Sprint Backlog persistent na loslaten en na paginaverversing
|
||
|
||
- [ ] **ST-306** Story uit Sprint verwijderen
|
||
- Verwijderknop per story in Sprint Backlog; `removeStoryFromSprintAction` Server Action (wist `sprint_id`, zet status terug op `OPEN`); story verdwijnt links en badge verdwijnt rechts
|
||
- Done when: verwijderen persistent; story beschikbaar in Product Backlog rechterpaneel
|
||
|
||
- [ ] **ST-307** Sprint Planning scherm — layout
|
||
- `/products/[id]/sprint/planning` pagina; `SplitPane` met Sprint Backlog stories links (op volgorde) en taken van geselecteerde story rechts; Sprint Goal zichtbaar; lege staat rechts als geen story geselecteerd
|
||
- Done when: pagina rendert; story selecteren links toont taken rechts
|
||
|
||
- [ ] **ST-308** Taak aanmaken
|
||
- "Taak aanmaken" knop in rechterpaneel navigatiebar; inline formulier (titel, omschrijving, prioriteit); `createTask` Server Action; voortgangsindicator per story (bijv. "0/0 Done")
|
||
- Done when: taak aangemaakt en zichtbaar in takenlijst; voortgangsindicator toont "0/1 Done"
|
||
|
||
- [ ] **ST-309** Taak drag-and-drop (verticaal)
|
||
- dnd-kit verticale `SortableContext` in rechterpaneel; herrangschikking via float-gemiddelde in `usePlannerStore.taskOrder`; `reorderTasksAction` Server Action
|
||
- Done when: taken versleepbaar; volgorde persistent na loslaten
|
||
|
||
- [ ] **ST-310** Taakstatus bijhouden
|
||
- Status-toggle per taak (TO_DO → IN_PROGRESS → DONE) via klikbare badge of dropdown; `updateTaskStatus` Server Action; voortgangsindicator op story updatet optimistisch
|
||
- Done when: taak op DONE zetten verhoogt teller in voortgangsindicator; persistent na herlaad
|
||
|
||
- [ ] **ST-311** Taak bewerken en verwijderen
|
||
- Inline bewerken van titel, omschrijving en prioriteit; `updateTask` Server Action; verwijderen met bevestiging; `deleteTask` Server Action
|
||
- Done when: titelwijziging persisteert; verwijderde taak verdwijnt uit lijst
|
||
|
||
- [ ] **ST-312** Sprint afronden
|
||
- "Sprint afronden" knop op Sprint-pagina; dialoog toont per story de status en vraagt: "Markeer als Done of terug naar Backlog?"; `completeSprint` Server Action zet Sprint op COMPLETED, verwerkt keuzes per story
|
||
- Done when: Sprint afgerond; stories correct verplaatst naar DONE of OPEN; nieuwe Sprint aanmaakbaar
|
||
|
||
---
|
||
|
||
### M4: Claude Code REST API
|
||
|
||
- [ ] **ST-401** API-token infrastructuur
|
||
- Schrijf `lib/api-auth.ts`: parseer `Authorization: Bearer` header; bereken SHA-256 hash; zoek op in `api_tokens`; controleer `revoked_at`; retourneer `userId` of 401; retourneer 403 als `is_demo`
|
||
- Done when: geldige token geeft userId terug; ongeldige token geeft 401; ingetrokken token geeft 401; demo-token op schrijf-endpoint geeft 403
|
||
|
||
- [ ] **ST-402** API-tokenbeheer UI
|
||
- `/settings/tokens` pagina; token aanmaken (label optioneel); token eenmalig getoond in kopieerbaar veld na aanmaken; tokenoverzicht (label, datum, actief/ingetrokken); intrekken via Server Action; max. 10 actieve tokens
|
||
- Done when: token aangemaakt en waarde zichtbaar; na sluiten dialoog niet meer te zien; intrekken maakt token onbruikbaar (getest via curl)
|
||
|
||
- [ ] **ST-403** `GET /api/products` — productenlijst
|
||
- Route Handler; authenticatie via `api-auth.ts`; retourneer actieve producten `[{ id, name, repo_url }]` als JSON voor producten waar de tokengebruiker eigenaar of teamlid is
|
||
- Done when: `curl -H "Authorization: Bearer <token>" /api/products` retourneert correct JSON inclusief gedeelde product backlogs; 401 zonder token
|
||
|
||
- [ ] **ST-404** `GET /api/products/:id/next-story` — volgende story ophalen
|
||
- Route Handler; haal hoogst geprioriteerde OPEN story op van actieve Sprint van het product (priority ASC, sort_order ASC); retourneer `{ id, title, description, acceptance_criteria, tasks[] }`; 404 als geen open stories
|
||
- Done when: endpoint retourneert eerste story van Sprint; 404 als Sprint leeg; 404 als geen actieve Sprint
|
||
|
||
- [ ] **ST-405** `GET /api/sprints/:id/tasks` — taken ophalen
|
||
- Route Handler met `?limit=N` query param (default 10, max 50); retourneer taken van actieve Sprint op `(story.sort_order, task.priority, task.sort_order)` volgorde; retourneer `{ id, title, story_id, priority, sort_order, status }`
|
||
- Done when: endpoint retourneert max N taken in juiste volgorde; `?limit=5` retourneert max 5
|
||
|
||
- [ ] **ST-406** `PATCH /api/stories/:id/tasks/reorder` — taakvolgorde aanpassen
|
||
- Route Handler; body: `{ task_ids: string[] }`; valideer alle IDs behoren tot de story; update `sort_order` via float-verdeling; retourneer `{ success: true }`
|
||
- Done when: volgorde in DB veranderd na PATCH; gewijzigde volgorde zichtbaar in Sprint Planning UI na herlaad; ongeldige task_id geeft 400
|
||
|
||
- [ ] **ST-407** `POST /api/stories/:id/log` — activiteit vastleggen
|
||
- Route Handler; body: `{ type, content, status?, commit_hash?, commit_message? }`; Zod-validatie per type; schrijf naar `story_logs`; retourneer `{ id, created_at }`
|
||
- Done when: drie typen werken (IMPLEMENTATION_PLAN, TEST_RESULT, COMMIT); log-entry zichtbaar in story-detail UI na aanmaken via API; ontbrekend verplicht veld geeft 400
|
||
|
||
- [ ] **ST-408** `PATCH /api/tasks/:id` — taakstatus en implementatieplan bijwerken
|
||
- Route Handler; body: `{ status?: "TO_DO" | "IN_PROGRESS" | "DONE", implementation_plan?: string }`; minimaal één veld verplicht; valideer dat taak aan requester's product behoort; retourneer `{ id, status, implementation_plan }`
|
||
- Done when: status update via API zichtbaar in Sprint Planning UI; implementation_plan opgeslagen en opvraagbaar; lege body geeft 400; andere gebruikers taak geeft 403
|
||
|
||
- [ ] **ST-409** `POST /api/todos` — todo aanmaken
|
||
- Route Handler; body: `{ title: string, product_id: string }`; valideer dat product bij de geverifieerde gebruiker hoort; schrijf naar `todos`; retourneer `{ id, title, created_at }`
|
||
- Done when: todo aangemaakt via API met product_id verschijnt in todo-lijst UI gekoppeld aan het juiste product; lege titel of ontbrekend product_id geeft 400; onbekend product geeft 404
|
||
|
||
- [ ] **ST-410** Story-activiteitenlog UI
|
||
- Activiteitenlog sectie in story-detail slide-over; haal `story_logs` op via Server Component; render chronologisch; visuele stijl per type (IMPLEMENTATION_PLAN = blauw, TEST_RESULT passed = groen, failed = rood, COMMIT = paars); commit-hash klikbaar als `repo_url` ingesteld; lege staat
|
||
- Done when: drie log-entries (plan, test, commit) correct gestyled; commit-hash link opent in nieuw tabblad
|
||
|
||
---
|
||
|
||
### M5: Todo-lijst
|
||
|
||
> **Herontwerp (april 2026):** ST-501–505 beschreven de oorspronkelijke QuickInput-aanpak. Die is geïmplementeerd maar vervangen door een Data Table + detail-kaart ontwerp (ST-509–510). ST-501–505 zijn als referentie bewaard; de functionele eisen zijn ongewijzigd.
|
||
|
||
- [x] **ST-501** Todo-lijst pagina *(vervangen door ST-509)*
|
||
- `/todos` pagina; haal actieve (niet-gearchiveerde) todos op inclusief productnaam; snel-invoerveld bovenaan met product-dropdown (verplicht) en titel (Enter om op te slaan); `createTodo` Server Action; lege staat met instructie; productnaam-badge per todo-item
|
||
- Done when: todo aanmaken via Enter persisteert en verschijnt in lijst met productnaam; aanmaken zonder product geblokkeerd; lege staat zichtbaar bij geen todos
|
||
|
||
- [x] **ST-502** Todo afvinken *(vervangen door ST-509)*
|
||
- Checkbox per todo; `toggleTodo` Server Action; afgevinkte todos visueel doorgestreept; afgevinkte todos blijven zichtbaar onderaan de lijst
|
||
- Done when: afvinken persistent na herlaad; visuele doorstreping correct
|
||
|
||
- [x] **ST-503** Afgevinkte todos archiveren *(vervangen door ST-510)*
|
||
- "Archiveer afgeronde items" knop; `archiveCompletedTodos` Server Action; gearchiveerde todos verdwijnen uit standaardweergave
|
||
- Done when: archiveren verbergt alle afgevinkte todos; telling correct
|
||
|
||
- [x] **ST-504** Todo promoveren naar PBI *(vervangen door ST-510)*
|
||
- "Promoveer naar PBI" contextmenu of knop per todo; dialoog: product dropdown (actieve producten), prioriteit dropdown; titel vooringevuld (bewerkbaar); bevestigingswaarschuwing; `promoteTodeToPbi` Server Action (maak PBI aan, verwijder todo)
|
||
- Done when: gepromoveerde todo verdwijnt; PBI zichtbaar in juist product met juiste prioriteit
|
||
|
||
- [x] **ST-505** Todo promoveren naar story *(vervangen door ST-510)*
|
||
- "Promoveer naar story" knop per todo; dialoog: product dropdown → PBI dropdown (gefilterd op product), prioriteit; titel vooringevuld; `promoteTodoToStory` Server Action (maak story aan, verwijder todo)
|
||
- Done when: gepromoveerde todo verdwijnt; story zichtbaar in juist PBI met juiste prioriteit
|
||
|
||
- [ ] **ST-509** Todo Data Table
|
||
- Installeer `@tanstack/react-table`; voeg shadcn `data-table`-patroon toe
|
||
- **Kolommen:**
|
||
- Selectie-checkbox (kolom 1): multi-select voor bulk-archivering; header-checkbox selecteert/deselecteert alle zichtbare rijen
|
||
- Titel (kolom 2): max 2 regels, `line-clamp-2 truncate`; afgevinkte todos doorgestreept; klik op rij (buiten checkbox) opent detail-kaart
|
||
- Productnaam-badge (kolom 3)
|
||
- Aanmaakdatum (kolom 4)
|
||
- **Toolbar boven de tabel:**
|
||
- Product-filter dropdown (Alles / Geen product / per product)
|
||
- "+" knop: opent lege detail-kaart voor nieuw aanmaken (erft geselecteerd filter-product)
|
||
- "Archiveer geselecteerde (N)" knop: actief zodra ≥ 1 checkbox aangevinkt; roept `archiveSelectedTodosAction` aan met de geselecteerde IDs; resettet selectie na afloop
|
||
- **Paginering:** max 10 rijen per pagina; vorige/volgende knoppen; paginatelling ("1–10 van 23")
|
||
- **Lege staat:** "Geen todo's voor deze selectie." bij lege filter; "Nog geen todo's. Gebruik + om er een aan te maken." bij volledig lege lijst
|
||
- **`archiveSelectedTodosAction`** toevoegen aan `actions/todos.ts`: valideert dat alle meegegeven IDs bij de ingelogde gebruiker horen vóór schrijven; `archiveMany` via `updateMany`
|
||
- Done when: tabel toont alle actieve todos; paginering werkt; product-filter werkt; selectie-checkbox selecteert meerdere rijen; bulk-archiveren verwijdert geselecteerde rijen uit de weergave
|
||
|
||
- [ ] **ST-510** Todo detail-kaart
|
||
- Kaart onder de tabel; altijd zichtbaar (leeg als geen todo geselecteerd of aangemaakt wordt)
|
||
- **Aanmaken:** "+" in toolbar zet kaart in aanmaak-modus; velden: product-dropdown (erft filter-product, of "Geen product" bij "Alles"), titel; opslaan via `createTodoAction`; na opslaan kaart leegmaken en tabel ververst
|
||
- **Bewerken:** klik op tabelrij (buiten checkbox) laadt todo in kaart; velden: product-dropdown, titel, done-toggle; opslaan via nieuwe `updateTodoAction` (title + product_id + done); annuleren deselecteert rij en leegt kaart
|
||
- **Promoveren:** knoppen "→ PBI" en "→ Story" in de kaart; openen de bestaande `PromotePbiDialog` en `PromoteStoryDialog`; alleen zichtbaar bij een bestaande geselecteerde todo
|
||
- **Demo-modus:** kaart-invoervelden uitgeschakeld; knoppen verborgen of disabled
|
||
- **`updateTodoAction`** toevoegen aan `actions/todos.ts`: valideert eigenaarschap; past `title`, `product_id` en/of `done` aan; `revalidatePath('/todos')`
|
||
- Done when: aanmaken via kaart persisteert; bewerken van titel, product en done-status werkt; promote vanuit kaart opent juist dialoog en verwijdert todo na bevestiging; kaart leeg bij geen selectie; demo-gebruiker ziet uitgeschakelde kaart
|
||
|
||
- [ ] **ST-506** Rolbeheer in instellingen
|
||
- `/settings` pagina met roltoewijzing (checkbox per rol: Product Owner, Scrum Master, Developer); minimaal één rol verplicht; `updateRoles` Server Action; geselecteerde rollen zichtbaar in profielbalk
|
||
- Done when: rollen bijwerken persisterend; profielbalk toont gekozen rollen; uitvinken van alle rollen geeft validatiefout
|
||
|
||
- [x] **ST-507** Gebruikersprofiel (buiten originele backlog toegevoegd)
|
||
- Profielfoto-upload (JPEG/PNG/WebP, max 12 MB), server-side resizing naar max 700×700 WebP met Sharp, opgeslagen als bytea in Neon; bio (max 160) en bio_detail (max 2000) als aparte velden; `POST /api/profile/avatar` + `GET /api/profile/avatar` + `updateProfileAction`
|
||
- Done when: foto geüpload en zichtbaar in instellingen; bio opgeslagen; ongeldige bestanden geweigerd vóór verwerking
|
||
|
||
- [x] **ST-508** Product Backlog-overzicht in instellingen (buiten originele backlog toegevoegd)
|
||
- Gecombineerde lijst op `/settings` van eigen producten (badge "Eigenaar") en team-lidmaatschappen (badge "Developer" + eigenaarsnaam); klikbaar naar product; "Verlaten"-knop met bevestiging voor lidmaatschappen; lege staat met CTA
|
||
- Done when: eigenaar-producten en team-producten zichtbaar in één lijst; verlaten werkt en verwijdert rij
|
||
|
||
---
|
||
|
||
### M6: Polish & Launch-ready
|
||
|
||
- [ ] **ST-601** Loading states en skeletons
|
||
- `loading.tsx` voor alle zware routes (`/products/[id]`, `/sprint`, `/sprint/planning`); skeletoncomponenten voor PBI-lijst, story-blokken en takenlijst; pending states op alle form-submit-knoppen via `useFormStatus`
|
||
- Done when: navigeren naar een trage route toont skeleton; submit-knoppen disablen tijdens Server Action
|
||
|
||
- [ ] **ST-602** Error boundaries
|
||
- `error.tsx` voor alle beschermde routes; toon gebruiksvriendelijke foutmelding met "Probeer opnieuw" knop; log fout naar console (Sentry in M6)
|
||
- Done when: gesimuleerde Server Action-fout toont error boundary zonder witte pagina
|
||
|
||
- [ ] **ST-603** Toast-notificaties (Sonner)
|
||
- Installeer Sonner; success-toast na aanmaken/bewerken/verwijderen van producten, PBI's, stories, taken, todos; error-toast bij mislukte Server Actions; toast niet bij drag-and-drop (te frequent)
|
||
- Done when: aanmaken van PBI toont success-toast; gesimuleerde netwerk-fout toont error-toast
|
||
|
||
- [ ] **ST-604** Demo-gebruiker write-protection in UI
|
||
- Alle aanmaak-, bewerk- en verwijderknoppen disabled + tooltip "Niet beschikbaar in demo-modus" voor demo-sessies; gebaseerd op `isDemo` in sessie
|
||
- Done when: demo-gebruiker ziet alle knoppen maar kan niets wijzigen; tooltip zichtbaar bij hover
|
||
|
||
- [ ] **ST-605** Keyboard-navigatie
|
||
- Tab-volgorde logisch in alle formulieren; Enter submits formulieren; Escape sluit modals/slide-overs; dnd-kit keyboard-drag (Space om te pakken, pijltjestoetsen, Space om te laten vallen)
|
||
- Done when: volledige PBI aanmaken-flow keyboard-only uitvoerbaar; dnd-kit drag via keyboard werkt
|
||
|
||
- [ ] **ST-606** Desktop-first UI-review
|
||
- Test alle flows op 1280px, 1440px en 1920px breedte; fix overflow, uitlijning en proportie-issues; controleer minimum schermbreedte 1024px (toon melding bij smaller)
|
||
- Done when: alle M0–M5 flows correct op drie schermbreedtes; melding bij < 1024px
|
||
|
||
- [ ] **ST-607** Toegankelijkheid (WCAG AA)
|
||
- Kleurcontrast-check op alle tekst en badges; aria-labels op icon-only knoppen; focus-ring zichtbaar op alle interactieve elementen; `role` en `aria-selected` op geselecteerde PBI in linkerpaneel
|
||
- Done when: geen WCAG AA contrastfouten op primaire flows; alle knoppen hebben toegankelijke labels
|
||
|
||
- [ ] **ST-608** Ratelimiting op auth-endpoints
|
||
- Max. 10 inlogpogingen per IP per minuut; max. 5 registraties per IP per uur; implementeer via in-memory counter (v1) of Vercel Edge middleware
|
||
- Done when: 11 snelle inlogpogingen leiden tot 429-respons met duidelijke melding
|
||
|
||
- [ ] **ST-609** Beveiligingsreview API-endpoints
|
||
- Controleer alle Route Handlers: elke schrijfoperatie valideert dat de resource binnen de toegankelijke product-scope valt; cross-scope reads zijn onmogelijk tenzij de gebruiker via `product_members` gekoppeld is; voeg integratietests toe die cross-user toegang testen
|
||
- Done when: poging om een niet-gedeeld product van een andere gebruiker op te halen via API geeft 403 of 404; gedeelde producten zijn wel zichtbaar; getest met twee test-gebruikers
|
||
|
||
- [ ] **ST-610** CI/CD via GitHub Actions
|
||
- Workflow: `lint` (ESLint), `typecheck` (tsc --noEmit), `prisma validate`, `build` (next build) op elke PR en push naar main; Vercel auto-deploy op main
|
||
- Done when: een TypeScript-fout in een PR blokkeert merge; succesvolle merge triggert Vercel-deploy
|
||
|
||
- [ ] **ST-611** README en lokale setup-documentatie
|
||
- Schrijf `README.md` met: wat is Scrum4Me, quickstart lokaal (clone → env → prisma push → seed → dev), cloud deployment (Vercel + Neon stappenplan), API-documentatie (alle 7 endpoints met voorbeelden), Claude Code-integratie uitleg, Vercel Analytics status en directe dependencies zoals Sharp
|
||
- De in-app landingspagina (`/`) bevat al een gebruikershandleiding, Scrum-samenvatting en API-overzicht — de README richt zich op lokale setup en deployment
|
||
- Done when: iemand zonder context de app lokaal kan draaien op basis van alleen de README en `.env.example`
|
||
|
||
- [ ] **ST-612** End-to-end acceptatietest
|
||
- Voer handmatig de volledige Lars-flow uit: product aanmaken → PBI's en stories aanmaken → Sprint starten → stories slepen → taken aanmaken → API-token aanmaken → curl `next-story` → curl `log` (plan, test, commit) → activiteitenlog controleren in UI
|
||
- Done when: volledige flow werkt zonder fouten of onverwacht gedrag; alle API-responses correct JSON
|
||
|
||
---
|
||
|
||
## v2 Backlog (na MVP)
|
||
|
||
- [ ] Uitnodigingsflow voor teams — e-mailuitnodiging of link-gebaseerd; nu kunnen alleen admins met toegang tot het systeem Developers toevoegen via gebruikersnaam
|
||
- [ ] Daily Scrum scherm — voortgang per story bijhouden tijdens Sprint
|
||
- [ ] Sprint Review scherm — demo en feedback vastleggen per story
|
||
- [ ] Sprint Retrospective scherm — reflectie per Sprint
|
||
- [ ] Automatische story-statusupdate na commit via API
|
||
- [ ] Velocity tracking — statistieken over meerdere Sprints
|
||
- [ ] Definition of Done per product configureerbaar (nu vaste instelling)
|
||
- [ ] Notificaties / reminders
|
||
- [ ] Timeline / kalenderweergave per Sprint
|
||
- [ ] Integratie GitHub Issues / Linear
|
||
- [ ] Mobiele app — uitsluitend taken afvinken
|
||
- [ ] Export van Product Backlog en Sprint als markdown of CSV
|
||
|
||
---
|
||
|
||
## Definition of MVP Done
|
||
|
||
- [ ] Alle M0–M6 tasks afgerond
|
||
- [ ] Volledige Lars-flow succesvol doorlopen (ST-612)
|
||
- [ ] Alle 7 API-endpoints getest via curl (ST-403 t/m ST-409)
|
||
- [ ] Demo-gebruiker kan inloggen en heeft geen schrijfrechten (ST-604)
|
||
- [ ] App lokaal opzetbaar via README zonder extra hulp (ST-611)
|
||
- [ ] CI/CD actief — falende build blokkeert merge (ST-610)
|
||
- [ ] Beveiligingsreview API geslaagd (ST-609)
|
||
- [ ] Geen bekende blocker-bugs
|