docs: architectuur en spec bijgewerkt na implementatie

- Next.js 15 → 16 in architecture doc en stack-tabel
- ProductMember model toegevoegd aan datamodel-sectie en Prisma schema excerpt
- implementation_plan veld gedocumenteerd bij tasks tabel
- lib/product-access.ts en components/products|settings toegevoegd aan projectstructuur
- Functionele spec: MVP-scope bijgewerkt met teambeheer; scope-bullet uitnodigingsflow aangepast
- Rolbeheer-spec: acceptatiecriterium "geen effect in v1" vervangen door Developer-vereiste voor teams
- v2 backlog: multi-user item herschreven naar uitnodigingsflow (basis teambeheer is nu v1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-25 13:13:14 +02:00
parent 357b1e32e8
commit 45011a3347
3 changed files with 76 additions and 38 deletions

View file

@ -7,7 +7,7 @@
## Architectuursamenvatting
Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt gerenderd en gedeployed op Vercel. De database is PostgreSQL via Neon, aangestuurd via Prisma v7. Authenticatie is custom username/password via iron-session — geen externe auth-provider, geen e-mail. De REST API voor Claude Code-integratie loopt via Next.js Route Handlers, beveiligd met API-tokens. Drag-and-drop in de planningsschermen wordt afgehandeld door dnd-kit.
Scrum4Me is een desktop-first Next.js 16 webapplicatie die server-side wordt gerenderd en gedeployed op Vercel. De database is PostgreSQL via Neon, aangestuurd via Prisma v7. Authenticatie is custom username/password via iron-session — geen externe auth-provider, geen e-mail. De REST API voor Claude Code-integratie loopt via Next.js Route Handlers, beveiligd met API-tokens. Drag-and-drop in de planningsschermen wordt afgehandeld door dnd-kit.
---
@ -15,10 +15,10 @@ Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt ger
| Laag | Technologie | Rationale |
|---|---|---|
| Frontend framework | Next.js 15 (App Router) | Stabiel, wijdverbreid, naadloze Vercel-deployment; SSR vereist voor auth-cookie-management |
| UI runtime | React 19 | Standaard bij Next.js 15; brengt `useActionState`, `useFormStatus` en de React Compiler (experimenteel) mee — minder boilerplate bij Server Actions |
| Frontend framework | Next.js 16 (App Router) | Stabiel, wijdverbreid, naadloze Vercel-deployment; SSR vereist voor auth-cookie-management |
| UI runtime | React 19 | Standaard bij Next.js 16; brengt `useActionState`, `useFormStatus` en de React Compiler (experimenteel) mee — minder boilerplate bij Server Actions |
| Taal | TypeScript (strict) | Type-veiligheid is essentieel voor een solo developer zonder reviewlaag; vangt datamodel-mismatches vroeg |
| Client state | Zustand | Minimale boilerplate voor ephemere UI-staat (selectie, optimistische drag-and-drop volgorde); leeft naast Server Components zonder conflict; eenvoudig uitbreidbaar naar v2 teamgebruik |
| Client state | Zustand | Minimale boilerplate voor ephemere UI-staat (selectie, optimistische drag-and-drop volgorde); leeft naast Server Components zonder conflict |
| Styling | Tailwind CSS + shadcn/ui | Snelle iteratie; toegankelijke componentprimitieven; desktop-first layouts goed ondersteund |
| Database (cloud) | PostgreSQL via Neon | Serverless Postgres, gratis tier voldoende voor MVP; native PostgreSQL zonder vendor lock-in |
| ORM | Prisma v7 | Type-safe queries; PostgreSQL via adapter; migraties zijn deterministisch |
@ -192,6 +192,7 @@ Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt ger
| sprint_id | String | FK → sprints, nullable | Denormalisatie voor snellere queries |
| title | String | not null, max 200 | |
| description | String | nullable, max 1000 | |
| implementation_plan | String | nullable | Opgeslagen door Claude Code MCP via `PATCH /api/tasks/:id` |
| priority | Int | 14, not null | |
| sort_order | Float | not null | |
| status | Enum | TO_DO \| IN_PROGRESS \| DONE | |
@ -219,6 +220,22 @@ Scrum4Me is een desktop-first Next.js 15 webapplicatie die server-side wordt ger
---
### `product_members`
| Kolom | Type | Constraints | Noten |
|---|---|---|---|
| id | String (cuid) | PK | |
| product_id | String | FK → products (cascade delete) | |
| user_id | String | FK → users (cascade delete) | |
| created_at | DateTime | default now() | |
**Indexes:** `(user_id)` — opzoeken van producten waarbij een gebruiker lid is
**Constraint:** unique `(product_id, user_id)` — één lidmaatschap per gebruiker per product
Koppelt Developer-gebruikers aan een product backlog. De eigenaar (`products.user_id`) heeft altijd volledige toegang; via `product_members` kunnen aanvullende Developers leesrechten en schrijfrechten op stories, taken en sprints van dat product krijgen. Rollen worden niet opgeslagen in deze tabel — dat doet `user_roles`. Een gebruiker kan alleen worden toegevoegd als hij/zij de rol `DEVELOPER` heeft.
---
## Prisma Schema (excerpt)
```prisma
@ -265,16 +282,17 @@ enum SprintStatus {
}
model User {
id String @id @default(cuid())
username String @unique
password_hash String
is_demo Boolean @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
roles UserRole[]
api_tokens ApiToken[]
products Product[]
todos Todo[]
id String @id @default(cuid())
username String @unique
password_hash String
is_demo Boolean @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
roles UserRole[]
api_tokens ApiToken[]
products Product[]
todos Todo[]
product_members ProductMember[]
}
model UserRole {
@ -299,19 +317,21 @@ model ApiToken {
}
model Product {
id String @id @default(cuid())
user User @relation(fields: [user_id], references: [id], onDelete: Cascade)
id String @id @default(cuid())
user User @relation(fields: [user_id], references: [id], onDelete: Cascade)
user_id String
name String
description String?
repo_url String?
definition_of_done String
archived Boolean @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
archived Boolean @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
pbis Pbi[]
sprints Sprint[]
stories Story[]
todos Todo[]
members ProductMember[]
@@unique([user_id, name])
@@index([user_id, archived])
@ -385,18 +405,19 @@ model Sprint {
}
model Task {
id String @id @default(cuid())
story Story @relation(fields: [story_id], references: [id], onDelete: Cascade)
story_id String
sprint Sprint? @relation(fields: [sprint_id], references: [id])
sprint_id String?
title String
description String?
priority Int
sort_order Float
status TaskStatus @default(TO_DO)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
id String @id @default(cuid())
story Story @relation(fields: [story_id], references: [id], onDelete: Cascade)
story_id String
sprint Sprint? @relation(fields: [sprint_id], references: [id])
sprint_id String?
title String
description String?
implementation_plan String?
priority Int
sort_order Float
status TaskStatus @default(TO_DO)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@index([story_id, priority, sort_order])
@@index([sprint_id, status])
@ -417,6 +438,19 @@ model Todo {
@@index([user_id, done, archived])
@@index([user_id, product_id])
}
model ProductMember {
id String @id @default(cuid())
product Product @relation(fields: [product_id], references: [id], onDelete: Cascade)
product_id String
user User @relation(fields: [user_id], references: [id], onDelete: Cascade)
user_id String
created_at DateTime @default(now())
@@unique([product_id, user_id])
@@index([user_id])
@@map("product_members")
}
```
---
@ -488,12 +522,15 @@ scrum4me/
│ ├── split-pane/ # Gesplitst scherm component
│ ├── backlog/ # PBI- en story-componenten
│ ├── sprint/ # Sprint-componenten
│ ├── products/ # ProductForm, TeamManager, ArchiveProductButton
│ ├── settings/ # RoleManager, LeaveProductButton
│ └── dnd/ # dnd-kit wrappers
├── lib/
│ ├── prisma.ts # Prisma Client singleton
│ ├── session.ts # iron-session configuratie
│ ├── auth.ts # login/register/token helpers
│ ├── api-auth.ts # Bearer token middleware voor API
│ ├── product-access.ts # productAccessFilter helper (eigenaar of teamlid)
│ └── env.ts # Zod-gevalideerde env vars
├── stores/ # Zustand stores
│ ├── planner-store.ts # Optimistische drag-and-drop volgorde

View file

@ -330,7 +330,7 @@ De MVP is klaar wanneer Lars — de primaire persona — de volledige cyclus kan
## v2 Backlog (na MVP)
- [ ] Meerdere gebruikers per Scrum Team — uitgebreide auth, rol-gebaseerde permissies, uitnodigingsflow
- [ ] 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

View file

@ -7,13 +7,13 @@
## MVP-scopeverklaring
v1 is een single-user desktop-first fullstack webapplicatie waarmee een solo developer of klein Scrum Team meerdere softwareprojecten hiërarchisch kan plannen (product → PBI → story → taak), Sprints kan beheren via gesplitste schermen met drag-and-drop, en Claude Code kan integreren voor geautomatiseerde implementatieflows waarbij elk resultaat wordt vastgelegd in de story. De app is deployable op Vercel + Neon én volledig lokaal draaibaar.
v1 is een desktop-first fullstack webapplicatie waarmee een solo developer of klein Scrum Team meerdere softwareprojecten hiërarchisch kan plannen (product → PBI → story → taak), Sprints kan beheren via gesplitste schermen met drag-and-drop, en Claude Code kan integreren voor geautomatiseerde implementatieflows waarbij elk resultaat wordt vastgelegd in de story. Een Product Owner kan Developers (via gebruikersnaam) aan een product backlog koppelen; zij krijgen dan schrijfrechten op stories, taken en sprints van dat product. De app is deployable op Vercel + Neon én volledig lokaal draaibaar.
## Expliciet buiten scope voor v1
- Meerdere gebruikers per Scrum Team — datastructuur is voorbereid, UI en permissies komen in v2
- Uitnodigingsflow voor teams — Developers toevoegen via gebruikersnaam is beschikbaar; e-mailuitnodiging of link-gebaseerde onboarding komt in v2
- E-mailverificatie bij registratie — gebruikersnaam/wachtwoord volstaat voor v1
- Daily Scrum, Sprint Review en Sprint Retrospective schermen — v2 zodra teamgebruik mogelijk is
- Daily Scrum, Sprint Review en Sprint Retrospective schermen — v2
- Automatische statusupdate van stories na commit — handmatige update via UI in v1
- Tijdregistratie, urenverantwoording en burndown-charts — buiten positionering
- Integratie met externe tools (GitHub Issues, Linear, Jira) — v2
@ -60,14 +60,14 @@ Gebruikers kunnen een account aanmaken en inloggen met gebruikersnaam en wachtwo
**Persona:** Remi (v2), Lars en Dina (impliciet)
**Omschrijving:**
Een gebruiker kan bij registratie of in instellingen één of meerdere Scrum-rollen aannemen: Product Owner, Scrum Master, Developer. In v1 heeft dit geen effect op zichtbare functionaliteit maar de datastructuur ondersteunt rolscheiding voor v2-teamgebruik.
Een gebruiker kan bij registratie of in instellingen één of meerdere Scrum-rollen aannemen: Product Owner, Scrum Master, Developer. De rol Developer is relevant voor teambeheer: alleen gebruikers met de rol Developer kunnen aan een product backlog worden gekoppeld door de eigenaar.
**Acceptatiecriteria:**
- [ ] Gebruiker kan bij registratie of achteraf in instellingen rollen selecteren
- [ ] Minimaal één rol is verplicht
- [ ] Alle drie de rollen tegelijk zijn toegestaan
- [ ] Geselecteerde rollen zijn zichtbaar in de profielbalk
- [ ] Rolkeuze heeft in v1 geen effect op zichtbare functionaliteit
- [ ] Alleen gebruikers met de rol Developer kunnen als teamlid aan een product backlog worden gekoppeld
- [ ] Demo-gebruiker heeft een vaste rol (Developer) die niet gewijzigd kan worden
**Data:**
@ -386,7 +386,7 @@ De app is deployable op Vercel + Neon PostgreSQL en lokaal draaibaar met een Neo
/products/:id/sprint (Sprint Backlog — gesplitst scherm)
/products/:id/sprint/planning (Sprint Planning — gesplitst scherm)
/todos (todo-lijst)
/settings (profiel, rollen, API-tokens)
/settings (profiel, rollen, mijn teams, API-tokens)
/settings/tokens (API-tokenbeheer)
```
@ -406,6 +406,7 @@ De app is deployable op Vercel + Neon PostgreSQL en lokaal draaibaar met een Neo
| `sprints` | id, product_id, sprint_goal, status (ACTIVE / COMPLETED), created_at, completed_at? | Max. 1 actieve Sprint per product |
| `tasks` | id, story_id, sprint_id, title, description, implementation_plan?, priority, sort_order, status | Status: TO_DO / IN_PROGRESS / DONE; implementation_plan door MCP |
| `todos` | id, user_id, product_id, title, done, archived, created_at | Gekoppeld aan product backlog; verplicht in UI en API |
| `product_members` | id, product_id, user_id, created_at | Many-to-many; alleen Developers; eigenaar via products.user_id |
---