From 7529fd54bc721fed2c2212c9eb23a63712ef6273 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 14:11:53 +0200 Subject: [PATCH 1/4] docs: CHANGELOG.md (Keep a Changelog) + README quick-start fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHANGELOG.md: Keep-a-Changelog formaat met [Unreleased], [0.9.0]-release, en compact-historie. Klaar voor v1.0.0 release-notes. README: - Test-count 69 → 445 (was outdated) - Quick-start claim over auto-erd-watch in `npm run dev` corrigeren (npm run db:erd:watch is optioneel, niet automatisch) - Env-vars-tabel uitgebreid: CRON_SECRET (productie), Sentry DSN + source-map vars (optioneel) - CHANGELOG-link in Documentation-sectie Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 10 +++++-- 2 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..939d598 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,85 @@ +# Changelog + +All notable changes to **Scrum4Me** are documented in this file. + +The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [Unreleased] + +### Added +- A11y: rate-limit `enforceUserRateLimit(scope, userId)` helper applied to all + high-value mutation paths (PBI/Story/Task/Todo/Sprint/Product/Token create, + Claude job enqueue, answerQuestion, story-log POST, avatar upload). + ([#86](https://github.com/madhura68/Scrum4Me/pull/86)) +- Sentry error-monitoring scaffolding (`@sentry/nextjs`) with no-op fallback + when DSN is not configured. Activate via `NEXT_PUBLIC_SENTRY_DSN` in Vercel + env-vars. ([#85](https://github.com/madhura68/Scrum4Me/pull/85)) + +### Changed +- A11y: `aria-selected` on PBI-cards replaced with `aria-pressed` (correct + ARIA role-attribute pairing). ([#88](https://github.com/madhura68/Scrum4Me/pull/88)) +- A11y: form-label associations (`htmlFor` + `id`) on all happy-path dialogs + (Story/Task + Promote-PBI/Story); auth pages get `
` landmark. + ([#87](https://github.com/madhura68/Scrum4Me/pull/87)) +- A11y: tap-targets ≥28×28 px on hover-icon-buttons (PBI ✎ + ×, Story ✎, + dashboard product ✎). ([#88](https://github.com/madhura68/Scrum4Me/pull/88)) + +--- + +## [0.9.0] — 2026-05-04 + +[GitHub Release](https://github.com/madhura68/Scrum4Me/releases/tag/v0.9.0) + +### Added +- **PBI-11: Mobile-shell met landscape-lock** ([#81](https://github.com/madhura68/Scrum4Me/pull/81)): + - Aparte route group `app/(mobile)/m/{settings,pair,products}/...` met eigen + layout (zonder NavBar/StatusBar/MinWidthBanner) + - `LandscapeGuard` (rotate-overlay in portrait), `MobileTabBar` (3 lucide-iconen) + - PWA-manifest met `"orientation": "landscape"` + - UA-redirect bij login: telefoons (`Mobi`-substring) → `/m/products/[active]/solo`, + tablets en desktop → `/dashboard` + - Gedeelde `lib/auth-guard.ts` `requireSession()` helper, hergebruikt door beide layouts + - Mobile-fullscreen voor entity-dialogen via gedeelde `entityDialogContentClasses` +- Sprint Product-Backlog kolom: filter-popover (prioriteit + status) en + edit-iconen op PBI/story/task-rijen. ([#79](https://github.com/madhura68/Scrum4Me/pull/79)) +- Edit-icoon op product-card in dashboard (consistent met PBI/story/task-pattern). + ([#83](https://github.com/madhura68/Scrum4Me/pull/83)) +- v1.0 readiness checklist in `docs/plans/v1-readiness.md`. + ([#82](https://github.com/madhura68/Scrum4Me/pull/82)) + +### Changed +- Refactor `app/(app)/layout.tsx` om gedeelde `requireSession()` te gebruiken + (gedrag onveranderd). ([#81](https://github.com/madhura68/Scrum4Me/pull/81)) +- `/m/pair` filesystem-verhuisd uit `(app)/` naar `(mobile)/` — URL onveranderd. + ([#81](https://github.com/madhura68/Scrum4Me/pull/81)) + +--- + +## [0.4.0] — eerder + +### Added +- M9 — Actief Product Backlog: persistente actieve PB-keuze, gesplitste + navigatie, disabled-states bij geen actief product + +--- + +## [0.3.1] — eerder + +Initiële stabilisatie-release. + +--- + +## Pre-0.3.x + +Foundation-werk (M0 t/m M8) is niet retroactief in dit changelog opgenomen. +Voor de volledige milestone-historie zie [docs/backlog/index.md](./docs/backlog/index.md). + +--- + +[Unreleased]: https://github.com/madhura68/Scrum4Me/compare/v0.9.0...HEAD +[0.9.0]: https://github.com/madhura68/Scrum4Me/releases/tag/v0.9.0 +[0.4.0]: https://github.com/madhura68/Scrum4Me/commit/615f0c8 +[0.3.1]: https://github.com/madhura68/Scrum4Me/commit/ecc05dd diff --git a/README.md b/README.md index 1f2da30..4de7224 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Scrum4Me biedt een lichtgewicht, web-based oplossing voor het beheren van sprint ## Documentation +- [CHANGELOG.md](CHANGELOG.md) — release-historie (Keep a Changelog) - [docs/INDEX.md](docs/INDEX.md) — generated index of all docs (front-matter driven) - [docs/glossary.md](docs/glossary.md) — domain terms (PBI, Story, MCP-job, etc.) - [CLAUDE.md](CLAUDE.md) / [AGENTS.md](AGENTS.md) — agent instructions @@ -152,7 +153,7 @@ npm run dev npm test ``` -Verwacht: alle 69 tests slagen, 0 failures. +Verwacht: alle 445 tests slagen, 0 failures. **API curl-tests (vereist lopende dev server + API token):** @@ -175,7 +176,7 @@ Handmatige generatie: npm run db:erd ``` -Tijdens lokale development draait `npm run dev` naast Next.js ook `npm run db:erd:watch`. Bij wijzigingen in `prisma/schema.prisma` wordt `docs/assets/erd.svg` automatisch opnieuw gegenereerd. +Optioneel: `npm run db:erd:watch` parallel aan `npm run dev` om bij wijzigingen in `prisma/schema.prisma` `docs/assets/erd.svg` automatisch opnieuw te genereren. Gebruik `npx prisma db push` alleen om het schema naar de database te synchroniseren. Gebruik `npm run db:erd` om lokaal Prisma Client en de ERD te genereren. Gebruik in CI uitsluitend `npx prisma generate --generator client`. @@ -198,8 +199,11 @@ Zie [.env.example](.env.example). | Variabele | Verplicht | Doel | |---|---:|---| | `DATABASE_URL` | Ja | PostgreSQL connection string voor Prisma | -| `DIRECT_URL` | Nee | Directe Neon connection string voor migraties | +| `DIRECT_URL` | Nee | Directe Neon connection string voor migraties (Prisma `directUrl`) | | `SESSION_SECRET` | Ja | Minimaal 32 tekens; gebruikt door iron-session | +| `CRON_SECRET` | Productie | Bearer-secret voor `/api/cron/*` routes — required als crons aan staan | +| `NEXT_PUBLIC_SENTRY_DSN` | Nee | Sentry DSN — zonder is de SDK een no-op | +| `SENTRY_ORG` / `SENTRY_PROJECT` / `SENTRY_AUTH_TOKEN` | Nee | Source-map upload tijdens build | | `NODE_ENV` | Nee | Wordt door Node/Vercel gezet | Vercel Analytics gebruikt geen project-specifieke environment variabele in deze app; de component staat in `app/layout.tsx`. From 95eff4087c61d3e973b236b6dbea142faea22aac Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 14:14:01 +0200 Subject: [PATCH 2/4] fix(demo): close 3 demo-policy gaps in mutation actions (before-launch) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit van alle Server Actions revealed drie mutation-paden zonder isDemo-check, terwijl de demo-policy zegt "demo-user is read-only": - toggleTodoAction: demo kon eigen todos done/undone toggelen - archiveCompletedTodosAction: demo kon todos archiveren (bulk) - leaveProductAction: demo kon productMembership verlaten Fix: standaard `if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }` toegevoegd, conform de andere mutation-actions. Andere claim/unclaim/reassign/updateTaskPlan-actions zijn al gedekt via requireProductWriter() → requireWriter() → demo-throw — nu code-side geverifieerd voor de hele actions/-tree. Co-Authored-By: Claude Opus 4.7 (1M context) --- actions/products.ts | 1 + actions/todos.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/actions/products.ts b/actions/products.ts index f238058..9a0856b 100644 --- a/actions/products.ts +++ b/actions/products.ts @@ -366,6 +366,7 @@ export async function removeProductMemberAction(productId: string, memberId: str export async function leaveProductAction(productId: string) { const session = await getSession() if (!session.userId) return { error: 'Niet ingelogd' } + if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' } await prisma.$transaction([ prisma.user.updateMany({ diff --git a/actions/todos.ts b/actions/todos.ts index 3c68da9..7720eb4 100644 --- a/actions/todos.ts +++ b/actions/todos.ts @@ -47,6 +47,7 @@ export async function createTodoAction(_prevState: unknown, formData: FormData) export async function toggleTodoAction(id: string, done: boolean) { const session = await getSession() if (!session.userId) return { error: 'Niet ingelogd' } + if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' } const todo = await prisma.todo.findFirst({ where: { id, user_id: session.userId } }) if (!todo) return { error: 'Todo niet gevonden' } @@ -59,6 +60,7 @@ export async function toggleTodoAction(id: string, done: boolean) { export async function archiveCompletedTodosAction() { const session = await getSession() if (!session.userId) return { error: 'Niet ingelogd' } + if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' } await prisma.todo.updateMany({ where: { user_id: session.userId, done: true, archived: false }, From 0f40bc1c706252009dcfaafe64c75d0df9520c32 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 14:16:49 +0200 Subject: [PATCH 3/4] fix(privacy): NODE_ENV-guard 4 debug-routes (before-launch privacy review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Privacy/PII review-pass van Server Actions, API-routes, debug-paths en Sentry config: ✅ Sentry sendDefaultPii: false in alle drie configs (server/edge/client) ✅ Geen wachtwoord/email/token in console-logs ✅ Pair-id-logs zijn metadata-only (5-min TTL, geen secret) ⚠️ Vier debug-routes hadden geen auth-guard: - /api/debug/realtime-stream — rauwe pg_notify-stream zonder filtering - /api/debug/emit-test-notify — anonieme test-emit op het kanaal - /debug-env — lekt env-var-metadata (hostnames, lengtes, pooled-flag) - /debug-realtime — UI op dezelfde rauwe pg_notify-stream Allemaal gemarkeerd als TIJDELIJK met VERWIJDEREN-comments uit M8. Voor v1 launch: NODE_ENV-guard die in productie 404 retourneert. Lokaal dev blijft alles werken voor debugging. Toekomstige cleanup: kunnen worden verwijderd zodra M8-realtime stabiel draait in productie en niemand ze meer nodig heeft. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/api/debug/emit-test-notify/route.ts | 5 +++++ app/api/debug/realtime-stream/route.ts | 5 +++++ app/debug-env/page.tsx | 4 ++++ app/debug-realtime/page.tsx | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/app/api/debug/emit-test-notify/route.ts b/app/api/debug/emit-test-notify/route.ts index e480258..ae1de28 100644 --- a/app/api/debug/emit-test-notify/route.ts +++ b/app/api/debug/emit-test-notify/route.ts @@ -12,6 +12,11 @@ export const dynamic = 'force-dynamic' const CHANNEL = 'scrum4me_changes' export async function POST(request: Request) { + // Productie-guard: anonieme test-emit op pg_notify is niet voor productie. + if (process.env.NODE_ENV === 'production') { + return new Response('Not found', { status: 404 }) + } + const directUrl = process.env.DIRECT_URL ?? process.env.DATABASE_URL if (!directUrl) { return Response.json({ error: 'DIRECT_URL/DATABASE_URL niet gezet' }, { status: 500 }) diff --git a/app/api/debug/realtime-stream/route.ts b/app/api/debug/realtime-stream/route.ts index e909bfc..1a02765 100644 --- a/app/api/debug/realtime-stream/route.ts +++ b/app/api/debug/realtime-stream/route.ts @@ -16,6 +16,11 @@ export const maxDuration = 300 const CHANNEL = 'scrum4me_changes' export async function GET(request: NextRequest) { + // Productie-guard: deze debug-stream lekt rauw alle pg_notify-events. + if (process.env.NODE_ENV === 'production') { + return new Response('Not found', { status: 404 }) + } + const directUrl = process.env.DIRECT_URL ?? process.env.DATABASE_URL if (!directUrl) { return Response.json({ error: 'DIRECT_URL/DATABASE_URL niet gezet' }, { status: 500 }) diff --git a/app/debug-env/page.tsx b/app/debug-env/page.tsx index e8d0c47..3e653b2 100644 --- a/app/debug-env/page.tsx +++ b/app/debug-env/page.tsx @@ -5,6 +5,7 @@ // VERWIJDEREN zodra env-config op Vercel bevestigd is. import { headers } from 'next/headers' +import { notFound } from 'next/navigation' export const dynamic = 'force-dynamic' export const runtime = 'nodejs' @@ -45,6 +46,9 @@ function inspectSecret(name: string, raw: string | undefined): VarStatus { } export default async function DebugEnvPage() { + // Productie-guard: lekt env-var-metadata (hostnames, lengtes, pooled-flag). + if (process.env.NODE_ENV === 'production') notFound() + // Force dynamic so each visit reads runtime env (niet build-time gecached) await headers() diff --git a/app/debug-realtime/page.tsx b/app/debug-realtime/page.tsx index 4dc28f3..f28124e 100644 --- a/app/debug-realtime/page.tsx +++ b/app/debug-realtime/page.tsx @@ -5,11 +5,15 @@ // // VERWIJDEREN VOOR M8 OUT-OF-DRAFT. +import { notFound } from 'next/navigation' import { DebugRealtimeClient } from './client' export const dynamic = 'force-dynamic' export default function DebugRealtimePage() { + // Productie-guard: deze pagina toont rauwe pg_notify-events zonder auth. + if (process.env.NODE_ENV === 'production') notFound() + return (

Realtime debug — scrum4me_changes

From b225c83ace40842718e27090f9b1d3fe4d1b3d22 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 14:18:25 +0200 Subject: [PATCH 4/4] docs: v1.0 smoke-test checklist + readiness-doc bijgewerkt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs/runbooks/v1-smoke-test.md (NIEUW): 11-secties handmatige checklist voor de v1.0-pre-launch verificatie — auth, mobile UA-redirect, happy-path flow, mobile shell, edit-flows, demo-policy, rate-limiting steekproef, realtime, debug-routes 404 in productie, Lighthouse a11y per pagina, rollback-trigger. v1-readiness.md: 4 Before-launch items afgevinkt (demo-policy, privacy, README, CHANGELOG); smoke-test verwijst nu naar de checklist; PWA-test en v1.0.0-bump zijn de twee resterende handmatige items. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/INDEX.md | 1 + docs/plans/v1-readiness.md | 14 ++--- docs/runbooks/v1-smoke-test.md | 100 +++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 docs/runbooks/v1-smoke-test.md diff --git a/docs/INDEX.md b/docs/INDEX.md index bf5c415..ddb1a02 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -110,6 +110,7 @@ Auto-generated on 2026-05-04 from front-matter and headings. | [Branch, PR & Commit Strategy](./runbooks/branch-and-commit.md) | `runbooks/branch-and-commit.md` | active | 2026-05-03 | | [Vercel Deployment](./runbooks/deploy-vercel.md) | `runbooks/deploy-vercel.md` | active | 2026-05-03 | | [MCP Integration — Scrum4Me Tools](./runbooks/mcp-integration.md) | `runbooks/mcp-integration.md` | active | 2026-05-03 | +| [v1.0 Smoke Test Checklist](./runbooks/v1-smoke-test.md) | `runbooks/v1-smoke-test.md` | active | 2026-05-04 | | [StoryDialog Profiel](./story-dialog.md) | `story-dialog.md` | active | 2026-05-03 | | [TaskDialog Profiel](./task-dialog.md) | `task-dialog.md` | active | 2026-05-03 | | [Scrum4Me — API Test Plan](./test-plan.md) | `test-plan.md` | active | 2026-05-03 | diff --git a/docs/plans/v1-readiness.md b/docs/plans/v1-readiness.md index beb1473..a8610ee 100644 --- a/docs/plans/v1-readiness.md +++ b/docs/plans/v1-readiness.md @@ -93,13 +93,13 @@ Twee verwante todo's over de todo-feature uitbreiden. Past bij de strategische r Must-do voor publieke aankondiging, maar mag pas vlak vóór v1.0-tag. -- [ ] **Smoke-test productie** na merge: registreren → product → PBI → story → sprint → task → solo → completion. Ook mobile flow (DevTools UA-spoof of echt toestel). 12-min-job. -- [ ] **PWA-installatie test** op echt mobiel (Android + iOS) — bevestig manifest landscape, controleer iOS-fallback via CSS-overlay. -- [ ] **Demo-policy regression-pass:** demo-user mag niets schrijven via UI/API/MCP. Drie-laags-demo-block. -- [ ] **Privacy review:** zit er PII in logs? Sentry-events strippen? Avatar-upload-paden? -- [ ] **README + Quick start verifiëren** op een schone clone — kan iemand binnen 10 min `npm run dev` draaien? -- [ ] **Bump naar v1.0.0** + GitHub release met release-notes (mirror van wat in v0.9.0 zit, met v1-claim "stabiele MVP") -- [ ] **CHANGELOG.md** aanmaken (ontbreekt nu) — een vlakke `Keep-a-Changelog`-formaat is genoeg +- [ ] **Smoke-test productie** — checklist klaar in [docs/runbooks/v1-smoke-test.md](../runbooks/v1-smoke-test.md), 11 secties, ~15 min +- [ ] **PWA-installatie test** op echt mobiel (Android + iOS) — bevestig manifest landscape, controleer iOS-fallback via CSS-overlay +- [x] **Demo-policy regression-pass** — code-side gefixt: 3 gaps gedicht (toggleTodo, archiveCompletedTodos, leaveProduct). Drielaags-block geverifieerd voor alle mutation-actions +- [x] **Privacy review** — Sentry sendDefaultPii=false; geen PII in logs; 4 debug-routes nu NODE_ENV-guarded (404 in productie) +- [x] **README + Quick start verifiëren** — test-count 69 → 445 gecorrigeerd, env-vars-tabel uitgebreid (CRON_SECRET, Sentry vars), CHANGELOG-link toegevoegd +- [x] **CHANGELOG.md** aangemaakt (Keep a Changelog formaat met [Unreleased] + [0.9.0]) +- [ ] **Bump naar v1.0.0** + GitHub release met release-notes --- diff --git a/docs/runbooks/v1-smoke-test.md b/docs/runbooks/v1-smoke-test.md new file mode 100644 index 0000000..3743338 --- /dev/null +++ b/docs/runbooks/v1-smoke-test.md @@ -0,0 +1,100 @@ +--- +title: "v1.0 Smoke Test Checklist" +status: active +audience: [maintainer] +language: nl +last_updated: 2026-05-04 +--- + +# v1.0 Smoke Test Checklist + +Loop deze checklist door **vóór** je v1.0.0 tagt. Alleen handmatig — geen automation. +Time-budget: ~15 min. + +**Productie-URL:** https://scrum4me.jp-visser.nl + +--- + +## 1. Auth + dashboard (3 min) + +- [ ] **Demo-login:** `demo` / `demo1234` → dashboard rendert, alle write-acties geven 403 +- [ ] **Logout** vanuit user-menu → redirect naar `/login` +- [ ] **Register** met nieuwe gebruikersnaam → succesvol, redirect naar `/dashboard` +- [ ] **Login fout-flow:** verkeerd wachtwoord → generieke fout, geen leak + +## 2. Mobile UA-redirect (2 min) + +- [ ] DevTools mobile-emulatie iPhone 12 (UA-spoof) → log in → automatisch naar `/m/products/[id]/solo` (of `/m/settings` zonder actief product) +- [ ] Tablet-UA (iPad) → blijft op `/dashboard` +- [ ] Desktop blijft `/dashboard` + +## 3. Product → PBI → Story → Sprint → Task happy-path (5 min) + +- [ ] **Product aanmaken** (eigen account) → naam, code, DoD ingevuld +- [ ] **PBI aanmaken** in Product Backlog kolom → priority + status +- [ ] **Story aanmaken** onder PBI → titel + acceptatiecriteria +- [ ] **Sprint starten** met sprint-goal +- [ ] **Story slepen** vanuit Product Backlog naar Sprint Backlog +- [ ] **Task aanmaken** in Sprint → titel + implementation_plan +- [ ] **Task drag-and-drop** in Solo Paneel: To Do → Bezig → Klaar +- [ ] **Story-status auto-promotie:** alle taken DONE → story status DONE + +## 4. Mobile shell (2 min — op echte phone of DevTools landscape iPhone 12) + +- [ ] `/m/products/[id]` rendert in tab-mode (3 tabs onderaan: Backlog/Solo/Settings) +- [ ] Portrait-orientatie → rotate-overlay +- [ ] `/m/products/[id]/solo` toont 3-koloms kanban met horizontal scroll +- [ ] Task-detail dialog opent full-screen (`<640px`) — sticky header + footer bereikbaar +- [ ] `/m/settings` toont username + actieve product + logout-knop met bevestiging +- [ ] `/m/pair` toont QR-pairing-confirmation (M10 intact) +- [ ] **Geen** NavBar / AppIcon / Scrum4Me-tekst zichtbaar op `/m/*` + +## 5. Edit-flows (1 min) + +- [ ] **Pencil-icon op product-card** (dashboard hover) → ProductDialog opent +- [ ] **PBI ✎-icoon** (hover) → PbiDialog opent en saved +- [ ] **Story ✎-icoon** (sprint screen Sprint Backlog) → StoryDialog opent +- [ ] **Task ✎-icoon** (Taken-kolom) → TaskDialog opent + +## 6. Demo-policy (1 min) + +Inloggen als demo-gebruiker: +- [ ] PBI/Story/Task create-knoppen disabled met DemoTooltip +- [ ] Edit-iconen disabled +- [ ] Logout-knop bereikbaar (demo mag uitloggen) +- [ ] Productselector gaat door op view, maar Activeer-acties geven 403 + +## 7. Rate-limiting (steekproef, 1 min) + +- [ ] Probeer 31 PBIs in <60s aan te maken via UI → 31e geeft toast "Te veel acties achter elkaar" +- [ ] (Optioneel) `bash scripts/test-api.sh` → alle endpoints groen + +## 8. Realtime (1 min) + +- [ ] Open `/products/[id]/solo` in twee browsers (één als owner, één als teamlid) +- [ ] Status-toggle in browser A → ziet binnen 1s in browser B (SSE-pipe) +- [ ] Claude-vraag binnenkrijgen → bell-badge verschijnt zonder refresh + +## 9. Debug-routes (productie afgeschermd) + +- [ ] `https://scrum4me.jp-visser.nl/debug-env` → **404** (NODE_ENV-guard) +- [ ] `https://scrum4me.jp-visser.nl/debug-realtime` → **404** +- [ ] `https://scrum4me.jp-visser.nl/api/debug/realtime-stream` → **404** + +## 10. Lighthouse op happy-path + +- [ ] `/login` — a11y ≥95 +- [ ] `/dashboard` — a11y ≥95 +- [ ] `/products/[id]` — a11y ≥95 (was 86 vóór PR #88) +- [ ] `/products/[id]/sprint` — a11y ≥95 +- [ ] `/products/[id]/solo` — a11y ≥95 + +> Performance score in dev-mode is misleidend (dev-bundles, Chrome-extensies). +> Test op productie of `npm run build && npm run start` voor betrouwbare cijfers. + +## 11. Rollback-trigger + +Als één van bovenstaande faalt: +- Vercel dashboard → Deployments → vorige Ready deploy → "Promote to Production" +- Issue-titel: "v1.0 smoke-test failure: \" +- Tag v1.0.0 NIET totdat alles groen is