Files
cannamanage/docs/sprint-6/cannamanage-sprint6-plan-review.md
Patrick Plate 3232d2f7fd
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
feat(sprint-6): Phase 2 — DSGVO consent management
- V6 migration: consents table with audit columns
- Consent entity, repository, service (grant/revoke/check)
- ConsentController: GET/POST/DELETE consent endpoints
- DSGVO export (Art. 15): full personal data JSON download
- DSGVO deletion (Art. 17): anonymization + account deactivation
- Frontend: consent banner (modal, cannot dismiss), privacy settings page
- React Query hooks for consent + DSGVO operations
- Full i18n (de/en) for consent and DSGVO namespaces
2026-06-12 22:22:48 +02:00

32 KiB
Raw Permalink Blame History

CannaManage Sprint 6 Plan — Multi-Persona Review Panel

Date: 2026-06-12 Reviewed Document: docs/sprint-6/cannamanage-sprint6-plan.md (v2, ~1266 lines) Review Method: 6-persona stakeholder simulation, scoring on 4 dimensions (0100%) Iteration: 1 Sprint Goal: Production readiness — deploy, DSGVO compliance, Stripe payments, immutable audit log, grow calendar, notifications, launch


Decisions Incorporated (13 confirmed )

All open questions from the planning session are resolved:

  1. Stripe (fresh account) — SEPA + PayPal + Card (D1)
  2. SEPA Lastschrift as primary payment method (D2)
  3. IONOS VPS (existing plate-software.de, 8 GB RAM) (D3)
  4. Subdomain cannamanage.plate-software.de (D4)
  5. pg_dump daily 7d + weekly 4w retention (D5)
  6. Gitea Actions self-hosted CI/CD (D6)
  7. Uptime Kuma for monitoring (D7)
  8. Consent-first DSGVO approach (D8)
  9. Immutable append-only audit log (D9)
  10. FullCalendar with FULL scope (sensors, photos, feeding) (D10)
  11. WebSocket (SockJS/STOMP) + Web Push API (D11)
  12. 3-month free trial → tiered pricing (D12)
  13. Basic PWA (manifest + offline page) in Sprint 6 (D13)

1. 👤 Club Member (End User)

"I'm a regular member of a cannabis social club. I want to use the app on my phone, get notified about my distributions, and trust that my data is protected under DSGVO."

Findings

# Type Observation
1 Positive PWA installable — I can add CannaManage to my home screen and use it like a native app. Standalone mode, themed green, proper icons. This makes daily access much faster than bookmarking a URL.
2 Positive Real-time distribution notifications — When staff records a distribution for me, I get an instant notification via WebSocket. No more checking manually. The bell icon shows unread count.
3 Positive Push notifications even when app is closed — Web Push with opt-in means I get notified about quota warnings and batch recalls even with the browser closed. Critical for recalls.
4 Positive DSGVO transparency — I can see exactly what data is stored about me, export everything as ZIP (Art. 15), and request full deletion (Art. 17). The consent flow is clear: accept or leave.
5 Positive Offline resilience — If I lose signal, I see an offline page instead of a browser error. Not full offline mode, but graceful degradation.
6 ⚠️ Minor No grow calendar visibility for members — The grow calendar appears to be admin-only. As a member, I'd love to see what's currently growing (without sensitive details) — builds trust and community engagement.
7 ⚠️ Minor Notification preferences not detailed — Can I choose which notifications I receive? The plan mentions opt-in for push but doesn't describe granular notification preferences (e.g., only recalls, not every distribution).
8 Positive Consent versioning — If the privacy policy changes, I'm re-prompted. I'm not silently bound to new terms.

Scores

Dimension Score Rationale
Precision 88% Notification events are explicitly listed (quota warning, batch recall, new distribution). PWA manifest is precisely defined. However, notification preferences and member-facing grow visibility are unspecified.
Correctness 92% WebSocket + STOMP is a correct real-time architecture for this scale. Web Push with VAPID is the right standard. DSGVO implementation follows Arts. 6, 7, 15, 17 correctly.
Usability 86% PWA + push + bell icon covers my daily needs well. Missing granular notification control and member-facing grow calendar slightly reduce the experience.
Usefulness 90% The jump from "no notifications, no DSGVO, no mobile" to "push notifications, full DSGVO compliance, installable PWA" is massive. This sprint makes the app genuinely usable for daily members.

Composite Score: 89%

  • Add a note about notification preferences (future sprint or a simple "mute all" toggle)
  • Consider a read-only grow progress view for members (e.g., "Northern Lights — Flowering 🌸" without quantities)

2. 🏢 Club Owner / Vorstand (Business Owner)

"I run the Anbauvereinigung. I need Stripe payments to fund operations, an audit log for Behörde inspections, the grow calendar to manage our cultivation, and a reliable production deployment."

Findings

# Type Observation
1 Positive Stripe handles all billing complexity — SEPA mandates, dunning, invoicing, billing portal, payment method updates — all offloaded to Stripe. I don't need to manually chase payments or generate invoices.
2 Positive Tiered pricing is clear — Starter (€29/50 members) vs. Pro (€79/unlimited) gives me room to grow. The 14-day free trial lowers the barrier for new clubs.
3 Positive Immutable audit log for Behörde — PDF export of the audit log is exactly what inspectors need. Every distribution, member change, and batch action is logged with server timestamps. Immutability (@Immutable + no DELETE) ensures credibility.
4 Positive Grow calendar (FULL scope) — Stage tracking from seedling to curing, batch linking for traceability, sensor data for environmental control, photo documentation for compliance evidence. This is a complete cultivation management tool.
5 Positive Production deployment on existing infrastructure — No new server to provision. Co-hosted on the existing IONOS VPS means lower cost and immediate availability. Gitea Actions CI/CD means I don't depend on GitHub.
6 ⚠️ Medium Pricing discrepancy in plan — Section 0 (Decisions) says "≤30 members, €19/mo" and "≤100 members, €49/mo" but Section 3.3 (Stripe Architecture) says "up to 50 members, €29/month" and "unlimited members, €79/month". These need to be reconciled before implementation.
7 ⚠️ Medium Trial period discrepancy — Decision D12 says "3-month free trial" but the Stripe code shows setTrialPeriodDays(14L) (14 days). Which is it? This directly affects my club's onboarding strategy.
8 ⚠️ Minor No grace period defined — What happens when a payment fails? How many retry attempts before lockout? The plan mentions invoice.payment_failed shows a warning but doesn't specify the dunning timeline (Stripe default is 3 attempts over ~14 days, but this should be documented).
9 Positive Subscription enforcement middlewareSubscriptionFilter.java blocks API access when subscription expires. No free-riding after trial ends.
10 Positive Harvest → batch traceability — Linking a grow entry to a batch creates the full chain: grow → batch → distribution → member. This is exactly what regulators want to see.

Scores

Dimension Score Rationale
Precision 82% The pricing/trial discrepancies are concerning — they need resolution before implementation. Grow calendar and audit log are precisely specified. Dunning behavior is under-specified.
Correctness 88% Stripe architecture follows best practices (webhook signature verification, idempotent handlers, billing portal). Audit log immutability approach is correct. Grow stages and batch linking are logically sound.
Usability 90% Self-service billing portal, one-click PDF export for audits, visual grow calendar — all reduce my operational burden significantly.
Usefulness 93% This sprint delivers the three hardest requirements for going live: payments (to sustain the business), audit (for legal compliance), and grow tracking (for cultivation management).

Composite Score: 88%

Must Fix Before Implementation

  • 🔴 Reconcile pricing tiers — D12 says €19/€49 (30/100 members), Section 3.3 says €29/€79 (50/unlimited). Pick one and update throughout.
  • 🔴 Reconcile trial period — D12 says 3 months, code says 14 days. Which is the actual business decision?
  • Add dunning timeline documentation (how many retries, what interval, when lockout)

3. 💻 Developer (Technical)

"I'm building this on IONOS with Docker + Nginx, Gitea Actions for CI/CD, Stripe webhooks, WebSockets, and sensor ingestion. Is the architecture sound?"

Findings

# Type Observation
1 Positive Docker Compose prod is well-structured — env vars via .env, proper health checks with start_period, restart policies, named volumes for pgdata. Production-ready configuration.
2 Positive Nginx config is comprehensive — TLS termination, HTTP/2, HSTS, rate limiting (30r/s with burst), WebSocket upgrade, security headers. The Stripe webhook path correctly skips rate limiting.
3 Positive Gitea Actions CI/CD is practical — Self-hosted, no external dependencies, build → Docker → deploy locally. Simple and fast for a single-server deployment.
4 ⚠️ Medium Gitea Actions cd /opt/cannamanage in deploy step — The deploy step assumes the runner IS the production server (running locally). This works but means the CI runner has root-level access to production. If the Gitea instance is compromised, production is compromised. Consider SSH-based deployment even for local deploys (separation of concerns).
5 ⚠️ Medium No blue-green or rolling deploydocker compose up -d --remove-orphans causes downtime during image pull + container restart. For a single VPS this might be acceptable, but even a simple docker compose pull && docker compose up -d split would reduce downtime to seconds.
6 Positive Stripe webhook signature verificationWebhook.constructEvent(payload, sigHeader, webhookSecret) is the correct Stripe SDK pattern. Prevents webhook spoofing.
7 ⚠️ Minor WebSocket auth not specifiedWebSocketConfig uses setAllowedOriginPatterns("*"). In production, this should be restricted to the actual domain. Also, how is the WebSocket connection authenticated? STOMP interceptor with JWT? Session cookie?
8 ⚠️ Minor Sensor data ingestion endpoint unclear — The plan mentions "API endpoint for IoT devices" for sensor readings but doesn't specify authentication for IoT devices. Are sensors authenticated with API keys? Device tokens? This is a different auth flow from user JWT.
9 Positive Backup strategy is simple and effective — `pg_dump
10 Positive Flyway migrations are well-sequenced — V6 (consent + audit), V7 (stripe), V8 (grow), V9 (notifications). Clear dependency ordering.
11 ⚠️ Minor Phase 1 header says "Hetzner VPS" but body says "IONOS VPS" — The Phase 1 heading reads "Production Deployment (Hetzner VPS)" but the decision says IONOS. Inconsistency in the document.
12 Positive Service worker scope is appropriately limited — "Basic in Sprint 6" (offline page + asset caching) avoids the complexity of full offline sync, which would require IndexedDB and conflict resolution.
13 ⚠️ Minor Photo upload size limit (10MB) but no storage strategy — Where are grow photos stored? Local filesystem? S3-compatible object storage? For a single VPS, local disk works initially but needs a plan for growth.

Scores

Dimension Score Rationale
Precision 85% Core architecture is well-specified (Docker, Nginx, Stripe, Flyway). Gaps in WebSocket auth, sensor device auth, photo storage, and deploy strategy reduce precision.
Correctness 87% Docker Compose patterns, Nginx configuration, Stripe SDK usage, and STOMP/SockJS are all technically correct. The allowedOriginPatterns("*") and missing auth layers are correctness concerns for production.
Usability 88% Gitea Actions CI/CD is developer-friendly. Single docker compose up for local dev. Flyway handles migrations automatically. Clear phase separation makes implementation order obvious.
Usefulness 91% The plan delivers a complete production stack: deploy pipeline, payment processing, real-time notifications, and grow management — all on a single affordable VPS. Pragmatic engineering.

Composite Score: 88%

  • 🔴 Fix Phase 1 heading: "Hetzner VPS" → "IONOS VPS"
  • Specify WebSocket authentication mechanism (STOMP CONNECT frame with JWT or session-based)
  • Restrict setAllowedOriginPatterns to cannamanage.plate-software.de in production
  • Document sensor device authentication strategy (API key-based recommended)
  • Add photo storage strategy note (local filesystem initially, /opt/cannamanage/uploads/, with future migration path to S3)
  • Consider docker compose pull && docker compose up -d two-step deploy to minimize downtime

4. 🛡️ Datenschutzbeauftragter (Privacy/DSGVO Officer)

"I ensure this application complies with DSGVO. I check consent flows, data exports, erasure rights, data minimization, and third-party data processing agreements."

Findings

# Type Observation
1 Positive Art. 6 Rechtsgrundlage — Consent-first approach (Art. 6 Abs. 1 lit. a) is implemented. Users must explicitly accept before using the app. Consent entity stores timestamp, IP, user agent, and policy version.
2 Positive Art. 7 Einwilligung — Consent is freely given (user can decline and is logged out), specific (separate consent types: PRIVACY_POLICY, TERMS_OF_SERVICE, DATA_PROCESSING), informed (links to full Datenschutzerklärung), and unambiguous ("Akzeptieren" button). Withdrawal is as easy as giving (revoke in settings).
3 Positive Art. 15 AuskunftsrechtGET /api/v1/dsgvo/export returns a ZIP with all personal data. The implementation collects user profile, distributions, quota history, consent records, and login history.
4 Positive Art. 17 Recht auf LöschungDELETE /api/v1/dsgvo/erasure with appropriate exemption: "Some data must be retained for legal compliance (tax records, 10-year retention)." This correctly implements the Art. 17(3)(b) exception for legal obligations.
5 ⚠️ Medium Art. 28 Auftragsverarbeitung (Stripe) — Stripe is a data processor handling payment data. The plan doesn't mention the AVV (Auftragsverarbeitungsvertrag) with Stripe. This is a legal requirement. Stripe provides a standard DPA — it must be accepted and documented.
6 ⚠️ Medium IP address storage in consent — Storing IP addresses in the consent record is legitimate for proof of consent (Art. 7(1)), but the Datenschutzerklärung must explicitly mention this. IP addresses are personal data (EuGH C-582/14). Ensure retention period is defined.
7 ⚠️ Medium Audit log contains PIIactor_name ("Patrick Plate"), ip_address, and description (may contain member names in distribution descriptions like "25g Northern Lights an Max Mustermann ausgegeben"). The audit log is immutable (no deletion), which conflicts with Art. 17. This needs a documented legal basis (Art. 6(1)(c) — legal obligation for compliance records) and a defined retention period.
8 ⚠️ Minor Data minimization (Art. 5(1)(c)) — The consent entity stores user_agent (full browser string). Is the full user agent necessary? A truncated version or just the browser name would satisfy proof requirements while minimizing data.
9 Positive Consent versioning — When the privacy policy changes, users are re-prompted. This correctly implements the requirement for renewed consent when purposes change.
10 ⚠️ Minor No cookie banner mentioned — The consent modal handles app usage consent, but if any analytics cookies or third-party scripts are used (Uptime Kuma external check?), a separate cookie consent mechanism may be needed under ePrivacy/TTDSG. If no cookies beyond session cookies → document this.
11 Positive Erasure with anonymization — "Anonymize distributions (keep aggregates for compliance)" correctly balances Art. 17 deletion with legal retention. Aggregate data is no longer personal data.

Scores

Dimension Score Rationale
Precision 84% Core DSGVO flows (consent, export, erasure) are well-specified. Missing: AVV documentation with Stripe, audit log retention periods, IP storage justification in Datenschutzerklärung.
Correctness 86% Arts. 6, 7, 15, 17 are correctly implemented. The Art. 17(3)(b) exception for legal obligations is correctly applied. However, the audit log immutability vs. Art. 17 tension needs explicit legal basis documentation.
Usability 90% The consent flow is user-friendly: clear modal, accept/decline, revoke in settings, export as ZIP. Privacy settings page gives users full control.
Usefulness 88% The DSGVO implementation covers all critical requirements for launch. The few gaps (AVV, retention periods, audit log legal basis) are documentation tasks, not code changes.

Composite Score: 87%

Must Fix Before Launch

  • 🔴 Document Stripe AVV — Accept Stripe's DPA, reference it in the Datenschutzerklärung as a data processor (Art. 28)
  • 🔴 Define audit log retention period — Document the legal basis (Art. 6(1)(c) + §257 HGB 10-year retention for business records) and add it to the Datenschutzerklärung
  • 🟡 Mention IP address storage in the Datenschutzerklärung (why, how long, legal basis)
  • 🟡 Consider truncating user_agent to browser name + version only
  • Clarify cookie usage: if only session cookies, add a "no tracking cookies" statement to the privacy policy

5. 🔒 Security Auditor

"I audit the security posture of this application before it goes live. I check PCI compliance, SEPA data handling, webhook verification, TLS configuration, secret management, and backup encryption."

Findings

# Type Observation
1 Positive Stripe handles PCI compliance — By using Stripe Checkout (hosted payment page) and Payment Element (Stripe.js), card data never touches our servers. PCI SAQ-A eligible. No card numbers in our DB.
2 Positive Webhook signature verificationWebhook.constructEvent(payload, sigHeader, webhookSecret) validates the HMAC signature from Stripe. Rejects tampered or replayed webhook events.
3 Positive TLS configuration — Let's Encrypt certificate, HTTP→HTTPS redirect, HSTS with 2-year max-age. SSL Labs A+ should be achievable with these settings.
4 Positive Security headers — HSTS, X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin. Good baseline.
5 ⚠️ Medium Missing CSP header — Content-Security-Policy is not in the Nginx config. Without CSP, XSS attacks can load arbitrary external scripts. Add at minimum: default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com;
6 ⚠️ Medium Secrets in Docker env varsSTRIPE_SECRET_KEY, JWT_SECRET, DB_PASSWORD are passed as environment variables. While this is common with Docker Compose, the .env file on the server must be root-only readable (chmod 600). The plan doesn't mention file permissions or secret rotation.
7 ⚠️ Medium Backup encryption missing — `pg_dump
8 ⚠️ Minor Rate limiting only on /api/ — The / (frontend) path has no rate limiting. While Next.js SSR is less sensitive, a determined attacker could DOS the frontend rendering. Consider a lower global rate limit (e.g., 100r/s).
9 Positive Stripe webhook path excluded from rate limiting — Correct decision. Stripe retries on 429 with exponential backoff, but rate-limiting webhooks can cause payment state drift.
10 ⚠️ Minor No fail2ban or IP blocking — If the rate limiter triggers repeatedly for an IP, there's no mechanism to ban that IP temporarily. Consider adding limit_req_status 429 + fail2ban watching for 429s in access.log.
11 Positive Audit log immutability@Immutable annotation + no DELETE in repository. Server-generated timestamps prevent client manipulation. JSONB details field preserves before/after state for forensics.
12 ⚠️ Medium No DB-level DELETE prevention on audit_event — Hibernate @Immutable is application-level only. A compromised backend or direct DB access can still DELETE records. Add a PostgreSQL trigger: CREATE RULE no_delete_audit AS ON DELETE TO audit_event DO INSTEAD NOTHING; or use a REVOKE DELETE on the app DB user.
13 ⚠️ Minor SEPA data handling — SEPA bank details (IBAN) are handled by Stripe, not stored locally. Good. But the plan should explicitly state "No IBAN data touches our servers" as a security control statement.
14 Positive JWT for API authJWT_SECRET from env, Spring Security integration for API endpoints. Standard approach for SPA backends.
15 ⚠️ Minor No JWT rotation or expiry mentioned — The plan uses JWT_SECRET but doesn't specify token expiry, refresh token strategy, or secret rotation cadence. For a go-live, at minimum define token TTL (e.g., 15min access + 7d refresh).

Scores

Dimension Score Rationale
Precision 83% TLS, Stripe, and webhook verification are precise. Missing: CSP header definition, backup encryption, secret file permissions, DB-level audit protection, JWT lifecycle.
Correctness 85% The security architecture is fundamentally sound (Stripe handles PCI, TLS terminates at Nginx, rate limiting exists). But application-level immutability without DB enforcement is incomplete. Missing CSP is a significant gap.
Usability 91% From a security operations standpoint: automated TLS renewal, simple backup cron, Docker restart policies, and Uptime Kuma alerting make ongoing security operations manageable.
Usefulness 87% The plan delivers a production-ready security baseline. The gaps are hardening measures that should be addressed before public launch but don't block development.

Composite Score: 87%

Must Fix Before Launch

  • 🔴 Add Content-Security-Policy header — at minimum: default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com https://hooks.stripe.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
  • 🔴 Encrypt backups — Add GPG or AES-256 encryption to the backup script
  • 🔴 Add DB-level audit protection — PostgreSQL RULE or REVOKE DELETE on audit_event for the app user
  • 🟡 Document .env file permissions (chmod 600, root-only)
  • 🟡 Define JWT token lifecycle (access TTL, refresh strategy, secret rotation)
  • 🟡 Add explicit "No IBAN/card data stored locally" security control statement

6. 🌱 Cultivation Manager (Grower)

"I manage the club's grows from seed to harvest. I need to track plant stages, monitor environment (temperature/humidity), document with photos, plan feeding schedules, and link harvests to inventory batches."

Findings

# Type Observation
1 Positive Full lifecycle tracking — Six stages (Seedling → Vegetative → Flowering → Harvest → Drying → Curing) cover the complete cannabis grow cycle. Color-coded calendar blocks give me instant visual status of all active grows.
2 Positive Harvest → batch linking — This is the killer feature for compliance. When I harvest, I link directly to a batch entity, creating full traceability: seed → plant → harvest → batch → distribution → member. Inspectors love this.
3 Positive Sensor data — Temperature and humidity readings with configurable threshold alerts (e.g., temp > 30°C → notification). This lets me react quickly to environmental issues even when I'm not in the grow room.
4 Positive Photo documentation — Timeline view with captions per grow entry. This serves both my own record-keeping (disease identification, growth progress) and compliance evidence for inspectors.
5 Positive Feeding schedule — Nutrient name, amount, frequency, and calendar overlay showing feeding days. This replaces my spreadsheet and integrates feeding with the grow timeline.
6 ⚠️ Medium No multi-grow-room support — The GrowEntry entity has no room or location field. In a real club, we might have multiple grow rooms (veg room, flower room, drying room). Entries should be groupable by location.
7 ⚠️ Medium Sensor readings are per-grow-entry, not per-room — In practice, a temperature sensor monitors a room, not a single plant. Multiple grows share the same room environment. The data model should allow sensor readings at a room level, shared across grow entries in that room.
8 ⚠️ Minor No yield tracking compared to expected — The entity has expected_yield_grams and actual_yield_grams, which is great. But the plan doesn't mention a yield comparison/analytics view. Over time, I want to see yield trends per strain.
9 ⚠️ Minor No recurring grow templates — If I grow Northern Lights every 3 months with the same feeding schedule, I'd love to create a template and duplicate it. Not essential for v1, but worth noting.
10 Positive FullCalendar with drag-resize — Adjusting end dates by dragging is intuitive. Starting a new grow by clicking a date is natural. The de locale (German month names, Monday start) is correct for our users.
11 Positive Audit log integration — Grow entries and harvest-to-batch links are logged in the audit trail. This creates an unbroken record of cultivation activities for regulatory compliance.
12 ⚠️ Minor No strain-specific growing guides — It would be helpful to see default durations per stage for a given strain (e.g., Northern Lights typical flowering: 8 weeks). Auto-suggest end dates based on strain genetics. Future feature.

Scores

Dimension Score Rationale
Precision 84% Core entities (GrowEntry, SensorReading, GrowPhoto, FeedingSchedule) are well-defined with specific fields. Stage enum is complete. However, the room/location dimension is missing, and sensor-to-room relationship is not modeled.
Correctness 85% The stage progression, batch linking, and calendar visualization are all correct cannabis cultivation patterns. The sensor model (per-entry rather than per-room) is architecturally questionable but functionally correct for MVP.
Usability 88% FullCalendar with color-coded stages, drag-resize, and click-to-create is highly usable. Photo gallery with timeline is intuitive. Feeding schedule with calendar overlay reduces context switching.
Usefulness 90% This is the most comprehensive grow management I've seen in a club management app. The harvest-to-batch traceability alone justifies the feature. Sensors, photos, and feeding elevate it from a simple calendar to a real cultivation tool.

Composite Score: 87%

  • 🟡 Add room or location field to GrowEntry (simple VARCHAR, e.g., "Veg Room A", "Flower Room 1")
  • 🟡 Consider a SensorDevice entity linked to a room, with readings associated to the device rather than individual grow entries
  • Add yield analytics as a future enhancement (strain performance over time)
  • Note: templates and strain guides are clear Sprint 7+ features

Summary Matrix

Persona Precision Correctness Usability Usefulness Composite
👤 Club Member 88% 92% 86% 90% 89%
🏢 Club Owner / Vorstand 82% 88% 90% 93% 88%
💻 Developer 85% 87% 88% 91% 88%
🛡️ Datenschutzbeauftragter 84% 86% 90% 88% 87%
🔒 Security Auditor 83% 85% 91% 87% 87%
🌱 Cultivation Manager 84% 85% 88% 90% 87%
Average 84% 87% 89% 90% 88%

Verdict: 🟡 CONDITIONAL PASS (88% — below 85% target on Precision)

The Sprint 6 plan is ambitious and well-structured, covering all critical go-live requirements. However, it contains internal inconsistencies (pricing, trial period, server provider naming) and security gaps (CSP, backup encryption, DB-level audit protection) that must be resolved before implementation begins.

Overall assessment: The plan is implementable as-is for development purposes, but requires 4 must-fix items before production launch.


Priority Fix List

🔴 Must Fix (Blocking launch)

# Source Issue Fix
1 🏢 Owner Pricing tier discrepancy (D12 vs §3.3) Reconcile: pick €19/€49 or €29/€79. Update all references.
2 🏢 Owner Trial period discrepancy (3 months vs 14 days) Confirm business decision. Update D12 or Stripe code.
3 🔒 Security No Content-Security-Policy header Add CSP to Nginx config targeting Stripe JS domains.
4 🔒 Security Backups are unencrypted Add GPG/AES-256 encryption to backup script.
5 🔒 Security Audit log only app-level immutable Add PostgreSQL RULE or REVOKE DELETE on audit_event.
6 🛡️ DSGVO No Stripe AVV documentation Accept Stripe DPA, reference in Datenschutzerklärung.
7 🛡️ DSGVO Audit log retention period undefined Document legal basis (§257 HGB) + retention in privacy policy.
8 💻 Dev Phase 1 heading says "Hetzner" instead of "IONOS" Fix heading text.

🟡 Should Fix (Before launch, non-blocking for dev)

# Source Issue Fix
9 💻 Dev WebSocket auth mechanism unspecified Document STOMP CONNECT JWT or session-based auth.
10 💻 Dev allowedOriginPatterns("*") in production Restrict to cannamanage.plate-software.de.
11 💻 Dev Photo storage location undefined Document local filesystem path + future S3 migration.
12 💻 Dev Sensor device auth for IoT undefined Specify API key-based auth for devices.
13 🔒 Security JWT lifecycle not specified Define access token TTL (15min) + refresh token (7d).
14 🔒 Security .env file permissions not documented Add chmod 600 + root ownership requirement.
15 🛡️ DSGVO IP address storage not in privacy policy Add to Datenschutzerklärung with retention period.
16 🌱 Grower No room/location field on GrowEntry Add optional location VARCHAR field.
17 🌱 Grower Sensors modeled per-entry not per-room Consider SensorDevice entity linked to location.

🟢 Nice to Have (Sprint 7+)

# Source Issue Fix
18 👤 Member No granular notification preferences Add mute/category toggles in settings.
19 👤 Member No member-visible grow progress Read-only grow view for members.
20 🏢 Owner Dunning timeline not documented Add retry schedule documentation.
21 🌱 Grower No grow templates Duplicate-from-previous feature.
22 🌱 Grower No yield analytics Strain performance dashboard.
23 💻 Dev No blue-green deploy Two-step pull + up for zero-downtime.
24 🔒 Security No fail2ban integration Watch for 429s, auto-ban repeat offenders.

Recommendation

Proceed with development after resolving the 8 🔴 must-fix items (most are documentation/config corrections, not architectural changes). The plan is solid architecturally and covers all critical go-live requirements. Target the 🟡 items during implementation as they come up naturally in each phase.

Estimated fix effort: ~2 hours for document corrections (items 1, 2, 8), ~1 day for security hardening specs (items 37).