# 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 (0–100%) **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 `` 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.