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

CannaManage

Multi-tenant cannabis club management platform for German Anbauvereinigungen (cultivation associations) under CanG §19.

Overview

CannaManage handles member management, distribution tracking, and legal compliance for cannabis cultivation clubs in Germany. It enforces the strict quotas mandated by the Cannabis Act (CanG) — including monthly limits (50g adult / 30g under-21), daily limits (25g), and THC restrictions for minors.

Tech Stack

Component Technology
Runtime Java 21 (Temurin)
Framework Spring Boot 4.0.6
Security Spring Security 7.0 + JWT (JJWT 0.12.6)
ORM Hibernate 7 / JPA
Database PostgreSQL (prod), H2 (test)
Migrations Flyway 10
API Docs SpringDoc OpenAPI 2.8.6
Build Maven (multi-module)
Container Docker Compose (Postgres + app)

Project Structure

cannamanage/
├── cannamanage-domain/      # JPA entities, enums, TenantContext
├── cannamanage-service/     # Business logic, repositories, ComplianceService
├── cannamanage-api/         # Spring Boot app, controllers, security, DTOs
├── docs/
│   └── sprint-2/           # Sprint planning docs
└── docker-compose.yml       # Local dev environment

Modules

cannamanage-domain

JPA entities with multi-tenant isolation via @Filter("tenantFilter"):

  • Member — club members with age tracking
  • Distribution — cannabis distribution records
  • MonthlyQuota — per-member monthly usage tracking
  • Batch / Strain / StockMovement — inventory management
  • Club — association registration
  • User — authentication accounts

cannamanage-service

  • ComplianceService — CanG §19 quota enforcement (25 unit tests)
  • Repositories for all entities

cannamanage-api

  • Auth — JWT login + refresh token rotation (SHA-256 hashed)
  • Members — CRUD for association members
  • Distributions — compliance-gated distribution recording
  • Stock — batch and inventory management
  • Compliance — quota status API
  • Multi-tenant isolation via TenantFilterAspect (Hibernate @Filter activation)

API Endpoints

Method Path Auth Description
POST /api/v1/auth/login Public Login with email + password
POST /api/v1/auth/refresh Public Refresh token rotation
GET /api/v1/compliance/quota/{memberId} ADMIN, MEMBER Monthly quota status
GET/POST/PUT /api/v1/members/** ADMIN, MEMBER Member CRUD
POST /api/v1/distributions/** ADMIN, MEMBER Record distributions
GET/POST /api/v1/stock/** ADMIN Stock management

Swagger UI: http://localhost:8080/swagger-ui.html

Running Locally

# Start PostgreSQL
docker compose up -d

# Run the app
JAVA_HOME=/path/to/jdk-21 ./mvnw spring-boot:run -pl cannamanage-api

# Run all tests (H2 in-memory)
JAVA_HOME=/path/to/jdk-21 ./mvnw clean verify

Testing

  • 37 tests total — all green
  • 25 unit tests (ComplianceServiceTest) — quota enforcement logic
  • 7 integration tests (AuthControllerIntegrationTest) — full HTTP auth flow
  • 5 integration tests (ComplianceControllerIntegrationTest) — quota API with JWT

Integration tests use @SpringBootTest(webEnvironment = RANDOM_PORT) with H2 and Spring's RestClient.

Security Model

  • Stateless JWT — no session, no UserDetailsService
  • Roles: ADMIN (full access), MEMBER (self-service), STAFF (Sprint 3)
  • Multi-tenancy: Hibernate @Filter activated per-request via AOP aspect
  • Refresh tokens: SHA-256 hashed (Spring Security 7 enforces BCrypt 72-byte limit)
  • Token rotation on refresh — old tokens invalidated

Sprint History

Sprint Focus Status
1 Domain entities, ComplianceService, 25 tests Done
2 REST API, Spring Security, JWT, OpenAPI, integration tests Done
3 Member portal, STAFF role, real-time notifications 📋 Planned

License

Private — Patrick Plate

S
Description
CannaManage — B2B SaaS for German Cannabis Social Clubs (Anbauvereinigungen)
Readme 7.8 MiB
Languages
Java 61%
TypeScript 38.1%
JavaScript 0.4%
CSS 0.3%
Shell 0.2%