Files
cannamanage/docs/sprint-4/cannamanage-sprint4-plan-persona-review.md
Patrick Plate fe6e96dd3f feat: Sprint 4 complete — frontend MVP (admin dashboard + member portal)
Shadboard starter-kit (Next.js 15 + React 19 + shadcn/ui + Tailwind 4)

Sprint 4.a — Admin Dashboard:
- Auth: NextAuth.js v5, login page, middleware, token rotation
- Dashboard: KPI cards, Recharts stock chart, quick actions
- Members: TanStack Table (search/sort/paginate), add/edit forms
- Distributions: multi-step form, real-time quota check, history
- Stock: batch management, recall dialog, bar chart
- Reports: monthly/member-list/recall, PDF/CSV download, preview

Sprint 4.b — Member Portal:
- Separate route group with top-nav layout (mobile-first)
- Quota dashboard with radial SVG progress indicators
- Distribution history with month filter
- Profile/settings with password change

Cross-cutting:
- i18n: German (default) + English via next-intl
- Dark + light mode (next-themes, user-togglable)
- Playwright E2E tests (6/6 green)
- Docker multi-stage build (node:22-alpine)
- API proxy via Next.js rewrites

Tech: Next.js 15.2.8, React 19, Tailwind 4, NextAuth v5,
TanStack Table, Recharts, Zod, React Hook Form, Playwright
2026-06-12 17:18:38 +02:00

294 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CannaManage Sprint 4 Plan — Multi-Persona Review Panel (Iteration 2)
**Date:** 2026-06-12
**Reviewed Document:** `docs/sprint-4/cannamanage-sprint4-plan.md` (v3, ~1690 lines)
**Review Method:** 6-persona stakeholder simulation, scoring on 4 dimensions (0100%)
**Iteration:** 2 (re-review after addressing Iteration 1 gaps)
---
## Changes Since Iteration 1
The v3 plan addresses the following gaps identified in Iteration 1:
1.**Immutable Audit Trail** — Section 6.8 added (audit log viewer, locked indicators, compliance PDF export)
2.**Security Hardening** — Section 6.6 added (CSP headers in `next.config.ts`, secret management, cookie security, input sanitization)
3.**Frontend Testing Strategy** — Section 6.7 added (Vitest, React Testing Library, Playwright, MSW, coverage targets)
4.**Member Quota Visualization** — Phase 9 enhanced (color-coded progress bars, "next refill" date, simple language)
5.**Club Owner Daily Operations** — Phase 3 enhanced (today's summary widget, global Cmd+K search, low stock alerts)
6.**Accessibility** — Section 6.5 expanded (WCAG 2.1 AA target, skip-nav, focus rings, aria-live, reduced motion)
7.**Empty/Error States** — Section 6.1 expanded (per-page empty states, error boundaries with retry, offline indicator)
8.**Compliance Timestamps** — Section 6.9 added (server-authoritative, Europe/Berlin TZ display, Intl.DateTimeFormat)
Additional improvements:
- ESLint flat config + Prettier added to Phase 1 (lint/format)
- Hardcoded secrets removed from examples (replaced with `${NEXTAUTH_SECRET}` references)
- CSP + HSTS + X-Frame-Options in `next.config.ts` security headers
---
## 1. 👤 Club Member (End User)
*"I'm a regular member of a cannabis social club. I want to see my quota, pick up my cannabis, and check my history."*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **Enhanced quota visualization** — color-coded progress bars (green/amber/red), "next refill" date, and simple German language ("Du hast noch 28g diesen Monat") make my quota status instantly understandable. |
| 2 | ✅ Positive | **Empty states are defined** — if I'm a new member with no distributions, I see a friendly message instead of a blank page. Loading skeletons provide visual feedback. |
| 3 | ✅ Positive | **Offline indicator** — if my phone loses connection, I see a subtle banner rather than confusing error states. |
| 4 | ✅ Positive | **Distribution history is immutable and trustworthy** — records show 🔒 lock icon and server-generated timestamps in my timezone. I know the data hasn't been tampered with. |
| 5 | ⚠️ Minor | **Still no push notifications** — recalls or quota resets aren't proactively communicated. I still need to check the portal manually. (Acknowledged as Sprint 5+ scope.) |
| 6 | ⚠️ Minor | **No PWA/mobile app** — still deferred. Responsive web is fine but I'd prefer a home-screen shortcut. (Explicitly out of scope.) |
| 7 | ✅ Positive | **Accessibility improvements** — WCAG 2.1 AA target means the portal will be usable even if I have visual impairments. Screen reader announcements for quota updates are planned. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 90% | +8% | Quota visualization is now fully specified with color thresholds, next-refill date, and simple language copy. Empty states have exact messages per page. |
| Correctness | 92% | +4% | Timestamps are explicitly Europe/Berlin with TZ indicator. Color thresholds match intuitive expectations. Under-21 differentiation clear. |
| Usability | 85% | +13% | Color-coded quota, friendly empty states, offline indicator, and accessibility improvements significantly enhance the daily experience. Only missing notifications keeps this below 90%. |
| Usefulness | 86% | +11% | Quota view is now genuinely useful with refill date + color coding. Immutable history gives confidence. Lack of proactive alerts is the remaining gap. |
**Composite Score: 88%** (was 79%, Δ +9%)
### Remaining Gaps (minor, Sprint 5+)
- Push/email notifications for recalls and quota resets
- PWA manifest for mobile home-screen
---
## 2. 🏢 Club Owner / Vorstand (Business Owner)
*"I run the Anbauvereinigung. I need compliance reports for the Behörde, member oversight, and distribution control."*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **"Today's Distribution Summary" widget** — I can see at a glance how many distributions happened today, total grams, which staff recorded them, and a comparison vs yesterday. This is exactly what I need every morning. |
| 2 | ✅ Positive | **Global member search (Cmd+K)** — quick type-ahead search in the header means I can find any member in seconds without navigating to the member list first. |
| 3 | ✅ Positive | **Low stock alert badge** — red dot on "Bestand" nav item when batches < 100g means I won't be caught off guard by empty stock. |
| 4 | ✅ Positive | **Audit log viewer** — the new `(dashboard)/audit/page.tsx` gives me a chronological view of all distributions. I can filter by date range, staff, and action type. Essential for Behörde inspections. |
| 5 | ✅ Positive | **Compliance PDF export** — "Audit-Bericht exportieren" button generates a PDF with all distributions for a date range. Timestamps include timezone. Ready for inspections. |
| 6 | ⚠️ Minor | **Staff management still deferred** — I can't invite or manage staff permissions from the UI in Sprint 4. The plan acknowledges this is Sprint 5. |
| 7 | ⚠️ Minor | **Club settings page still deferred** — email whitelist and prevention officer limits have no UI yet. |
| 8 | ✅ Positive | **Immutable records** — distribution records are locked after creation. The UI shows 🔒 indicators. This protects me legally — I can prove records weren't altered. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 92% | +7% | Today's summary widget, global search, low stock alerts, and audit page are concretely specified with component props and API endpoints. |
| Correctness | 90% | +10% | Audit trail design is legally sound. Timestamps are server-authoritative in correct timezone. Immutability is enforced at backend level. |
| Usability | 82% | +17% | Daily operations are now well-supported (today summary, quick search, stock alerts). Only missing staff management and settings UI. |
| Usefulness | 88% | +16% | The core compliance workflow is now complete: distribute → audit → report → export. Missing staff management is the main gap. |
**Composite Score: 88%** (was 76%, Δ +12%)
### Remaining Gaps (minor, Sprint 5)
- Staff management UI (invite, permission editing)
- Club settings page (email whitelist, prevention officer limit config)
---
## 3. 💻 Developer (Technical Implementer)
*"I'm the one building this. Is the technical plan sound? Are dependencies clear? Is the architecture scalable?"*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **Testing strategy fully defined** (Section 6.7) — Vitest for units, React Testing Library for components, Playwright for E2E, MSW for API mocking. File conventions, directory structure, and `vitest.config.ts` are copy-paste ready. |
| 2 | ✅ Positive | **ESLint flat config + Prettier** — lint/format tooling is defined in Phase 1 with exact config files. No ambiguity about code style from day one. |
| 3 | ✅ Positive | **Security headers in `next.config.ts`** — CSP, HSTS, X-Frame-Options are defined with exact header values. I can implement this without research. |
| 4 | ✅ Positive | **`next.config.ts` now shows the full combined config** — API rewrites + security headers + next-intl plugin all in one place. No confusion about how to compose them. |
| 5 | ✅ Positive | **No hardcoded secrets**`.env.local` example uses `<generate-with-openssl-rand-base64-32>` placeholder. Docker Compose uses `${NEXTAUTH_SECRET}` variable reference. Security note explains production injection. |
| 6 | ✅ Positive | **Date utility function provided**`lib/date-utils.ts` with `Intl.DateTimeFormat` configured for Europe/Berlin. I won't accidentally use wrong timezone. |
| 7 | ⚠️ Minor | **NextAuth v5 beta risk remains** — still committed to v5. The plan acknowledges the risk but doesn't pin a specific version. Manageable since v5 is the documented path forward. |
| 8 | ✅ Positive | **Middleware composition is now clear** — the combined `next.config.ts` shows headers + rewrites together. Auth middleware in `middleware.ts` is separate (NextAuth pattern). No conflict. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 95% | +3% | Testing strategy, lint config, security headers, and date utilities are all specified with exact code. Near-zero ambiguity. |
| Correctness | 90% | +5% | All technical decisions are sound. Testing tools are current and well-chosen. CSP policy is appropriate for Next.js. NextAuth v5 beta is a known risk. |
| Usability | 92% | +14% | As a developer, I have everything I need: test conventions, lint rules, security config, and utility functions. No decisions left to me that should be in the plan. |
| Usefulness | 93% | +5% | This plan saves me days of setup research. Testing strategy alone would have taken half a day to decide. Code snippets are directly implementable. |
**Composite Score: 93%** (was 86%, Δ +7%)
### Remaining Gaps (negligible)
- Could pin NextAuth v5 beta version (e.g., `"next-auth": "5.0.0-beta.25"`) — trivial to add during implementation
---
## 4. 🛡️ Compliance Officer / Behörde Inspector
*"I need to verify this club is operating within KCanG §19 limits. The software must produce auditable records."*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **Immutable audit trail is explicitly designed** (Section 6.8) — distributions are append-only, no UPDATE/DELETE allowed. Backend enforces `DISTRIBUTION_IMMUTABLE` error code. Frontend shows lock icons. |
| 2 | ✅ Positive | **Server-authoritative timestamps** (Section 6.9) — `distributedAt` is set by backend, not client. All times displayed in Europe/Berlin with explicit timezone indicator. Monthly reports include timezone-aware date ranges. |
| 3 | ✅ Positive | **Audit log viewer** — admin dashboard includes a paginated event log with date range filters. I can see who distributed what, when, and to whom in chronological order. |
| 4 | ✅ Positive | **Compliance PDF export** — "Audit-Bericht exportieren" generates a report suitable for Behörde inspections. Includes all legally required fields: timestamp (TZ-aware), member ID, quantity, batch code, staff name. |
| 5 | ✅ Positive | **Batch traceability intact** — recall reports trace contaminated batches to affected members. Combined with immutable distribution records, this creates a complete chain of custody. |
| 6 | ⚠️ Minor | **No cryptographic hash chain** — while records are immutable (no UPDATE/DELETE), there's no SHA-256 hash linking each record to the previous one. This means a database admin could theoretically insert backdated records. For KCanG compliance this is acceptable (not required by law), but would strengthen auditability. |
| 7 | ⚠️ Minor | **No inspector read-only mode** — there's still no separate login for Behörde officials. They must trust the admin to show them the audit log. The compliance PDF export partially mitigates this. |
| 8 | ✅ Positive | **Under-21 differentiation clear** — quota visualization explicitly distinguishes 25g (under-21) vs 50g (adult) with visual warnings. Compliance with §19 age-based limits is verifiable. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 88% | +18% | Audit trail design, timestamp handling, and compliance export are precisely specified. Immutability enforcement is clear (backend error code + frontend lock icons). |
| Correctness | 90% | +15% | Timestamps are correctly server-authoritative in Europe/Berlin. Append-only records meet KCanG audit requirements. Quota limits match §19 specifications. |
| Usability | 78% | +23% | Audit log viewer and PDF export make inspections feasible. No separate inspector login is a gap but the PDF export provides a sealed artifact. |
| Usefulness | 85% | +17% | The system can now demonstrate compliance during inspections: immutable records + timestamped audit trail + exportable PDF reports. Core compliance needs are met. |
**Composite Score: 85%** (was 67%, Δ +18%)
### Remaining Gaps (future enhancement)
- Cryptographic hash chain (SHA-256 linking records) — nice-to-have, not legally required
- Inspector read-only mode — could be a time-limited token generating feature (Sprint 6+)
- Monthly report auto-sealing at month-end — would prevent retroactive modification concerns
---
## 5. 🔒 Security Auditor
*"I'm reviewing the app for security vulnerabilities before production deployment."*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **CSP headers fully defined**`Content-Security-Policy` with `default-src 'self'`, `frame-ancestors 'none'`, `form-action 'self'`. Also includes HSTS (63072000s), X-Frame-Options, X-Content-Type-Options, Permissions-Policy. Comprehensive header set. |
| 2 | ✅ Positive | **No hardcoded secrets anywhere**`.env.local` uses placeholder with generation command. Docker Compose uses `${NEXTAUTH_SECRET}` and `${DB_PASSWORD:-dev_password}`. Security note explains production injection. |
| 3 | ✅ Positive | **Cookie security verified** — HttpOnly, Secure (prod), SameSite=Lax. JWT never exposed to client JavaScript. This is NextAuth's default but explicitly confirmed. |
| 4 | ✅ Positive | **Rate limiting acknowledged** — backend enforces 5 attempts/15min. Frontend shows "Zu viele Anmeldeversuche" on 429. The backend enforcement is the correct layer for this. |
| 5 | ✅ Positive | **CSRF protection via NextAuth** — built-in csrfToken verification in credential forms. Explicitly mentioned in section 6.6. |
| 6 | ✅ Positive | **Input sanitization strategy** — all inputs validated with Zod schemas. No `dangerouslySetInnerHTML`. Server-side validation remains authoritative. Defense in depth. |
| 7 | ⚠️ Minor | **CSP allows `unsafe-inline` and `unsafe-eval`** for scripts — necessary for Next.js in development mode. In production, could tighten with nonce-based CSP. Plan notes this with comment "Next.js requires unsafe-inline/eval in dev". |
| 8 | ✅ Positive | **API proxy pattern** (rewrites) means backend URL never exposed to browser. Combined with CSP `connect-src 'self'`, external data exfiltration is blocked. |
| 9 | ✅ Positive | **Immutable distribution records** — append-only design prevents data tampering through the application layer. Good defense against insider threats. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 90% | +15% | CSP header values are exact. Cookie attributes are specified. Rate limiting parameters defined. Secret management guidance is clear. |
| Correctness | 92% | +14% | Security architecture is sound: server-side tokens, CSP, HSTS, SameSite cookies, input validation, no secret exposure. The `unsafe-inline/eval` is a known Next.js trade-off. |
| Implementability | 90% | +10% | All security measures are implementable within the sprint. CSP headers are copy-paste. Secret management guidance prevents common mistakes. |
| Usefulness | 88% | +18% | The plan now provides a production-ready security posture. Only nonce-based CSP (removing unsafe-inline) would improve it, and that's a post-MVP optimization. |
**Composite Score: 90%** (was 76%, Δ +14%)
### Remaining Gaps (post-MVP optimization)
- Nonce-based CSP to eliminate `unsafe-inline`/`unsafe-eval` — requires Next.js middleware integration
- Subresource Integrity (SRI) for third-party scripts — no third-party scripts planned, so N/A
---
## 6. 🎨 UX Designer
*"I'm evaluating the user experience and accessibility of the planned UI."*
### Findings
| # | Type | Observation |
|---|------|-------------|
| 1 | ✅ Positive | **Empty states are comprehensively defined** — each list page has a specific message and CTA. "Noch keine Mitglieder vorhanden" + "Erstes Mitglied anlegen" button. No blank pages anywhere. |
| 2 | ✅ Positive | **WCAG 2.1 AA compliance target with specific implementations** — focus rings (`ring-2 ring-ring ring-offset-2`), skip-nav link, aria-live regions for toasts, reduced motion support. Not just a checklist but actual CSS and implementation guidance. |
| 3 | ✅ Positive | **Color contrast verified**`#E6EDF3` on `#0D1117` = 13.5:1 ✅, `#2ECC71` on `#0D1117` = 7.5:1 ✅. Numbers given, not just "meets AA". |
| 4 | ✅ Positive | **Quota visualization with color coding** — green/amber/red progress bars with exact thresholds (50%/80%). This provides instant visual feedback about quota status. |
| 5 | ✅ Positive | **Loading skeletons expanded** — specific skeleton patterns for stat cards, tables, quota rings, and charts. Users always see a structured placeholder during load. |
| 6 | ✅ Positive | **Offline indicator** — subtle banner "Keine Internetverbindung" shows without interrupting flow. Good progressive enhancement. |
| 7 | ✅ Positive | **Screen reader announcements** — toasts use `role="alert"` with appropriate `aria-live` politeness levels. Quota updates and form results are announced. |
| 8 | ⚠️ Minor | **No micro-interactions/transitions still** — page transitions, form animations remain unspecified. The plan is functional but won't feel "polished". Acceptable for MVP. |
| 9 | ⚠️ Minor | **Distribution form still lacks visual progress stepper** — 3-step flow doesn't have a step indicator component specified. Users may not know they're on step 2 of 3. |
### Scores
| Dimension | Score | Δ from v2 | Rationale |
|-----------|-------|-----------|-----------|
| Precision | 88% | +16% | Empty states have exact messages per page. Accessibility has CSS values. Color coding has numeric thresholds. Significant improvement in UX specification. |
| Correctness | 90% | +8% | Color contrast ratios are verified. WCAG 2.1 AA implementations are technically correct. Loading patterns follow best practices. |
| Usability | 86% | +16% | Empty states, offline indicator, color-coded quota, and accessibility improvements make the app usable by a wider audience. Missing animations keep it from "delightful". |
| Usefulness | 88% | +10% | The plan now delivers a usable, accessible, and informative MVP. Users can understand their status at a glance. Accessibility means no users are excluded. |
**Composite Score: 88%** (was 76%, Δ +12%)
### Remaining Gaps (polish, Sprint 5)
- Page transition animations (Framer Motion or next-view-transitions)
- Distribution form progress stepper (3-dot visual indicator)
- Portal visual differentiation from admin (subtle color shift)
---
## Summary Matrix
| Persona | Precision | Correctness | Usability | Usefulness | Composite | Δ from v2 |
|---------|-----------|-------------|-----------|------------|-----------|-----------|
| 👤 Club Member | 90% | 92% | 85% | 86% | **88%** | +9% |
| 🏢 Club Owner | 92% | 90% | 82% | 88% | **88%** | +12% |
| 💻 Developer | 95% | 90% | 92% | 93% | **93%** | +7% |
| 🛡️ Compliance Officer | 88% | 90% | 78% | 85% | **85%** | +18% |
| 🔒 Security Auditor | 90% | 92% | 90%¹ | 88% | **90%** | +14% |
| 🎨 UX Designer | 88% | 90% | 86% | 88% | **88%** | +12% |
¹ Security Auditor "Usability" replaced with "Implementability"
**Overall Plan Score: 89%** (was 77%, Δ +12%)
### Dimension Averages (across all personas)
| Dimension | Average | Δ from v2 | Weakest Persona |
|-----------|---------|-----------|-----------------|
| Precision | 91% | +12% | Compliance Officer (88%) |
| Correctness | 91% | +10% | Developer / Compliance / UX (90%) |
| Usability | 86% | +16% | Compliance Officer (78%) |
| Usefulness | 88% | +13% | Compliance Officer (85%) |
---
## Iteration Comparison
| Persona | Iteration 1 (v2) | Iteration 2 (v3) | Delta | Target Met (≥90%) |
|---------|-------------------|-------------------|-------|-------------------|
| 👤 Club Member | 79% | 88% | +9% | ⚠️ Close (88%) |
| 🏢 Club Owner | 76% | 88% | +12% | ⚠️ Close (88%) |
| 💻 Developer | 86% | 93% | +7% | ✅ Yes |
| 🛡️ Compliance Officer | 67% | 85% | +18% | ⚠️ No (85%) |
| 🔒 Security Auditor | 76% | 90% | +14% | ✅ Yes |
| 🎨 UX Designer | 76% | 88% | +12% | ⚠️ Close (88%) |
**Personas at or above 90%: 2 of 6** (Developer, Security Auditor)
**Personas at 85-89%: 4 of 6** (all close but below target)
---
## Verdict
The v3 plan represents a **significant improvement** across all dimensions (+12% overall). The largest lift was for the Compliance Officer persona (+18%), which went from the weakest performer (67%) to a solid 85% thanks to the audit trail, timestamp verification, and compliance export additions.
**Key remaining gaps preventing all personas from reaching 90%:**
1. **Compliance Officer (85%)** — lacks cryptographic hash chain and inspector read-only mode. These are enhancements beyond KCanG requirements but would provide stronger audit guarantees. The 85% score reflects a system that meets legal compliance needs but doesn't exceed them.
2. **Club Member (88%)** — lacks proactive notifications (recall alerts, quota reset reminders) and PWA support. Both are explicitly deferred to Sprint 5+. The core portal experience is excellent.
3. **Club Owner (88%)** — lacks staff management and club settings UI. These are Sprint 5 scope. Daily operations (today summary, search, alerts) are well-covered.
4. **UX Designer (88%)** — lacks micro-interactions/transitions and distribution form progress stepper. These are polish items that don't affect functionality.
**Assessment:** The plan is **implementation-ready** for a frontend MVP sprint. All critical gaps from Iteration 1 have been addressed. The remaining gaps are explicitly deferred scope (Sprint 5+) or post-MVP polish — they do not represent missing requirements for Sprint 4.
**Recommendation:** **GO** — proceed to implementation. The 4 personas at 85-89% have gaps that are intentionally out of Sprint 4 scope. No blocking issues remain.