# Sprint 9 Implementation Plan — Berichtszentrale (Report Center) **Date:** 2026-06-15 **Author:** Patrick Plate / Lumen (Architect) **Status:** Draft v2 (incorporates panel review advisory items) **Basis:** cannamanage-sprint9-analysis.md **Sprint Goal:** Complete reporting & documentation module with authority-ready exports --- ## Implementation Phases Sprint 9 is organized into 6 phases, building from backend infrastructure to frontend polish. ```mermaid graph LR P1[Phase 1: Data Model + Backend Services] --> P2[Phase 2: Report Generators - Financial] P2 --> P3[Phase 3: Report Generators - KCanG Compliance] P3 --> P4[Phase 4: DSGVO Templates + Verein Reports] P4 --> P5[Phase 5: Frontend - Berichtszentrale + Sidebar Reorg] P5 --> P6[Phase 6: Compliance Dashboard + Retention + Integration Testing] ``` --- ## Phase 1: Data Model & Backend Infrastructure ### Step 1.1 — Database Migrations (V23-V28) **Files:** - `cannamanage-api/src/main/resources/db/migration/V23__destruction_records.sql` - `cannamanage-api/src/main/resources/db/migration/V24__transport_records.sql` - `cannamanage-api/src/main/resources/db/migration/V25__propagation_sources.sql` - `cannamanage-api/src/main/resources/db/migration/V26__prevention_activities.sql` - `cannamanage-api/src/main/resources/db/migration/V27__generated_reports.sql` - `cannamanage-api/src/main/resources/db/migration/V28__compliance_deadlines.sql` - `cannamanage-api/src/main/resources/db/migration/V29__distribution_thc_cbd.sql` **V29 specifically:** ```sql ALTER TABLE distributions ADD COLUMN IF NOT EXISTS thc_percentage NUMERIC(4,2); ALTER TABLE distributions ADD COLUMN IF NOT EXISTS cbd_percentage NUMERIC(4,2); ALTER TABLE distributions ADD COLUMN IF NOT EXISTS strain_name VARCHAR(200); ``` ### Step 1.2 — JPA Entities **New entities:** - `de.cannamanage.domain.entity.DestructionRecord` - `de.cannamanage.domain.entity.TransportRecord` - `de.cannamanage.domain.entity.PropagationSource` - `de.cannamanage.domain.entity.PreventionActivity` - `de.cannamanage.domain.entity.GeneratedReport` - `de.cannamanage.domain.entity.ComplianceDeadline` **Modified entities:** - `Distribution` — add `thcPercentage`, `cbdPercentage`, `strainName` fields ### Step 1.3 — Repositories - `DestructionRecordRepository` - `TransportRecordRepository` - `PropagationSourceRepository` - `PreventionActivityRepository` - `GeneratedReportRepository` - `ComplianceDeadlineRepository` Each with standard tenant-scoped queries + date range filters. ### Step 1.4 — Base Report Service Infrastructure **New file:** `cannamanage-service/src/main/java/de/cannamanage/service/report/ReportGenerator.java` ```java /** * Base interface for all report generators. * Standardizes the contract across 18+ report types. * Each implementation handles one ReportType. */ public interface ReportGenerator { ReportType getType(); byte[] generatePdf(T params); default byte[] generateCsv(T params) { throw new UnsupportedOperationException("CSV not supported for " + getType()); } default byte[] generateJson(T params) { throw new UnsupportedOperationException("JSON not supported for " + getType()); } Set supportedFormats(); } ``` **New file:** `cannamanage-service/src/main/java/de/cannamanage/service/ReportGeneratorService.java` ```java @Service public class ReportGeneratorService { // Central orchestrator — delegates to typed ReportGenerator implementations // Auto-discovers all ReportGenerator beans via Spring injection // Handles: format dispatch, audit logging, document storage // Rate-limited: max 5 generations per minute per tenant (via @RateLimiter) private final Map> generators; public ReportGeneratorService(List> allGenerators) { this.generators = allGenerators.stream() .collect(Collectors.toMap(ReportGenerator::getType, Function.identity())); } @RateLimiter(name = "reportGeneration", fallbackMethod = "rateLimitFallback") public GeneratedReport generateReport(ReportType type, ReportParameters params); public byte[] exportAsPdf(ReportType type, ReportParameters params); public byte[] exportAsCsv(ReportType type, ReportParameters params); public byte[] exportAsJson(ReportType type, ReportParameters params); private GeneratedReport rateLimitFallback(ReportType type, ReportParameters params, Exception ex) { throw new TooManyRequestsException("Report generation rate limit exceeded. Max 5 per minute."); } } ``` > **Advisory implementation (v2):** The `ReportGenerator` interface provides a standardized contract across all 18+ report generators. This enables consistent error handling, format negotiation, and future plugin extensibility without requiring every generator to implement all formats. Rate limiting (max 5/min/tenant) is enforced at the orchestrator level via Resilience4j `@RateLimiter`. **New file:** `cannamanage-service/src/main/java/de/cannamanage/service/RetentionService.java` ```java @Service public class RetentionService { // Scheduled daily: checks retention periods // Flags records approaching end-of-retention // Never auto-deletes — requires admin confirmation @Scheduled(cron = "0 0 2 * * *") // 2 AM daily public void checkRetentionPeriods(); public List getPendingAlerts(UUID tenantId); } ``` ### Step 1.5 — REST Controllers for New Entities - `DestructionRecordController` — CRUD + PDF generation - `TransportRecordController` — CRUD + certificate generation - `PropagationSourceController` — CRUD - `PreventionActivityController` — CRUD - `ComplianceDeadlineController` — CRUD + status updates - `ReportController` (enhanced) — all report generation endpoints ### Step 1.6 — Enums **New enums in `cannamanage-domain`:** - `ReportType` — `ANNUAL_AUTHORITY`, `DISTRIBUTION_LOG`, `STOCK_INVENTORY`, `DESTRUCTION_PROTOCOL`, `CULTIVATION_REPORT`, `TRANSPORT_CERTIFICATE`, `FULL_AUTHORITY_EXPORT`, `EUR`, `ANNUAL_FINANCIAL`, `KASSENBUCH_EXPORT`, `FEE_CONFIRMATION`, `MEMBER_LIST_REGISTRY`, `BOARD_CHANGE_NOTICE`, `ANNUAL_BOARD_REPORT`, `VVT`, `TOM`, `DSFA`, `DELETION_CONCEPT`, `BREACH_NOTIFICATION` - `DestructionMethod` — `INCINERATION`, `COMPOSTING`, `CHEMICAL`, `OTHER` - `TransportStatus` — `PLANNED`, `AUTHORITY_NOTIFIED`, `IN_TRANSIT`, `COMPLETED` - `ComplianceArea` — `KCANG`, `FINANCE`, `DSGVO`, `VEREIN` - `ComplianceStatus` — `GREEN`, `YELLOW`, `RED` - `RetentionCategory` — `KCANG_5Y`, `AO_6Y`, `AO_8Y`, `AO_10Y`, `INDEFINITE` --- ## Phase 2: Financial Report Generators ### Step 2.1 — EÜR (Einnahmen-Überschuss-Rechnung) Generator **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/EurReportGenerator.java` Logic: 1. Query all `financial_transactions` for the selected calendar year 2. Group into Einnahmen (INCOME transactions) and Ausgaben (EXPENSE transactions) 3. Sub-group by `expense_category` / income source 4. Calculate: Total income, total expenses, Überschuss/Fehlbetrag 5. Include: Opening balance (Jan 1) and closing balance (Dec 31) 6. Generate PDF in standard EÜR format (Anlage EÜR compatible structure) 7. Generate CSV with semicolons, ISO-8859-1, German decimal format **PDF Structure:** ``` EINNAHMEN-ÜBERSCHUSS-RECHNUNG Kalenderjahr: 2025 Verein: Grüner Daumen e.V. I. EINNAHMEN Mitgliedsbeiträge ................ 54.000,00 € Sonstige Einnahmen ............... 2.400,00 € ───────────────────────────────────────────── Summe Einnahmen .................. 56.400,00 € II. AUSGABEN Miete/Pacht ...................... 18.000,00 € Strom/Energie .................... 4.800,00 € Cannabis-Anbaumaterial ........... 12.000,00 € Verwaltung ....................... 3.600,00 € Versicherungen ................... 2.400,00 € Sonstige Ausgaben ................ 5.200,00 € ───────────────────────────────────────────── Summe Ausgaben ................... 46.000,00 € III. ERGEBNIS Überschuss ....................... 10.400,00 € ``` ### Step 2.2 — Enhanced Kassenbuch Export **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/KassenbuchExportGenerator.java` Enhance existing Kassenbuch with: - DATEV-compatible CSV format (optional export) - GoBD-compliant: immutable entries, sequential numbering, no gaps - Period selection (monthly, quarterly, annual) - Running balance per entry - Category totals at bottom ### Step 2.3 — Beitragsbescheinigung (Fee Confirmation per Member) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/FeeConfirmationGenerator.java` - Per-member annual PDF: confirms total fees paid in calendar year - Letterhead with club name, address, Vereinsregisternummer - Suitable for member's tax records (Sonderausgaben) - Batch generation: one click → all active members get a PDF ### Step 2.4 — Jahresabschluss Enhancement Enhance existing Sprint 8 annual report with: - Comparison to previous year (if data exists) - Category-wise breakdown with percentages - Chart data (for frontend visualization) - Kassenprüfer-ready format (signature lines) --- ## Phase 3: KCanG Compliance Report Generators ### Step 3.1 — Annual Authority Report (§26 Abs. 3 KCanG) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/AnnualAuthorityReportGenerator.java` **THE most important report.** Due January 31 each year. Logic: 1. Query all harvests (from grow module) in calendar year → sum by strain + THC/CBD 2. Query all distributions in calendar year → sum by strain + THC/CBD 3. Query all destruction records in calendar year → sum by strain + THC/CBD 4. Query stock snapshot as of Dec 31 → by strain + THC/CBD 5. Validate: cultivated - distributed - destroyed ≈ stock change (flag discrepancies) 6. Format into authority-mandated structure **Output format (PDF + JSON):** ```json { "anbauvereinigung": { "name": "...", "erlaubnisnummer": "...", "anschrift": "..." }, "berichtszeitraum": { "von": "2025-01-01", "bis": "2025-12-31" }, "angebaute_mengen": [ { "sorte": "Amnesia Haze", "menge_gramm": 5000, "thc_prozent": 18.5, "cbd_prozent": 0.8 } ], "weitergegebene_mengen": [...], "vernichtete_mengen": [...], "bestand_jahresende": [...] } ``` ### Step 3.2 — Distribution Log (§26 Abs. 1 Nr. 5) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/DistributionLogGenerator.java` - Date-range selectable log of all distributions - Per entry: Datum, Mitglied (Name, Vorname, Geburtsjahr), Menge (g), THC%, Sorte - Summary: total grams, unique members, average per member - Flags any quota violations (>25g/day, >50g/month, >30g/month for 18-21, >10% THC for 18-21) - PDF + CSV export ### Step 3.3 — Stock Inventory Report (§26 Abs. 1 Nr. 2) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/StockInventoryReportGenerator.java` - Point-in-time snapshot of all cannabis + propagation material on premises - By strain: grams available, THC%, CBD%, harvest date - Propagation material: count by type (seeds, clones, cuttings) - Includes stock movements for selected period (in/out/destroyed) ### Step 3.4 — Destruction Protocol (§26 Abs. 1 Nr. 4) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/DestructionProtocolGenerator.java` - Official Vernichtungsprotokoll PDF - Per destruction event: date, batch, strain, grams, method, reason, witness - Dual signature lines (destroying person + witness) - Sequential protocol number - Cumulative annual destruction total ### Step 3.5 — Cultivation Report (§26 Abs. 1 Nr. 3) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/CultivationReportGenerator.java` - Harvest data from grow module - Per harvest: strain, grams harvested, THC%, CBD%, harvest date, grow cycle ID - Annual total by strain - Growth cycle overview (planted → harvested → distributed/destroyed) ### Step 3.6 — Transport Certificate (§22 Abs. 4 KCanG) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/TransportCertificateGenerator.java` Per §22(4), the certificate must contain: 1. Name und Anschrift des Sitzes der Anbauvereinigung 2. Datum des Transports 3. Start- und Zieladresse des Transports 4. Mengen in Gramm und Sorten des transportierten Cannabis 5. Name und Kontaktdaten der zuständigen Behörde Generate as a single-page PDF, suitable for printing and carrying during transport. ### Step 3.7 — Full Authority Export (§26 Abs. 2 + §27) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/FullAuthorityExportGenerator.java` The "panic button" — generates EVERYTHING the authority needs in one package: 1. All distribution records (complete §26(1) Nr. 5 data) 2. Stock movement history 3. All destruction records 4. All cultivation records 5. All transport records 6. Propagation material sources 7. Member register (name + birth year only, per DSGVO minimization) **Security:** Requires re-authentication (password re-entry) before generation. This is a high-sensitivity operation containing all member distribution histories (Art. 9 DSGVO health data). The confirmation dialog includes a mandatory reason field for the audit trail. > **Advisory implementation (v2):** Re-authentication gate added per Security Expert recommendation. The endpoint requires a fresh authentication token (max 30 seconds old) obtained via `POST /api/auth/reconfirm` before the export can proceed. **Output:** ZIP file — **streamed** (not buffered in memory): - Uses `StreamingResponseBody` to write ZIP entries directly to the HTTP response - For clubs with 5+ years and 500 members, exports can reach 50MB+ - Streaming avoids `OutOfMemoryError` on the server > **Advisory implementation (v2):** Streaming ZIP generation per Architecture Expert recommendation. Uses `ZipOutputStream` wrapping `ServletOutputStream` directly — entries are written sequentially without buffering the entire archive in heap memory. **ZIP contents:** - `README.txt` — explains contents and legal basis - `distributions.json` + `distributions.csv` - `stock.json` - `destructions.json` - `cultivation.json` - `transports.json` - `members.json` (anonymized: name + birth year only) - `summary.pdf` — human-readable overview ### Step 3.8 — Distribution Info Sheet (§21 Abs. 2 KCanG) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/DistributionInfoSheetGenerator.java` Printable info sheet that must be handed out at every distribution: - Weight in grams - Harvest date - Best-before date - Strain name - Average THC% - Average CBD% - Health warnings (§21(3) — standardized text) Generate as small PDF (A5 or 1/3 A4) — can be batch-printed. --- ## Phase 4: DSGVO Templates & Verein Administrative Reports ### Step 4.1 — Verarbeitungsverzeichnis (VVT) Generator **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/VvtGenerator.java` Pre-filled template for Anbauvereinigungen: - 8 standard processing activities pre-defined (member mgmt, distributions, finance, video, etc.) - Club-specific data filled in (name, address, DPO name if applicable) - Output: PDF (A4, multi-page table format per Art. 30 requirements) ### Step 4.2 — TOM (Technisch-Organisatorische Maßnahmen) Document **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/TomGenerator.java` Checklist-style PDF with: - Zutrittskontrolle (physical access) - Zugangskontrolle (system access — passwords, 2FA) - Zugriffskontrolle (data access — roles, permissions) - Trennungskontrolle (purpose limitation) - Pseudonymisierung/Verschlüsselung - Verfügbarkeit und Belastbarkeit (backups, disaster recovery) - Verfahren zur regelmäßigen Überprüfung Pre-filled with what CannaManage provides (encryption, role-based access, audit log, etc.). ### Step 4.3 — DSFA (Datenschutz-Folgenabschätzung) Template **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/DsfaGenerator.java` Required because cannabis distribution data = health-related data (Art. 9 DSGVO). Structure: 1. Beschreibung der Verarbeitung (automated from VVT) 2. Bewertung der Notwendigkeit (pre-filled: §26 KCanG mandates the processing) 3. Risikobewertung (template with common risks pre-identified) 4. Abhilfemaßnahmen (auto-filled from TOM document) ### Step 4.4 — Löschkonzept (Deletion Concept) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/DeletionConceptGenerator.java` Documents when each category of data is deleted: - Maps data categories → retention periods → deletion triggers - References §26(2) KCanG (5 years), §147 AO (6/8/10 years) - Describes the automated retention checking (RetentionService) - Lists manual review process ### Step 4.4b — Breach Notification Template (Art. 33/34 DSGVO) — **P1** **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/BreachNotificationGenerator.java` > **Advisory implementation (v2):** Elevated from P2 to P1 per Risk/Compliance Expert recommendation. Cannabis distribution data is Art. 9 DSGVO health data — a breach could cause significant harm (employment discrimination, social stigma). Having the template ready before an incident occurs is critical. Pre-filled breach notification PDF with: - Art. 33 fields: nature of breach, categories of data subjects affected, approximate number, DPO contact, likely consequences, measures taken - Art. 34 fields: communication to affected data subjects (plain language) - Auto-fills club details, DPO info, and data category descriptions from VVT - Checklist: 72-hour notification deadline reminder, authority contact details - Editable fields for incident-specific details (what happened, when discovered) **Priority justification:** A cannabis club experiencing a data breach has 72 hours to notify the Landesdatenschutzbehörde. Without a pre-prepared template, clubs will scramble under pressure and risk non-compliance with Art. 33(1) DSGVO. Given the sensitivity of cannabis health data, this is P1. ### Step 4.5 — Mitgliederliste für Vereinsregister **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/MemberListRegistryGenerator.java` Formatted per BGB requirements for Vereinsregister: - Minimal data: Name, Vorname, Anschrift, Eintrittsdatum - Sorted alphabetically - Includes total count and date of generation - Footer: "Erstellt gemäß §67 BGB" ### Step 4.6 — Vorstandsänderung-Meldung (Board Change Template) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/BoardChangeNoticeGenerator.java` Template for notifying Registergericht of board changes: - Old board composition - New board composition (from board_members table) - Date of election (from assembly records) - Reference to MV protocol - Signature line for new Vorstand ### Step 4.7 — Jahresbericht des Vorstands (Annual Board Report) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/report/AnnualBoardReportGenerator.java` Combines multiple data sources into a report the Vorstand presents to members at the annual MV: - Member statistics (new, left, total) - Financial summary (from EÜR) - Compliance status (KCanG obligations met) - Key activities (from prevention log, assemblies held, etc.) - Outlook/plans (editable text section) --- ## Phase 5: Frontend — Berichtszentrale & Sidebar Reorganization ### Step 5.1 — Sidebar Reorganization **Modified file:** `cannamanage-frontend/src/data/navigations.ts` Replace flat list with grouped, collapsible sections: ```typescript export const navigationsData: NavigationType[] = [ { title: "Betrieb", icon: "Leaf", items: [ { title: "Dashboard", href: "/dashboard", iconName: "LayoutDashboard" }, { title: "Mitglieder", href: "/members", iconName: "Users" }, { title: "Ausgabe", href: "/distributions", iconName: "Leaf" }, { title: "Lager", href: "/stock", iconName: "Package" }, { title: "Anbau", href: "/grow", iconName: "Sprout" }, ], }, { title: "Kommunikation", icon: "MessageCircle", items: [ { title: "Schwarzes Brett", href: "/info-board", iconName: "Megaphone" }, { title: "Kalender", href: "/calendar", iconName: "Calendar" }, { title: "Forum", href: "/forum", iconName: "MessageSquare" }, ], }, { title: "Verwaltung", icon: "Building", items: [ { title: "Finanzen", href: "/finance", iconName: "Wallet" }, { title: "Versammlungen", href: "/assemblies", iconName: "Gavel" }, { title: "Dokumente", href: "/documents", iconName: "FileArchive" }, { title: "Vorstand", href: "/board", iconName: "Shield" }, { title: "Personal", href: "/settings/staff", iconName: "UserCog" }, ], }, { title: "Compliance", icon: "ShieldCheck", items: [ { title: "Berichtszentrale", href: "/reports", iconName: "FileBarChart" }, { title: "Protokoll", href: "/audit-log", iconName: "ScrollText" }, { title: "Einstellungen", href: "/settings", iconName: "Settings" }, ], }, ] ``` **Modified component:** Sidebar must support collapsible groups with section headers and icons. ### Step 5.2 — Berichtszentrale Page (Report Center) **New page:** `cannamanage-frontend/src/app/(app)/reports/page.tsx` (replaces existing basic reports page) Layout: - Top: Compliance status cards (4 cards: KCanG 🟢/🟡/🔴, Finanzen, DSGVO, Verein) - Middle: Upcoming deadlines list (next 90 days) - Bottom: Report categories as card grid with accordion sub-items **Empty-state handling (new clubs):** > **Advisory implementation (v2):** Per UX Expert recommendation — when a club first accesses the Berichtszentrale with no reports generated yet, all compliance indicators will be 🔴 RED. To prevent this from being demoralizing, display a "Compliance Setup" guided callout instead of raw red indicators. When `generated_reports` is empty for this tenant: - Show a "Erste Schritte" banner with 4-step setup guide: 1. "VVT erstellen" → links to DSGVO tab 2. "Jahresbericht konfigurieren" → links to KCanG tab 3. "Kassenbuch einrichten" → links to Finance tab 4. "Fristen prüfen" → links to deadlines view - Compliance cards show "Einrichtung erforderlich" (setup required) in neutral gray instead of alarming red - After first report is generated in any category, switch to normal traffic-light indicators - Dismissible: admin can click "Verstanden, Dashboard anzeigen" to skip directly to normal view Each report card shows: - Report name - Last generated date (or "Noch nie erstellt") - Legal basis reference - [Generate PDF] [Generate CSV] [Generate JSON] buttons (as applicable) - [View History] link ### Step 5.3 — Report Category Pages **New pages:** - `/reports/finance` — Financial reports tab - `/reports/compliance` — KCanG reports tab - `/reports/verein` — Administrative reports tab - `/reports/dsgvo` — Data protection reports tab Each with: - List of available reports in that category - Generation form (date range, parameters) - Preview before download - Download history table ### Step 5.4 — Destruction Record Management **New pages:** - `/stock/destructions` — List all destruction records - `/stock/destructions/new` — Record a new destruction event Form fields: Batch selection, grams destroyed, propagation count, method, reason, witness name, date. ### Step 5.5 — Transport Record Management **New pages:** - `/transports` (or nested under operations) - `/transports/new` — Plan a new transport (with authority notification reminder) - `/transports/[id]/certificate` — View/download transport certificate ### Step 5.6 — Prevention Activity Log **New page:** - `/board/prevention` — Prevention officer activity log List of activities + "Add Activity" form. Shows training certificate info. ### Step 5.7 — Report Services (Frontend) **New file:** `cannamanage-frontend/src/services/report-center.ts` ```typescript // Report generation triggers export function useGenerateReport(type: ReportType, params: ReportParams) export function useReportHistory(type?: ReportType) export function useComplianceStatus() export function useUpcomingDeadlines() export function useDestructionRecords() export function useTransportRecords() export function usePreventionActivities() ``` ### Step 5.8 — i18n Additions **Modified files:** - `cannamanage-frontend/messages/de.json` — all new report names, categories, form labels - `cannamanage-frontend/messages/en.json` — English translations --- ## Phase 6: Compliance Dashboard + Retention + Integration ### Step 6.1 — Compliance Status Service (Backend) **File:** `cannamanage-service/src/main/java/de/cannamanage/service/ComplianceDashboardService.java` Calculates real-time compliance status per area: ```java public ComplianceStatus getOverallStatus(UUID tenantId) { // KCanG: Check if annual report was submitted, distribution records complete // Finance: Check if EÜR generated for last fiscal year // DSGVO: Check if VVT exists and is recent // Verein: Check board term expiry, next MV date // Yellow = deadline within 30 days or data gaps // Red = deadline passed or critical gaps // Green = everything current } ``` ### Step 6.2 — Deadline Seeding + Scheduler **File:** `cannamanage-service/src/main/java/de/cannamanage/service/ComplianceDeadlineScheduler.java` On tenant creation (or first report center access): - Seed standard annual deadlines (Jan 31 authority report, MV, EÜR) - Daily scheduler checks for approaching deadlines → creates notifications - Auto-rolls annual deadlines to next year after completion ### Step 6.3 — Retention Service Implementation Implements the daily retention check: - Queries all data categories - Compares creation date against retention period rules - Creates admin notification when data approaches end-of-retention - Provides "Löschprotokoll" (deletion log) export ### Step 6.4 — API Endpoint Summary New REST endpoints: ``` # Destruction Records POST /api/destructions GET /api/destructions GET /api/destructions/{id} GET /api/destructions/{id}/pdf # Transport Records POST /api/transports GET /api/transports GET /api/transports/{id} GET /api/transports/{id}/certificate/pdf POST /api/transports/{id}/notify-authority # Propagation Sources POST /api/propagation-sources GET /api/propagation-sources DELETE /api/propagation-sources/{id} # Prevention Activities POST /api/prevention-activities GET /api/prevention-activities DELETE /api/prevention-activities/{id} # Report Center POST /api/reports/generate (body: {type, params}) GET /api/reports/history GET /api/reports/{id}/download # Specific Report Generators GET /api/reports/eur/pdf?year=2025 GET /api/reports/eur/csv?year=2025 GET /api/reports/authority-annual/pdf?year=2025 GET /api/reports/authority-annual/json?year=2025 GET /api/reports/distribution-log/pdf?from=&to= GET /api/reports/distribution-log/csv?from=&to= GET /api/reports/stock-inventory/pdf?date= GET /api/reports/destruction-protocol/pdf?from=&to= GET /api/reports/cultivation/pdf?year= GET /api/reports/transport-certificate/{id}/pdf GET /api/reports/authority-export/zip?from=&to= GET /api/reports/member-list-registry/pdf GET /api/reports/board-change-notice/pdf GET /api/reports/annual-board-report/pdf?year= GET /api/reports/vvt/pdf GET /api/reports/tom/pdf GET /api/reports/dsfa/pdf GET /api/reports/deletion-concept/pdf GET /api/reports/fee-confirmation/pdf?memberId=&year= GET /api/reports/fee-confirmation/batch/zip?year= GET /api/reports/info-sheet/{distributionId}/pdf # Compliance Dashboard GET /api/compliance/status GET /api/compliance/deadlines PUT /api/compliance/deadlines/{id}/complete ``` ### Step 6.5 — Integration Testing - Test each report generator with realistic data - Verify PDF output quality (correct German formatting, legal references) - Verify CSV encoding (ISO-8859-1, semicolons, decimal comma) - Verify JSON schema for authority export - Test retention service with date manipulation - Test compliance status calculation edge cases - E2E: Generate report from frontend → download → verify contents ### Step 6.6 — Seed Data Enhancement Extend existing seed data with: - Sample destruction records - Sample transport records - Sample propagation sources - Prevention activities - Pre-seeded compliance deadlines for demo - THC/CBD percentages on existing distribution seeds --- ## Technical Decisions | Decision | Choice | Rationale | |----------|--------|-----------| | PDF library | Reuse existing OpenPDF | Proven in Sprint 5+8, already in dependencies | | CSV encoding | ISO-8859-1 + semicolons | German DATEV standard, accountants expect this | | CSV injection prevention | Prefix dangerous cells with single quote | Cells starting with `=`, `+`, `-`, `@` get `'` prefix to prevent Excel formula injection | | JSON schema | Custom (no standard exists) | KCanG is too new for an official schema — we define it | | ZIP generation | `java.util.zip.ZipOutputStream` via `StreamingResponseBody` | Standard library, streamed to avoid OOM on large exports | | Report storage | Database record + file in documents module | Reuse existing document storage from Sprint 8 | | Retention checking | Spring `@Scheduled` | Simple, already used for payment reminders | | Rate limiting | Resilience4j `@RateLimiter` — 5 reports/min/tenant | Prevents DoS via report generation spam (CPU-intensive PDF rendering) | | Authority export auth | Re-authentication required (password re-entry) | High-sensitivity: contains all member health data | | Sidebar state | LocalStorage for collapsed/expanded | No backend needed, instant UX | | Report preview | Server-side rendered HTML → PDF | Same template for preview and final PDF | | Empty-state UX | Guided setup banner for new clubs | Prevents demoralizing all-red compliance dashboard on first access | > **Advisory implementations (v2):** CSV injection prevention, rate limiting, re-authentication gate, streaming ZIP, and empty-state UX all added per panel review recommendations. --- ## File Count Estimate | Phase | New Backend Files | New Frontend Files | Modified Files | |-------|------------------|--------------------|----------------| | Phase 1 | ~18 (entities, repos, controllers, enums) | 0 | 3 (Distribution entity, pom.xml) | | Phase 2 | ~5 (report generators) | 0 | 1 (existing ReportService) | | Phase 3 | ~9 (report generators) | 0 | 0 | | Phase 4 | ~8 (report generators) | 0 | 0 | | Phase 5 | 0 | ~20 (pages, components, services) | 5 (sidebar, navigations, i18n) | | Phase 6 | ~4 (services, schedulers) | ~3 (dashboard components) | 2 (seed data) | | **Total** | **~44** | **~23** | **~11** | --- ## Dependencies & Risks | Risk | Probability | Impact | Mitigation | |------|-------------|--------|------------| | Authority report format changes | Low (KCanG is new) | Medium | JSON export is flexible, PDF regenerable | | DSGVO template incomplete | Medium | Low | Templates are editable, clubs can customize | | PDF formatting issues with German umlauts | Low | Low | OpenPDF handles UTF-8, already proven | | Retention period legal ambiguity (§26 "5 Jahre" — from when?) | Medium | Medium | Conservative: 5 years from record creation + admin review | | Large data export performance | Low | Medium | Stream responses, chunked ZIP generation | | Sidebar reorg breaks existing bookmarks | Low | Low | URL paths stay the same, only visual grouping changes | --- ## Success Criteria 1. ✅ All P0 reports generate valid PDFs with correct German formatting 2. ✅ Authority annual report (§26(3)) produces complete, accurate data 3. ✅ Full authority export generates machine-readable JSON bundle 4. ✅ EÜR matches standard format for Finanzamt submission 5. ✅ Sidebar is grouped and collapsible with no functionality loss 6. ✅ Compliance dashboard shows correct status for all 4 areas 7. ✅ Retention service identifies records approaching end-of-life 8. ✅ All exports respect DSGVO data minimization (birth year, not full DOB in authority exports) 9. ✅ CSV exports use correct encoding (ISO-8859-1) and delimiter (semicolons) 10. ✅ Report history tracks what was generated when and by whom