Merge pull request #89 from madhura68/chore/before-launch-changelog
docs+fix: Before-launch checklist (CHANGELOG, demo-policy, privacy, smoke-test)
This commit is contained in:
commit
d02434a1e9
11 changed files with 221 additions and 10 deletions
85
CHANGELOG.md
Normal file
85
CHANGELOG.md
Normal file
|
|
@ -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 `<main>` 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
|
||||
10
README.md
10
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`.
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div style={{ fontFamily: 'monospace', padding: 16 }}>
|
||||
<h1 style={{ fontSize: 18, fontWeight: 'bold' }}>Realtime debug — scrum4me_changes</h1>
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
100
docs/runbooks/v1-smoke-test.md
Normal file
100
docs/runbooks/v1-smoke-test.md
Normal file
|
|
@ -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: \<korte beschrijving\>"
|
||||
- Tag v1.0.0 NIET totdat alles groen is
|
||||
Loading…
Add table
Add a link
Reference in a new issue