# ApiCore – Architektur Basiert auf [`docs/lastenheft.md`](docs/lastenheft.md). Diese Datei beschreibt, WIE die fachlichen Anforderungen technisch umgesetzt werden. ## 1. Backend – Modulschnitt (NestJS) Ein NestJS-Modul pro fachlichem Bereich, Reihenfolge entspricht Baureihenfolge in TASKS.md: | Modul | Zweck | Abhängig von | |---|---|---| | `AuthModule` | Login, Refresh, Passwort-Reset, JWT-Strategien | – | | `UsersModule` | Benutzerverwaltung, Rollen | Auth | | `AuditModule` | Audit-Log-Grundstruktur (Service `AuditLogService`, wird von anderen Modulen injiziert) | Users | | `ApiariesModule` | Bienenstände | Auth | | `ColoniesModule` | Völker, Standortwechsel-Historie, Ableger/Vereinigung | Apiaries | | `QueensModule` | Königinnen, Volk-Historie | Colonies | | `InspectionsModule` | Durchsichten | Colonies | | `TasksModule` | Aufgaben, polymorph verknüpft | – | | `VarroaModule` | Varroamessungen | Colonies | | `TreatmentsModule` | Behandlungen | Colonies | | `FeedingsModule` | Fütterungen | Colonies | | `HarvestsModule` | Ernten | Apiaries, Colonies | | `ExtractionsModule` | Schleuderungen | Harvests | | `HoneyBatchesModule` | Honigchargen, Honigmessungen | Extractions | | `StorageModule` | Lagerbehälter, einfache Lagerverwaltung (StockItem/StockMovement) | HoneyBatches | | `DashboardModule` | Aggregations-Endpunkte | alle o.g. | | `SearchModule` | globale Suche, Filter-Bausteine | alle o.g. | | `ExportModule` | CSV/JSON/PDF-Export | alle o.g. | Jedes Modul: `*.controller.ts`, `*.service.ts`, `dto/`, `*.module.ts`, `*.spec.ts` (Unit), `test/*.e2e-spec.ts` (Integration). Rollenprüfung über `@Roles()`-Decorator + `RolesGuard`, angewendet pro Endpunkt – niemals nur UI-seitig. Alle Routen unter `/api/v1/...`, versioniert über NestJS `URI Versioning`. OpenAPI-Doku automatisch über `@nestjs/swagger`, erreichbar unter `/api/v1/docs`. ## 2. Frontend – Seitenstruktur (Next.js App Router) ``` app/ ├── (auth)/login/ ├── (app)/ geschütztes Layout mit Bottom-Nav (mobil) / Sidebar (Desktop) │ ├── dashboard/ │ ├── apiaries/[id]/ │ ├── colonies/[id]/ │ ├── queens/[id]/ │ ├── inspections/new/ │ ├── tasks/ │ ├── varroa/new/ │ ├── treatments/new/ │ ├── feedings/new/ │ ├── harvests/new/ │ ├── honey-batches/[id]/ │ ├── storage/ │ ├── search/ │ └── settings/users/ nur Administrator ``` Zentrale Schnellaktion "+ Neu" (Abschnitt 22): permanent sichtbarer Floating-Button in der mobilen Bottom-Nav, öffnet Auswahl-Sheet (Durchsicht, Fütterung, Behandlung, Varroamessung, Aufgabe, Ernte, Volk, Königin) → direkt zum jeweiligen Schnellerfassungs-Formular, mobil möglichst 1-2 Taps bis zum ersten Eingabefeld. Datenzugriff ausschließlich über TanStack Query gegen die Backend-API (kein direkter DB-Zugriff, kein Next.js-eigenes Datenbank-Layer) – erzwingt API-first auch praktisch. ## 3. Auth-Flow 1. Login (`POST /api/v1/auth/login`) mit E-Mail/Passwort → Access-Token (kurzlebig, ~15 min, JWT) + Refresh-Token (langlebig, ~7 Tage, in DB als Hash gespeichert, rotierend). 2. Frontend hält Access-Token im Memory/React-Context, Refresh-Token als httpOnly-Cookie. 3. Bei 401 automatischer Refresh über `POST /api/v1/auth/refresh`, danach Retry. 4. Jeder geschützte Endpunkt: `JwtAuthGuard` (Authentifizierung) + `RolesGuard` (Autorisierung nach Rolle aus Abschnitt 3). 5. API-Client-Rolle nutzt dieselben JWT-Endpunkte mit client-credentials-artigem Service-Account (kein OAuth2-Server im MVP, siehe Annahmen). ## 4. Datenfluss / Rückverfolgbarkeit Kernkette (Abschnitt 16, 29) relational über Fremdschlüssel, nicht über Textfelder: ``` Apiary → Colony → (Inspection | Treatment | Feeding | VarroaMeasurement) Apiary/Colony → Harvest → Extraction → HoneyBatch → StorageContainer ``` `HoneyBatch` referenziert `Extraction`, `Extraction` referenziert n `Harvest`s (m:n über `ExtractionHarvest`), `Harvest` referenziert n `Colony`s (m:n über `HarvestColony`) + eine `Apiary`. Damit ist "von welchem Volk stammt Charge X" eine reine Join-Abfrage, kein Freitext. Historie statt Löschen: alle fachlichen Haupttabellen haben `status`/`deactivatedAt` statt Hard-Delete. Verschiebungen (Volk↔Stand) und Königinnenwechsel werden als eigene Historientabellen geführt (`ColonyApiaryHistory`, `QueenColonyHistory`), nicht durch Überschreiben des aktuellen Zustands. ## 5. Technische Leitentscheidungen (bestätigt, keine Abweichung) - Validierung: **class-validator/class-transformer** (nicht Zod) – konsistent mit NestJS-Idiomatik und `@nestjs/swagger`-Decorators, ein Schema-Ort statt zwei. - Ein gemeinsames Git-Repo im `ApiCore/`-Root für Backend + Frontend (Monorepo-artig, aber zwei unabhängige `package.json`, kein Turborepo/Nx-Overhead im MVP). - Package-Manager: npm (in beiden Projekten, keine Vermischung mit pnpm/yarn). - Backend-Tests: Jest (NestJS-Standard). Frontend-Tests: Vitest + React Testing Library. ## 6. Annahmen & offene Fragen Fachliche Annahmen, getroffen weil das Lastenheft an der Stelle keine eindeutige Vorgabe macht. Bei Bedarf mit dem Fachbereich klären, aktuell aber Grundlage der Umsetzung: 1. **HoneyMeasurement als MVP-Entität**: Abschnitt 26 MUSS-Liste nennt Honigmessungen nicht explizit, Abschnitt 4.17 aber als eigenen Unterpunkt und Abschnitt 30 verlangt Wassergehalt schnell abrufbar. Da sie klein und für die Chargen-Kette relevant ist, wird sie als Teil des `HoneyBatchesModule` im MVP mitgebaut statt auf v1.x verschoben. 2. **Treatment auf Einzelvolk statt "Völkergruppe"**: Abschnitt 4.11 erlaubt "Volk oder Völkergruppe". MVP modelliert `Treatment` pro Volk (`colonyId` Pflichtfeld); eine Gruppenbehandlung wird im MVP als mehrere Treatment-Datensätze mit gleicher `batchNumber`/Notiz erfasst statt eigener Gruppen-Entität. Spätere Migration kann eine `TreatmentGroup`-Entität nachziehen, falls das in der Praxis zu unhandlich ist. 3. **Lagerverwaltung MVP-Umfang**: "grundlegende Lagerverwaltung" (Abschnitt 26 Punkt 12) wird als generisches `StockItem` + `StockMovement` (Kategorie Honig/Verbrauchsmaterial/Imkereimaterial) umgesetzt. Das detaillierte Inventar mit Wartungsdaten (Abschnitt 4.22) bleibt v1.x/"SOLL", wie im Lastenheft vorgesehen. 4. **API-Client-Rolle im MVP**: kein vollwertiger OAuth2/Client-Credentials-Server. Ein API-Client ist ein `User` mit Rolle `API_CLIENT` und einem langlebigen Service-Refresh-Token; vollwertiges Scopes-/Client-Management ist SOLL/KANN. 5. **Backup-fähige Struktur**: kein eigenes Backup-Tooling im Code. Umgesetzt als: reproduzierbare Prisma-Migrationen (kein manuelles Schema-Drift), dokumentierte `pg_dump`/PITR-Strategie in diesem Dokument (Betrieb obliegt dem bestehenden Cluster/DBA), `/health`-Endpoint für Betriebsüberwachung. 6. **Deviations vom Leitentscheidungs-Rahmen**: bisher keine. Wird ergänzt, falls während der Umsetzung ein konkreter Grund für eine Abweichung von NestJS/Prisma/Next.js/Tailwind/shadcn/TanStack Query auftritt. 7. **Dokumentenspeicher als lokales Volume (Modul 29)**: `DocumentsModule` speichert Uploads unterhalb von `DOCUMENTS_STORAGE_PATH` auf dem lokalen Dateisystem des Backend-Pods, keine Objektspeicher-Anbindung (S3-kompatibel o.ä.) im MVP/v1.x. Der Pfad ist über die ConfigMap austauschbar, wie in Abschnitt 27 des Lastenhefts vorgesehen. Wichtig für den Betrieb: das aktuelle `deploy/k8s`-Deployment läuft mit `replicas: 2` ohne geteiltes Volume – für konsistente Uploads über beide Pods hinweg muss vor Produktivbetrieb mit Dokumenten-Feature ein `ReadWriteMany`-PVC (z.B. NFS- oder EFS-basiert) gemountet und `DOCUMENTS_STORAGE_PATH` darauf gesetzt werden, sonst sieht nur der Pod, der die Datei entgegengenommen hat, sie auch beim Download wieder. ## 7. Kubernetes `deploy/k8s/` enthält je Projekt: `deployment.yaml`, `service.yaml`, `ingress.yaml`, sowie `configmap.example.yaml` und `secret.example.yaml` (Platzhalter, keine echten Werte). Backend exponiert `GET /health` (liveness) und `GET /health/ready` (readiness, prüft DB-Verbindung). Beide Projekte je ein schlankes Multi-Stage-Dockerfile (Build-Stage mit vollem `node_modules`, Runtime-Stage mit `npm ci --omit=dev` bzw. Next.js `output: 'standalone'`). ## 8. Backup & Restore **Schema-Migrationen (Reproduzierbarkeit):** Ausschließlich `prisma/migrations/` als Quelle der Wahrheit. Lokal/Entwicklung: `npx prisma migrate dev`. Gegen jede Produktions- oder Staging-Datenbank ausschließlich `npx prisma migrate deploy` (idempotent, wendet nur fehlende Migrationen an, kein Schema-Drift). `prisma db push` wird an keiner Stelle im Code, in Skripten oder im Dockerfile verwendet und ist für Produktions-/Staging-Umgebungen untersagt. `migrate deploy` läuft als eigener Schritt vor dem Rollout (z. B. Kubernetes-`Job` oder manueller Schritt in der Deploy-Pipeline), nicht im `CMD` des Runtime-Images, damit mehrere Pod-Replicas nicht gleichzeitig Migrationen ausführen. **Datensicherung:** Die PostgreSQL-Instanz selbst ist bestehende Cluster-Infrastruktur (siehe CLAUDE.md, "keine eigene DB-Infrastruktur"); Backup-Ausführung liegt beim Cluster-/DBA-Betrieb. Empfohlene Strategie dort: - Tägliches logisches Backup via `pg_dump -Fc` (custom format, komprimiert, für `pg_restore` geeignet), Aufbewahrung nach Retention-Policy des Clusters. - Kontinuierliches WAL-Archiving/PITR (Point-in-Time Recovery), falls vom Cluster unterstützt, für Wiederherstellung auf einen beliebigen Zeitpunkt zwischen den täglichen Dumps. - Restore-Test: `pg_restore` eines Dumps in eine isolierte Datenbank, danach `npx prisma migrate deploy` zur Kontrolle, dass der Migrationsstand konsistent ist (`prisma migrate status`). **Restore-Ablauf (Kurzfassung):** 1) Zielinstanz/-datenbank bereitstellen. 2) `pg_restore` (oder WAL-Replay bis zum Zielzeitpunkt bei PITR). 3) `npx prisma migrate status` prüfen. 4) `npx prisma migrate deploy` falls seit dem Dump neue Migrationen hinzugekommen sind. 5) `GET /health/ready` gegen die wiederhergestellte Instanz aufrufen, um DB-Erreichbarkeit zu bestätigen, bevor Verkehr umgeschaltet wird.