60844efaba839b55cc4615e3ef3614daaf87eceb
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.
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 trackingDistribution— cannabis distribution recordsMonthlyQuota— per-member monthly usage trackingBatch/Strain/StockMovement— inventory managementClub— association registrationUser— 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
@Filteractivated 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
Description
Languages
Java
61%
TypeScript
38.1%
JavaScript
0.4%
CSS
0.3%
Shell
0.2%