Patrick Plate
3ca231dc9c
feat(sprint9): Phase 3 — KCanG compliance reports + Behörden-Export
...
Implemented 6 KCanG compliance report generators and the hero
Behörden-Export feature:
- AnnualAuthorityReportGenerator: Multi-section §22 KCanG annual report
(9 sections: Vereinsdaten, Mitgliederstatistik, Anbauübersicht,
Weitergabe-Statistik, Bestandsführung, Vernichtung, Transport,
Prävention, Jugendschutz)
- DistributionLogGenerator: §19(4) distribution log (PDF+CSV,
anonymized member data per DSGVO)
- DestructionProtocolGenerator: §22 destruction protocol with
signature lines and sequential numbering
- TransportCertificateGenerator: §22(4) transport documentation
- BestandsfuehrungGenerator: Stock flow report (PDF+CSV) with
per-batch breakdown
- PreventionActivityReportGenerator: §23 prevention activities
Authority Export (Behörden-Export) — THE HERO FEATURE:
- AuthorityExportService: Streaming ZIP generation via ZipOutputStream
- Re-authentication required (password re-entry + BCrypt verification)
- Mandatory reason field stored in audit trail
- Rate limited: max 1 export per hour per tenant
- ZIP contains all compliance PDFs + anonymized member JSON + manifest
- Memory-efficient: PDFs generated and streamed sequentially
Endpoint: POST /api/v1/reports/authority-export
Request: { year, password, reason }
Response: StreamingResponseBody (application/zip)
Also enhanced repositories:
- DestructionRecordRepository: date-range queries + sum aggregation
- TransportRecordRepository: date-range queries
2026-06-15 12:53:12 +02:00
Patrick Plate
a29c38756c
feat(sprint9): Phase 2 — Financial report generators (EÜR, Kassenbuch, Beitragsbescheinigung)
...
Implements Sprint 9 Phase 2 financial report generators:
- MemberReportParameters: new parameter record for per-member reports
- EurReportGenerator: Einnahmen-Überschuss-Rechnung (§4(3) EStG)
- PDF: professional layout with income/expense sections, monthly breakdown
- CSV: semicolon-delimited, ISO-8859-1, German decimal format
- JSON: ELSTER-compatible structure for Steuerberater import
- KassenbuchExportGenerator: GoBD-compliant cash book export
- PDF: landscape A4, running balance, sequential Beleg-Nr
- CSV: GoBD-compliant format with injection prevention
- Includes opening balance calculation and period totals
- BeitragsbescheinigungGenerator: membership fee confirmation per member
- PDF: club letterhead, payment table, signature lines
- For member tax purposes (Sonderausgaben)
- ReportGeneratorService: added getAvailableTypes() method
- ReportController: added GET /api/v1/reports/types endpoint
All generators are @Service beans auto-discovered by ReportGeneratorService.
Docker build verified green.
2026-06-15 12:22:53 +02:00
Patrick Plate
26a77dd269
feat(sprint9): Phase 1 — Data model + ReportGenerator infrastructure
...
- 7 new enums: ReportType, ExportFormat, DestructionMethod, TransportStatus,
ComplianceArea, ComplianceStatus, RetentionCategory
- Extended: StaffPermission (+3), AuditEventType (+5), NotificationType (+2)
- Flyway V23-V29: destruction_records, transport_records, propagation_sources,
prevention_activities, generated_reports, compliance_deadlines, distribution THC/CBD
- 6 new JPA entities extending AbstractTenantEntity
- 6 new Spring Data repositories with tenant-scoped queries
- ReportGenerator<T> interface + ReportGeneratorService (auto-discovery, format dispatch)
- ComplianceRecordsController (CRUD for destruction/transport/propagation/prevention)
- ComplianceDeadlineController (create, list, complete, overdue)
- DateRangeReportParameters record for report generation
2026-06-15 12:01:06 +02:00
Patrick Plate
61b0cd92be
feat(sprint8): Phase 5+6 — Integration, schedulers, tier enforcement, testing
...
Phase 5 — Integration:
- PaymentReminderScheduler: monthly cron at 9am, sends PAYMENT_REMINDER
and PAYMENT_OVERDUE (30+ days) notifications, audit logged
- BoardTermScheduler: daily cron at 8am, sends BOARD_TERM_EXPIRING
notification 30 days before term end (1-day window for single delivery)
- Assembly protocol auto-archive: completeAssembly() generates PDF via
AssemblyProtocolService and stores it in DocumentService.archiveProtocol()
- PlanTierService: Sprint 8 limits added (Kassenbuch 3mo starter, 1 MV/year
starter, 100MB/1GB/unlimited document storage)
- Notification wiring: PAYMENT_RECEIVED sent to member on recordPayment(),
sendToAllMembers() added to NotificationService for assembly invitations
- Seed data: 2 fee schedules (Regular €30, Reduced €15), 4 fee assignments,
3 sample payments, 2 board positions, 2 board members
Phase 6 — Testing infrastructure:
- V22 migration: protocol_document_id on assemblies table
- Schedulers disabled in test profile (cannamanage.schedulers.enabled=false)
- Scheduler property configurable via SCHEDULERS_ENABLED env var
Additional fixes (pre-existing Phase 4 issues):
- AssemblyProtocolService: fixed Document import ambiguity (OpenPDF vs entity)
- AuditService: added convenience overloads for UUID actorId/clubId
- ReceiptPdfService: fixed getReceiptNumber/getMemberNumber/getPaymentDate
- StaffPermissionChecker: added getUserId/getClubId/getTenantId helpers
- FinanceService: added getPaymentById, exportLedgerCsv methods
2026-06-15 09:22:49 +02:00
Patrick Plate
e4698827ee
feat(sprint8): Phase 4 — Dokumentenarchiv + Vorstandsverwaltung
...
Backend:
- V20 migration: documents table with category, access_level, file storage
- V21 migration: board_positions + board_members with term tracking
- Document entity + DocumentCategory/DocumentAccessLevel enums
- BoardPosition + BoardMember entities
- Extended AuditEventType (DOCUMENT_UPLOADED/DELETED, BOARD_MEMBER_ELECTED/REMOVED)
- Extended StaffPermission (MANAGE_DOCUMENTS)
- Extended NotificationType (BOARD_TERM_EXPIRING)
- DocumentService: upload, list, download, delete, storage usage
- BoardService: positions CRUD, elect/remove members, current/history
- DocumentController: multipart upload, filtered list, download, delete, portal
- BoardController: positions, elect, remove, current board, history, portal
Frontend:
- documents.ts + board.ts service layers
- Admin /documents page: grouped by category, upload dialog, filter, download/delete
- Admin /board page: current board cards, position management, elect member dialog
- Navigation: added Dokumente + Vorstand to sidebar
- i18n: documents.* + board.* keys in de.json + en.json
2026-06-15 08:53:38 +02:00
Patrick Plate
b22702317a
feat(sprint8): Phase 3 — Mitgliederversammlung (assemblies, voting, protocol PDF)
...
Backend:
- V19 migration: assemblies, assembly_agenda_items, assembly_attendees, assembly_votes, assembly_vote_records
- Enums: AssemblyType, AssemblyStatus, AgendaItemType, VoteType, VoteDecision, VoteResult
- Entities: Assembly, AssemblyAgendaItem, AssemblyAttendee, AssemblyVote, AssemblyVoteRecord
- Repositories: Assembly, AgendaItem, Attendee, Vote, VoteRecord
- AssemblyService: full lifecycle (create, invite, start, attend, vote, quorum, complete)
- AssemblyProtocolService: OpenPDF protocol generation (§147 AO compliant)
- AssemblyController: admin + portal endpoints
- Extended: AuditEventType, NotificationType, StaffPermission
Frontend:
- Assembly service with full API client and TypeScript types
- Admin assemblies list page with create dialog (agenda builder)
- Admin assembly detail page (quorum, agenda, votes, attendees)
- Navigation: Versammlungen with Gavel icon (after Finanzen)
Legal basis: §32-§40 BGB (Mitgliederversammlung), §147 AO (retention)
2026-06-15 08:39:10 +02:00
Patrick Plate
3211ade5be
feat(sprint8): Phase 2 — Treasury frontend + PDF receipts
...
Backend:
- ReceiptPdfService: Generates Quittung PDF per payment (OpenPDF, A4)
- FinancialReportService: Annual financial report PDF (Jahresabschluss)
- FinanceController: Added receipt download, annual report, CSV export endpoints
- Portal receipt download with member ownership verification
Frontend:
- src/services/finance.ts: Complete React Query service (types, hooks, mutations)
- /finance: Dashboard with KPI cards, recent transactions, outstanding members
- /finance/payments: Payment list with filtering, void, receipt download
- /finance/kassenbuch: Kassenbuch ledger with date range, CSV export
- /finance/fee-schedules: Fee schedule CRUD with interval management
- /finance/reports: Annual report PDF download
- /portal/finance: Member self-service balance + payment history + receipts
Navigation & i18n:
- Added Finanzen (Wallet icon) to admin sidebar
- Portal finance page for member payments
- Comprehensive de.json + en.json finance keys (~100 translations)
2026-06-15 08:24:43 +02:00
Patrick Plate
721503b231
feat(sprint8): Phase 1 — Treasury backend (fee schedules, payments, Kassenbuch)
...
- Extend StaffPermission with MANAGE_FINANCES, VIEW_FINANCES
- Extend AuditEventType with PAYMENT_RECORDED, PAYMENT_VOIDED, FEE_SCHEDULE_CREATED, FEE_SCHEDULE_UPDATED, EXPENSE_RECORDED
- Extend NotificationType with PAYMENT_REMINDER, PAYMENT_OVERDUE, PAYMENT_RECEIVED
- New enums: PaymentMethod, PaymentStatus, TransactionType, FeeInterval, ExpenseCategory
- V18 Flyway migration: fee_schedules, member_fee_assignments, payments, ledger_entries tables
- Entities: FeeSchedule, MemberFeeAssignment, Payment, LedgerEntry
- Repositories with financial queries (balance, outstanding, period sums)
- FinanceService: fee schedule CRUD, record/void payments, expenses, Kassenbuch, summaries
- FinanceController: 14 admin endpoints + 2 portal self-service endpoints
- LedgerEntry is append-only per §147 AO (no update/delete)
- All amounts in cents (Integer) to avoid floating-point precision issues
2026-06-15 08:00:04 +02:00
Patrick Plate
aabde17532
feat(sprint7): Phase 4 — Integration (SMTP, tier enforcement, WebSocket)
...
Phase 4 implementation:
- 4.1 IONOS SMTP email configuration (production + docker profiles)
- 4.2 Portal navigation update (info board, events, forum links)
- 4.3 Tier enforcement: PlanTierService (forum=Pro+, info board limits)
- 4.4 WebSocket real-time updates (WebSocketEventPublisher)
- 4.5 EmailService: notification, event reminder, info board templates + rate limiting
- 4.6 Enterprise custom FROM: CustomMailDomain entity, DNS verification, controller
New files:
- PlanTierService: tier checks for forum/info board/enterprise features
- NotificationDispatchService: EMAIL channel dispatch via preferences
- WebSocketEventPublisher: STOMP topic push for forum/info board/events
- CustomMailDomainService: DNS TXT record verification for custom FROM
- MailSettingsController: Enterprise custom domain API endpoints
- CustomMailDomain entity + repository
- V16 migration: email dispatch index
- V17 migration: custom_mail_domains table
- Frontend: use-forum-subscription + use-info-board-subscription hooks
- Portal navbar: added info board, events, forum navigation items
- i18n: added portal nav translations (de + en)
Also fixed pre-existing Phase 2.5/3 compilation issues:
- Member entity: added userId field
- AuditService: added convenience overloads (logEvent, 4-param log)
- AuditEventType: added INFO_BOARD_POST_UPDATED, INFO_BOARD_POST_DELETED
- QuotaViolationCode: added TIER_UPGRADE_REQUIRED
- StaffPermissionChecker: added requirePermission(UserDetails, ...)
- TenantContext: added getCurrentTenantId() alias
- MemberRepository: added findByUserId, findByClubId, findAllByClubId
- EmailServiceTest: updated for new constructor signature
2026-06-13 20:51:10 +02:00
Patrick Plate
a539ed9eb2
feat(sprint7): Phase 3 — Forum MVP
...
- Flyway V15: forum_topics, forum_replies, forum_reactions, forum_reports tables
- Enums: ForumTargetType, ReactionType, ReportStatus
- Extended AuditEventType with FORUM_REPLY_CREATED, FORUM_REPORT_REVIEWED
- Entities: ForumTopic, ForumReply, ForumReaction, ForumReport
- Repositories: ForumTopicRepository, ForumReplyRepository, ForumReactionRepository, ForumReportRepository
- ForumService: full CRUD, moderation (lock/pin/delete), 60-min edit window,
toggle reactions, content reporting, notifications on new topics/replies
- ForumController: admin + portal endpoints (topics, replies, reactions, reports, moderation)
- Frontend: forum.ts service with React Query hooks (admin + portal)
- Frontend: Admin forum page with topic list, moderation actions (lock/pin/delete)
- Frontend: Portal forum page with topic list, reply thread, reactions, report
- Navigation: added Forum with MessageSquare icon
- i18n: forum.* keys in de.json and en.json
2026-06-13 20:31:17 +02:00
Patrick Plate
05fd679c4d
feat(sprint7): Phase 2.5 — Club Event Calendar
...
- Flyway V14: club_events + event_rsvps tables with reminder_sent tracking
- Enums: EventType, RsvpStatus, RecurrenceRule + extend AuditEventType/NotificationType
- Entities: ClubEvent (extends AbstractTenantEntity), EventRsvp (unique event+member)
- Repositories: ClubEventRepository, EventRsvpRepository with date-range and status queries
- EventService: CRUD, RSVP with maxAttendees enforcement (409 if full), iCal RFC 5545 generation, recurring event virtual expansion, notifications on create/cancel, auto-post to Info Board
- EventReminderScheduler: hourly check, 24h reminder to ACCEPTED/MAYBE attendees
- EventController: admin CRUD (MANAGE_INFO_BOARD permission), portal upcoming events, RSVP endpoint, iCal download (text/calendar), attendee list
- Frontend: events.ts service (React Query hooks matching apiClient pattern), admin calendar page (month grid with event dots, create dialog, event cards), portal events page (RSVP buttons, capacity display)
- Navigation: added Kalender with Calendar icon
- i18n: events.* keys in de.json and en.json
- UI: added @radix-ui/react-switch + Switch component
2026-06-13 20:16:56 +02:00
Patrick Plate
4aa27cd4f9
feat(sprint7): Phase 2 — Info Board (Schwarzes Brett)
...
Backend:
- V13 Flyway migration: info_board_posts, post_attachments, post_read_status tables
- InfoBoardPost entity with category enum (EVENT, RULE, GENERAL, MAINTENANCE)
- PostAttachment entity (table created, upload deferred to later)
- PostReadStatus entity with composite key (post_id, member_id)
- InfoBoardPostRepository with paginated queries + unread count
- InfoBoardService: CRUD, pin/archive, mark-as-read, notification dispatch
- InfoBoardController: admin CRUD + portal read/unread endpoints
- Integration with NotificationService and AuditService
Frontend:
- info-board.ts service with React Query hooks for all endpoints
- Admin Info Board page at /info-board with create dialog, filters, pin/archive/delete
- Navigation: added 'Schwarzes Brett' to admin sidebar
- i18n: added infoBoard.* keys to de.json and en.json
- Fixed pre-existing prettier issues in notification-compose.ts
- Fixed BufferSource type issue in push-subscription.ts
2026-06-13 19:41:20 +02:00
Patrick Plate
706a6e257b
feat(sprint7): Phase 1 — notifications enhancement + push infrastructure
...
Phase 1 (Notification Enhancement):
- Extended NotificationType enum (ADMIN_MESSAGE, INFO_BOARD_POST, FORUM_REPLY, FORUM_MENTION)
- Extended StaffPermission enum (SEND_NOTIFICATIONS, MANAGE_INFO_BOARD, MODERATE_FORUM)
- Extended AuditEventType with Sprint 7 events
- Flyway V11: notification_sends + notification_send_recipients tables
- NotificationSend + NotificationSendRecipient entities
- NotificationSendRepository + NotificationSendRecipientRepository
- Extended NotificationService with sendBroadcast() and sendToSelected()
- NotificationComposeController (POST /compose, GET /sends)
- ComposeNotificationRequest DTO
Phase 1B (Push Infrastructure):
- Flyway V12: device_tokens + notification_preferences tables
- DeviceToken entity + DevicePlatform enum
- NotificationPreference entity + NotificationChannel enum
- DeviceTokenRepository + NotificationPreferenceRepository
- DeviceRegistrationService (register/unregister/list devices, max 10 per user)
- NotificationPreferenceService (get/create defaults, update, IN_APP always on)
- NotificationDispatchService (multi-channel fan-out: WebSocket, Web Push, FCM, Email)
- WebPushSender (VAPID-based, simplified for MVP)
- FcmPushSender (graceful degradation if not configured)
- PushPayload DTO
- DeviceRegistrationController (POST/GET/DELETE /devices, GET /vapid-key)
- NotificationPreferenceController (GET/PUT /preferences)
- ConsentType extended (NOTIFICATION_PUSH, NOTIFICATION_EMAIL)
- TargetType enum (ALL, SELECTED)
Frontend:
- Updated sw.js with push event handler + notification click handler
- push-subscription.ts (subscribeToPush, unsubscribe, permission helpers)
- notification-compose.ts service (compose, sends, devices, preferences APIs)
- i18n keys (de.json + en.json) for compose, preferences, push, devices
Configuration:
- application-docker.properties: VAPID + FCM push config properties
- MemberRepository: added findAllActiveUserIds() for broadcast
2026-06-13 19:25:19 +02:00
Patrick Plate
52251cf711
fix(api): resolve consent/dsgvo 'User not found' — principal is userId not email
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
ConsentController.resolveUserId() and DsgvoController.resolveUserId() read
auth.getName() as an email and did findByEmailAndTenantId(...), but JwtAuthFilter
sets the Authentication principal to the userId (UUID) — the JWT subject is the
userId, not the email. So auth.getName() returns a UUID string, the email lookup
never matched, and every consent/dsgvo call threw 'User not found' (404/500).
This made the DSGVO consent banner unusable: /consent/check 404'd (banner always
shown) and clicking Accept POSTed /consent which 500'd with no UI feedback — the
button appeared to 'not react'.
Fix: parse auth.getName() as the userId UUID directly and verify existsById.
2026-06-13 10:52:43 +02:00
Patrick Plate
60844efaba
fix(api): disable mail health indicator in docker profile
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
Backend now starts and Flyway migrations run, but /actuator/health returned
503 (DOWN) so Docker marked the container unhealthy and the frontend refused
to start. Cause: spring-boot-starter-mail registers a mail health indicator
that tries to connect to localhost:1025; there is no SMTP container in this
deployment, so it reports DOWN and drags the aggregate health to DOWN.
Disable the mail health indicator in the docker profile. Mail being down must
not make the whole service unhealthy in an SMTP-less deployment.
2026-06-13 09:57:01 +02:00
Patrick Plate
8490da4705
fix(api): add spring-boot-starter-flyway for Spring Boot 4 migrations
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
Backend crashed on startup with 'Schema validation: missing table
[audit_events]'. Root cause: this is Spring Boot 4.0.6, which modularized
autoconfiguration. FlywayAutoConfiguration moved out of spring-boot-autoconfigure
into a dedicated spring-boot-flyway module that is only pulled in by
spring-boot-starter-flyway. The pom only had flyway-database-postgresql
(+ transitive flyway-core) but NOT the starter, so spring.flyway.enabled=true
was inert: no migrations ran, flyway_schema_history was never created, and
Hibernate ddl-auto=validate failed on the empty schema.
Adds spring-boot-starter-flyway (autoconfigure module + flyway-core); keeps
flyway-database-postgresql for the Postgres dialect.
Ref: https://spring.io/blog/2025/10/28/modularizing-spring-boot/
2026-06-13 09:52:22 +02:00
Patrick Plate
599514c0db
feat(sprint-6): Phase 6 — Notifications (WebSocket) + PWA
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- WebSocket: Spring STOMP + SockJS, NotificationService, persistent notifications table
- NotificationController: GET/PUT endpoints for notification management
- Frontend: notification bell with unread badge, dropdown panel, real-time via STOMP
- PWA: manifest.json, service worker (manual sw.js), offline page, install prompt
- PWA icons (192+512), dark theme colors, standalone display
- Full i18n (de/en) for notifications and PWA
- Flyway V10 migration for notifications table
- spring-boot-starter-websocket dependency added
2026-06-12 23:02:44 +02:00
Patrick Plate
076fd6f9b3
feat(sprint-6): Phase 5 — Full grow calendar (sensors, photos, feeding, harvest traceability)
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- V9 migration: grow_entries, grow_stage_logs, sensor_readings, grow_photos, feeding_logs
- 5 entities + GrowStage enum (7 stages) + SensorReadingType enum
- GrowCalendarService: CRUD + stage advancement + harvest-to-batch linking
- GrowCalendarController: 8 endpoints (/api/v1/grow/*)
- Frontend: /grow list + /grow/[id] detail (timeline, sensor charts, photo gallery, feeding log)
- Sensor chart (Recharts line: temp + humidity over time)
- Harvest completion links grow entry → batch (full traceability)
- React Query hooks for all grow operations
- Full i18n (de/en) with 7 grow stage labels
- Sidebar navigation updated with Anbau/Grow entry
2026-06-12 22:51:45 +02:00
Patrick Plate
05933a08ca
feat(sprint-6): Phase 4 — Immutable audit log
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- V8 migration: audit_events table (JSONB metadata, immutable by design)
- AuditEvent entity + AuditEventType enum (18 event types)
- AuditService: log events, paginated query, PDF export
- AuditController: GET /api/v1/audit (paginated, filtered), GET export
- AuditEventRepository with JPQL filtered queries
- Frontend: /audit-log page (read-only, filterable, timezone-aware)
- PDF export button for Behörde inspections
- Sidebar: 'Protokoll' under new Compliance section
- PdfReportGenerator: generateAuditReport method added
- 10-year retention, REVOKE DELETE documented
- Full i18n (de/en) with 18 event type translations
2026-06-12 22:40:40 +02:00
Patrick Plate
61e481b37b
feat(sprint-6): Phase 3 — Stripe integration (SEPA + PayPal + Card)
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- V7 migration: subscriptions table with plan tiers
- Subscription entity + PlanTier/SubscriptionStatus enums
- StripeService: customer creation, checkout, portal, webhook handling
- SubscriptionController: /api/v1/billing endpoints
- Webhook handler: invoice.paid, payment_failed, subscription.deleted/updated
- Plan enforcement: member limit interceptor, trial expiry check
- Frontend: /settings/billing page (plan card, usage, upgrade, portal link)
- Trial expired banner on all admin pages
- React Query hooks (useSubscriptionQuery, checkout/portal mutations)
- Stripe Java SDK 28.2.0
- Full i18n (de/en) for billing namespace
2026-06-12 22:31:03 +02:00
Patrick Plate
3232d2f7fd
feat(sprint-6): Phase 2 — DSGVO consent management
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- 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
Patrick Plate
b38902a7ee
feat(sprint-6): Phase 1 — Production deployment infrastructure (IONOS)
...
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
- docker-compose.prod.yml: production Docker Compose with health checks, logging, restart policies, resource limits
- deploy/nginx/cannamanage.conf: Nginx reverse proxy with TLS, CSP, security headers, rate limiting
- deploy/.env.production.example: environment template for secrets
- deploy/backup.sh: GPG-encrypted daily/weekly PostgreSQL backup with retention
- deploy/deploy.sh: manual deploy script with health check verification
- .gitea/workflows/deploy.yml: Gitea Actions CI/CD pipeline (test + deploy)
- application-production.properties: Spring Boot production profile (no stacktraces, Swagger disabled, Stripe)
- .gitignore: added .env to prevent accidental secret commits
2026-06-12 22:11:43 +02:00
Patrick Plate
279f2f6de0
feat(sprint-5): Phase 1 — Docker Compose full stack, CORS, Next.js upgrade
...
- Dockerfile.backend: multi-stage Java 21 build (eclipse-temurin)
- docker-compose.yml: PostgreSQL 16 + backend + frontend with health checks
- SecurityConfig: CORS for localhost:3000 frontend origin
- application-docker.properties: Docker profile with env vars
- Spring Boot Actuator health endpoint enabled
- Next.js upgraded 15.2.8 → 15.5.18 (security fixes)
2026-06-12 19:51:24 +02:00
Patrick Plate
864bbbdde1
feat(sprint-3): Phase 7 — integration tests (Testcontainers PostgreSQL)
...
- Add AbstractIntegrationTest base class with Testcontainers PostgreSQL,
RestClient helpers, and test data factories
- AuthIntegrationTest: login, refresh, token rotation, error cases
- TenantIsolationTest: multi-tenant data isolation verification
- StaffPermissionIntegrationTest: invite → activate → permission enforcement
- PortalIntegrationTest: session-based portal auth flow
- ReportIntegrationTest: JSON/PDF/CSV report generation E2E
- TokenRevocationIntegrationTest: permission change → JWT revocation
- application-integration.properties: Flyway-enabled test profile
- Remove obsolete Boot 3 @WebMvcTest/@MockBean tests (Boot 4 incompatible)
replaced by comprehensive integration tests with real PostgreSQL
2026-06-12 11:05:40 +02:00
Patrick Plate
4f00872486
feat(sprint-3): Phase 6 — prevention officer capability
...
- PreventionOfficerService: limit enforcement, under-21 monitoring, monthly distribution tracking
- PUT /api/v1/staff/{id}/prevention-officer: assign/revoke with club limit check (409 on exceed)
- GET /api/v1/members/under-21: list under-21 members with quota data (prevention officer access)
- GET /api/v1/members/{id}/prevention-data: member prevention details (quota, distributions)
- PreventionOfficerLimitExceededException mapped to 409 in GlobalExceptionHandler
- StaffResponse extended with preventionOfficer field
- PreventionOfficerServiceTest: 10 unit tests covering assignment, revocation, limits, age calc
- MemberRepository.findByTenantIdAndUnder21True added
2026-06-12 10:20:20 +02:00
Patrick Plate
87568e5bfc
feat(sprint-3): Phase 5 — member portal (session-based auth)
2026-06-12 10:11:58 +02:00
Patrick Plate
64927a3244
feat(sprint-3): Phase 4 — report controller + PDF/CSV generation
...
- Add report data models (MonthlyReport, MemberListReport, RecallReport)
- Implement ReportService with monthly aggregation, member list, recall batch tracing
- Add PdfReportGenerator using OpenPDF with minimal club branding
- Add PdfFooterHandler for timestamp + page numbers on every page
- Add CsvReportGenerator with UTF-8 BOM for Excel compatibility
- Create ReportController with 3 endpoints (monthly, members, recall)
supporting JSON/PDF/CSV format negotiation via ?format= param
- Add DTO records (MonthlyReportResponse, MemberListResponse, RecallReportResponse)
- Extend DistributionRepository + MemberRepository with report queries
- Update Commons CSV from 1.11.0 to 1.12.0
- 10 unit tests (ReportServiceTest: 6, PdfReportGeneratorTest: 4) all passing
Endpoints:
GET /api/v1/reports/monthly?month=YYYY-MM&format=json|pdf|csv
GET /api/v1/reports/members?format=json|pdf|csv&status=ACTIVE
GET /api/v1/reports/recall/{batchId}?format=json|pdf
2026-06-12 09:38:57 +02:00
Patrick Plate
6c66783b58
feat(sprint-3): Phase 3 — staff management + invite flow
...
- Step 3.1: Spring Boot Starter Mail dependency (api + service)
- Step 3.2: InviteToken JPA entity with 72h expiry
- Step 3.3: InviteTokenRepository with valid-token finder
- Step 3.4: EmailService (plain text invite email via JavaMailSender)
- Step 3.5: StaffService (CRUD + invite + email pattern validation + token revocation)
- Step 3.6: Staff DTOs (CreateStaffRequest, UpdateStaffRequest, StaffResponse)
- Step 3.7: SetPasswordRequest with password complexity (@Pattern: 1 digit + 1 special)
- Step 3.8: StaffController (6 endpoints, ADMIN-only via @PreAuthorize)
- Step 3.9: POST /api/v1/auth/set-password (public, generic error messages)
- Step 3.10: StaffTemplates (ausgabe, lager, vorstand predefined permission sets)
- Step 3.11: AuthService rejects inactive users with 'Account not activated'
- Step 3.12: Token revocation on permission change via revokeAllForUser()
- Step 3.13: invite-email.txt template (German, 72h expiry note)
- Step 3.14: Spring Mail config (Mailpit dev defaults, env var overrides)
- Step 3.15: Unit tests (StaffServiceTest, StaffControllerTest, EmailServiceTest)
- V5 Flyway migration for invite_tokens table
Security review findings incorporated:
- Password complexity: min 8 chars, 1 digit + 1 special char
- Generic 'invalid or expired token' error (no state leakage)
- SecureRandom 32-byte Base64 token generation
- Token values never logged
2026-06-11 18:03:12 +02:00
Patrick Plate
36deb72cf0
feat(sprint-3): Phase 2 — club settings controller
2026-06-11 16:56:44 +02:00
Patrick Plate
55d8434f35
feat(sprint-3): Phase 1 — staff permissions + token revocation
...
- StaffPermission enum (8 granular permissions)
- StaffAccount JPA entity with permissions collection
- RevokedToken entity for JWT blacklisting
- Flyway V3 migration (staff_accounts, staff_account_permissions, revoked_tokens)
- StaffAccountRepository + RevokedTokenRepository
- TokenRevocationService with Caffeine cache (60s TTL, 10k max)
- StaffPermissionChecker SpEL bean (@staffPermissions.has)
- PreventionOfficerChecker SpEL bean (@preventionOfficer.check)
- JwtService: added jti claim + generateStaffAccessToken + extractJti/extractPermissions
- JwtAuthFilter: token blacklist check via TokenRevocationService
- SecurityConfig: STAFF role added to endpoint matchers
- Controllers updated with @PreAuthorize for fine-grained access
- TokenCleanupScheduler (daily 03:00 cleanup of expired revoked tokens)
- Caffeine dependency added to cannamanage-service
- Unit tests: StaffPermissionCheckerTest (7), TokenRevocationServiceTest (9)
2026-06-11 16:45:21 +02:00
Patrick Plate
a1ddec37da
test(sprint-2): add integration tests for Auth + Compliance controllers
...
- AuthControllerIntegrationTest: 7 tests (login, refresh, error cases)
- ComplianceControllerIntegrationTest: 5 tests (quota, auth, 404)
- Fix Boot 4.0 @EntityScan relocation (boot.persistence.autoconfigure)
- Fix BCrypt 72-byte limit for refresh tokens (use SHA-256 instead)
- Configure H2 test DB with NON_KEYWORDS for reserved words (month/year)
2026-06-11 13:30:07 +02:00
Patrick Plate
2ede872d11
feat: Sprint 2 REST API layer — full implementation
...
- Fix critical Hibernate @Filter activation bug (TenantFilterAspect)
- Rename UserRole.ROLE_MANAGER → ROLE_STAFF (future-proofing)
- SecurityConfig: ADMIN + MEMBER roles only for Sprint 2
- AuthController: POST /auth/login + POST /auth/refresh with JWT
- AuthService: login, refresh token rotation, hashed refresh storage
- MemberController: CRUD (GET/POST/PUT /members)
- DistributionController: list + record distributions (CanG §26)
- StockController: batch management (GET/POST /stock/batches)
- ComplianceController: quota check (GET /compliance/quota/{id})
- OpenAPI/Swagger config with bearer-jwt security scheme
- GlobalExceptionHandler: full RFC 9457 problem+json coverage
- UserRepository: findByEmail, findByEmailAndTenantId
- Flyway V2: role rename migration + login indexes
- Testcontainers + test profile infrastructure (integration tests deferred)
- Parent POM: Testcontainers BOM, entity scan via properties
Controllers use validated DTOs (Jakarta Bean Validation records).
Compliance checks run before distribution recording.
Tenant filter AOP aspect ensures multi-tenant data isolation.
2026-06-11 12:05:52 +02:00
Patrick Plate
86c922e1f9
feat(sprint-2): add security infrastructure
...
- Spring Security 6 with dual SecurityFilterChain (API stateless JWT + public Swagger)
- JwtService: generate/validate access + refresh tokens (JJWT 0.12.6)
- JwtAuthFilter: extract Bearer token, set SecurityContext + TenantContext
- GlobalExceptionHandler: RFC 9457 ProblemDetail responses
- Dependencies: spring-security, jjwt, springdoc-openapi, bean-validation, h2-test
- Application properties: JWT config + OpenAPI paths
2026-06-11 10:46:48 +02:00
Patrick Plate
10891e7b89
chore: upgrade Spring Boot 3.3.4 → 4.0.6
...
- Remove manually-pinned versions (Hibernate, Flyway, AssertJ, Mockito)
now managed by Boot 4.0.6 BOM
- Remove @EntityScan and @EnableJpaRepositories — auto-detected via
scanBasePackages covering de.cannamanage hierarchy
- All 25 tests pass, build compiles in 9.6s
2026-06-11 10:41:59 +02:00
Patrick Plate
fa1eaf64e0
feat(sprint-1): CannaManage foundation — compliance engine, JPA entities, tests TC-001→TC-025
...
- Maven multi-module project (parent + domain + service + api)
- AbstractTenantEntity with Hibernate @Filter for multi-tenancy (explicit getters/setters, Java 25 compatible)
- TenantContext ThreadLocal for request-scoped tenant isolation
- 8 JPA entities: Club, Member, Strain, Batch, Distribution, MonthlyQuota, StockMovement, User
- ComplianceConstants with CanG §19 limits (25g/day adult, 50g/month adult, 30g/month under-21, 10% THC cap)
- ComplianceService: checkDistributionAllowed() with fail-fast sequential CanG checks
- Unit tests TC-001→TC-025: 25/25 passing, 100% line+branch coverage on ComplianceService (JaCoCo 0.8.13)
- Flyway V1__initial_schema.sql: all 8 tables + indexes
- docker-compose.yml: PostgreSQL 16 local dev
- application-local.properties: local profile configuration
Closes #1 #2 #3 #4 #5 #6 #7 #8 #9 #10
2026-04-12 20:30:12 +02:00