M10: Password-loze inlog via QR-pairing — backlog + implementatie-plan (#11)

* docs(ST-1001..1008): add M10 — QR-pairing login milestone to backlog

Plant acht stories ST-1001..ST-1008 voor password-loze inlog via QR-pairing.
Mobiele bevestiging met UA+IP, demo-blokkade, paired-sessie 8u TTL.
Security-uitgangspunt: mobileSecret reist alleen via QR-fragment + POST-body,
desktop-SSE/claim via HttpOnly pre-auth cookie — geheim materiaal nooit in
URL-paden, querystrings, access logs of browsergeschiedenis. Twee gescheiden
hashes in DB (secret_hash + desktop_token_hash). Bouwt voort op M8 LISTEN/NOTIFY-
infra met eigen channel scrum4me_pairing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ST-1001..1008): teach backlog parser about M9 + M10

M9 (Actief Product Backlog) was bij eerdere merge per ongeluk overgeslagen in
de drie milestone-maps; viel terug op fallbacks. Nu expliciet, samen met M10
(QR-pairing). Parser self-test toont 12 milestones / 118 stories / 190 tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(ST-1001..1008): document QR-login flow in functional spec + persona

Voeg F-01b (Inloggen via mobiel via QR-pairing) toe aan de functional spec met
acceptatiecriteria, randgevallen en datamodel. Beveiligingsuitgangspunt
expliciet: mobileSecret in URL-fragment en HttpOnly desktop-cookie zodat geheim
materiaal nooit in URL-paden of access logs belandt.

Lars-persona krijgt de bijbehorende use-case (publieke/geleende laptops bij
klantbezoek of familie) zodat de feature een herkenbare aanleiding heeft in v1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(ST-1001..1008): add M10 implementation plan + link from backlog

Volledig implementatie-plan per story (Bestanden / Stappen / Aandachtspunten /
Verificatie) in dezelfde stijl als M9. Citeert de patronen uit
docs/patterns/iron-session.md, route-handler.md en server-action.md, en
hergebruikt het LISTEN/NOTIFY-pattern uit app/api/realtime/solo/route.ts.

Bevat ook commit/branch-strategie per laag, reseed-stap voor de MCP-context, en
verificatie-acceptatie inclusief log-controle dat geheim materiaal niet in
access logs belandt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: enforce one-branch-per-milestone policy to limit Vercel builds

Vercel preview-deployments worden bij elke push naar een feature-branch
getriggered en kosten op het Hobby-account budget. Voeg expliciete Branch & PR
Strategy toe aan CLAUDE.md: één branch per milestone, commits accumuleren
lokaal, push + PR pas na handmatige gebruiker-acceptatie. Uitzonderingen voor
planning-only PR's (alleen docs) en hotfixes.

Update tegelijk de branch/commit-strategie-tabel in het M10-implementatieplan
zodat die de nieuwe policy weerspiegelt (één branch feat/M10-qr-login,
chronologische commits per stap, push pas bij groene happy-path-acceptatie).

Bevat een 'Wanneer aanpassen'-sectie zodat de regel makkelijk teruggedraaid kan
worden zodra het account naar Pro gaat.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-27 21:49:56 +02:00 committed by GitHub
parent 9941d96846
commit fb4d2e093f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1030 additions and 0 deletions

View file

@ -44,6 +44,8 @@ const MILESTONE_PRIORITY: Record<string, 1 | 2 | 3 | 4> = {
M6: 4,
M7: 4,
M8: 4,
M9: 4,
M10: 4,
}
const MILESTONE_GOAL: Record<string, string> = {
@ -57,6 +59,8 @@ const MILESTONE_GOAL: Record<string, string> = {
M6: 'Foutafhandeling, toegankelijkheid, CI/CD, beveiliging',
M7: 'MCP-server voor Claude Code',
M8: 'Realtime updates voor Solo Paneel',
M9: 'Actief Product Backlog — persistent gekozen product',
M10: 'Password-loze inlog via QR-pairing',
}
const MILESTONE_SPRINT_STATUS: Record<string, ParsedMilestone['sprint_status']> = {
@ -70,6 +74,8 @@ const MILESTONE_SPRINT_STATUS: Record<string, ParsedMilestone['sprint_status']>
M6: 'COMPLETED',
M7: 'COMPLETED',
M8: 'COMPLETED',
M9: 'COMPLETED',
M10: 'COMPLETED',
}
const MILESTONE_KEY = /^(?:M[\d.]+|PBI-\d+)$/