feat: Sprint 13 — Production Hardening (security fixes, CI gate, rate limiting, tests)
Deploy to TrueNAS / deploy (push) Failing after 12s
Deploy to TrueNAS / deploy (push) Failing after 12s
This commit is contained in:
@@ -1,111 +1,87 @@
|
||||
# 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.
|
||||
Full-stack management platform for German cannabis cultivation associations (Anbauvereinigungen) under the CanG/KCanG regulatory framework.
|
||||
|
||||
## 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) |
|
||||
| Layer | Technology |
|
||||
|-------|-----------|
|
||||
| **Frontend** | Next.js 15, React 19, TypeScript, Tailwind CSS 4, shadcn/ui |
|
||||
| **Backend** | Spring Boot 3.5, Java 17, Spring Security (JWT + session) |
|
||||
| **Database** | PostgreSQL 16, Flyway migrations |
|
||||
| **Infrastructure** | Docker Compose, Gitea Actions CI/CD, TrueNAS deployment |
|
||||
|
||||
## 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
|
||||
├── cannamanage-api/ # Spring Boot REST API (entry point)
|
||||
├── cannamanage-service/ # Business logic layer
|
||||
├── cannamanage-domain/ # JPA entities, enums, value objects
|
||||
├── cannamanage-frontend/ # Next.js frontend (pnpm)
|
||||
├── deploy/ # Deployment scripts & nginx config
|
||||
├── docker-compose.yml # Local development stack
|
||||
└── .gitea/workflows/ # CI/CD pipeline
|
||||
```
|
||||
|
||||
## Modules
|
||||
## Local Development
|
||||
|
||||
### 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
|
||||
### Prerequisites
|
||||
|
||||
### cannamanage-service
|
||||
- `ComplianceService` — CanG §19 quota enforcement (25 unit tests)
|
||||
- Repositories for all entities
|
||||
- Java 17+
|
||||
- Maven 3.9+
|
||||
- Node.js 22+ with pnpm 10+
|
||||
- Docker & Docker Compose
|
||||
|
||||
### 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
|
||||
### Backend
|
||||
|
||||
```bash
|
||||
# Start PostgreSQL
|
||||
docker compose up -d
|
||||
docker compose up -d db
|
||||
|
||||
# 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
|
||||
# Run Spring Boot
|
||||
mvn spring-boot:run -f cannamanage-api/pom.xml -Dspring-boot.run.profiles=local
|
||||
```
|
||||
|
||||
## Testing
|
||||
### Frontend
|
||||
|
||||
- **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
|
||||
```bash
|
||||
cd cannamanage-frontend
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Integration tests use `@SpringBootTest(webEnvironment = RANDOM_PORT)` with H2 and Spring's `RestClient`.
|
||||
The frontend runs on http://localhost:3000, backend on http://localhost:8080.
|
||||
|
||||
## Security Model
|
||||
### Full Stack (Docker)
|
||||
|
||||
- **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
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
## Sprint History
|
||||
## Deployment
|
||||
|
||||
| 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 |
|
||||
Push to `main` triggers the Gitea Actions CI pipeline which:
|
||||
1. Runs backend tests (`mvn test`)
|
||||
2. Runs frontend lint (`pnpm lint`)
|
||||
3. Builds Docker images
|
||||
4. Deploys to TrueNAS via Docker Compose
|
||||
5. Verifies backend health + frontend availability
|
||||
|
||||
Manual deploy:
|
||||
```bash
|
||||
cd deploy && ./deploy.sh
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Purpose | Default |
|
||||
|----------|---------|---------|
|
||||
| `CANNAMANAGE_SECURITY_JWT_SECRET` | JWT signing key (base64, 256-bit) | — (required) |
|
||||
| `CORS_ORIGINS` | Allowed CORS origins (comma-separated) | `http://localhost:3000` |
|
||||
| `SMTP_HOST` / `SMTP_PORT` | Mail server for invites | `localhost:1025` |
|
||||
| `SCHEDULERS_ENABLED` | Enable background jobs | `true` |
|
||||
|
||||
## License
|
||||
|
||||
Private — Patrick Plate
|
||||
Proprietary — Patrick Plate
|
||||
|
||||
Reference in New Issue
Block a user