1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 10:09:35 +01:00

docs: manuelle Testfälle für Inventory und Production BC ergänzen

Testfälle aus allen GitHub-Issues mit Status 'Done' abgeleitet:
- TC-SL (1-15): Lagerorte
- TC-STK (1-5): Bestandspositionen
- TC-BATCH (1-10): Chargen
- TC-REC (1-22): Rezepte
- TC-CYCLE (1-3): Zyklus-Erkennung
- TC-BAT (1-4): Chargenplanung
- TC-INV-CROSS/TC-PROD-CROSS: Übergreifende Tests
This commit is contained in:
Sebastian Frick 2026-02-20 08:46:08 +01:00
parent e8cbb948b7
commit 8c042925eb

View file

@ -305,6 +305,346 @@ POST /api/customers/{b2c-id}/frame-contract
---
# Manuelle Testfälle Inventory BC
## Kontext
Der Inventory Bounded Context umfasst zwei Aggregate:
- **StorageLocation** Lagerorte mit Typ und optionalem Temperaturbereich
- **Stock** Bestandspositionen mit chargengenauer Führung (Batches)
Alle Schreiboperationen erfordern `INVENTORY_WRITE`-Permission. API-Basis: `/api/inventory/`
---
## TC-SL: Lagerorte (GitHub #1, #2, #3)
### TC-SL-01: Lagerort erstellen Pflichtfelder (Happy Path)
1. `POST /api/inventory/storage-locations`
2. Body: `name: "Kühlraum 1"`, `storageType: "COLD_ROOM"` → ohne Temperaturbereich
- [ ] **Erwartung:** 201 Created; Lagerort hat ID, Status aktiv
### TC-SL-02: Lagerort erstellen mit Temperaturbereich
1. `POST /api/inventory/storage-locations`
2. Body: `name: "Tiefkühllager"`, `storageType: "FREEZER"`, `minTemperature: -25`, `maxTemperature: -18`
- [ ] **Erwartung:** 201 Created; Temperaturbereich korrekt gespeichert
### TC-SL-03: Lagerort erstellen ungültiger Temperaturbereich (min >= max)
1. Body: `name: "Fehler-Lager"`, `storageType: "COLD_ROOM"`, `minTemperature: 10`, `maxTemperature: 5`
- [ ] **Erwartung:** 400 Bad Request; Validierungsfehler
### TC-SL-04: Lagerort erstellen Temperatur außerhalb Grenzen
1. Body: `minTemperature: -60`, `maxTemperature: 90` (Grenzen: -50 bis +80)
- [ ] **Erwartung:** 400 Bad Request
### TC-SL-05: Doppelter Name wird abgelehnt
1. Lagerort `Kühlraum 1` erneut anlegen (Name existiert bereits)
- [ ] **Erwartung:** 409 Conflict; spezifische Fehlermeldung
### TC-SL-06: Leerer Name wird abgelehnt
1. Body: `name: ""`, `storageType: "COLD_ROOM"`
- [ ] **Erwartung:** 400 Bad Request
### TC-SL-07: Lagerort bearbeiten Name und Temperatur ändern
1. `PUT /api/inventory/storage-locations/{id}`
2. Name auf `Kühlraum A` ändern, Temperaturbereich anpassen
- [ ] **Erwartung:** 200 OK; Änderungen gespeichert
- [ ] **Erwartung:** StorageType ist unverändert (immutable)
### TC-SL-08: Lagerort bearbeiten Unique-Check bei Namensänderung
1. Lagerort umbenennen auf einen bereits existierenden Namen
- [ ] **Erwartung:** 409 Conflict
### TC-SL-09: Lagerort deaktivieren (ohne Bestand)
1. `PATCH /api/inventory/storage-locations/{id}/deactivate` (Lagerort ohne Stock)
- [ ] **Erwartung:** 200 OK; Status inaktiv
### TC-SL-10: Lagerort deaktivieren (mit Bestand) schlägt fehl
1. Lagerort hat zugeordneten Stock → Deaktivieren versuchen
- [ ] **Erwartung:** 400/409; Fehlermeldung Bestand existiert
### TC-SL-11: Lagerort aktivieren
1. Deaktivierten Lagerort reaktivieren
- [ ] **Erwartung:** 200 OK; Status aktiv
### TC-SL-12: Doppelte Deaktivierung/Aktivierung
1. Bereits inaktiven Lagerort erneut deaktivieren
- [ ] **Erwartung:** Spezifischer Fehler (bereits inaktiv)
2. Bereits aktiven Lagerort erneut aktivieren
- [ ] **Erwartung:** Spezifischer Fehler (bereits aktiv)
### TC-SL-13: Lagerorte auflisten
1. `GET /api/inventory/storage-locations`
- [ ] **Erwartung:** Liste aller Lagerorte mit id, name, storageType, temperatureRange, active
### TC-SL-14: Lagerorte filtern nach Typ
1. `GET /api/inventory/storage-locations?storageType=COLD_ROOM`
- [ ] **Erwartung:** Nur Kühlraum-Lagerorte
### TC-SL-15: Lagerorte filtern nach Status
1. `GET /api/inventory/storage-locations?active=true`
- [ ] **Erwartung:** Nur aktive Lagerorte
---
## TC-STK: Bestandspositionen (GitHub #4)
### TC-STK-01: Bestandsposition erstellen (Happy Path)
1. `POST /api/inventory/stocks`
2. Body: `articleId: "{existierendeId}"`, `storageLocationId: "{existierendeId}"`
- [ ] **Erwartung:** 201 Created; Stock angelegt
### TC-STK-02: Bestandsposition erstellen mit MinimumLevel und MinimumShelfLife
1. Body: `articleId`, `storageLocationId`, `minimumLevel: 10`, `minimumShelfLife: 5`
- [ ] **Erwartung:** 201 Created; Werte korrekt gespeichert
### TC-STK-03: Doppelte Bestandsposition (gleicher Artikel + Lagerort)
1. Gleiche Kombination `articleId + storageLocationId` erneut anlegen
- [ ] **Erwartung:** 409 Conflict
### TC-STK-04: Bestandsposition MinimumLevel negativ
1. Body: `minimumLevel: -1`
- [ ] **Erwartung:** 400 Bad Request
### TC-STK-05: Bestandsposition MinimumShelfLife 0 oder negativ
1. Body: `minimumShelfLife: 0`
- [ ] **Erwartung:** 400 Bad Request
---
## TC-BATCH: Chargen einbuchen/entnehmen/sperren (GitHub #5, #6, #7)
### TC-BATCH-01: Charge einbuchen (Happy Path)
1. `POST /api/inventory/stocks/{stockId}/batches`
2. Body: `batchId: "CH-001"`, `batchType: "PURCHASED"`, `quantity: 50`, `expiryDate: "2026-06-01"`
- [ ] **Erwartung:** 201 Created; Status AVAILABLE; receivedAt automatisch gesetzt
### TC-BATCH-02: Charge einbuchen Menge 0 oder negativ
1. Body: `quantity: 0`
- [ ] **Erwartung:** 400 Bad Request
2. Body: `quantity: -5`
- [ ] **Erwartung:** 400 Bad Request
### TC-BATCH-03: Doppelte BatchReference im selben Stock
1. Erneut `batchId: "CH-001"`, `batchType: "PURCHASED"` einbuchen
- [ ] **Erwartung:** 400/409; Duplikat abgelehnt
### TC-BATCH-04: Charge teilweise entnehmen
1. `POST /api/inventory/stocks/{stockId}/batches/{batchId}/remove`
2. Body: `quantity: 20` (von 50 verfügbar)
- [ ] **Erwartung:** 200 OK; Restmenge = 30
### TC-BATCH-05: Charge vollständig entnehmen
1. Restmenge (30) komplett entnehmen
- [ ] **Erwartung:** 200 OK; Charge wird entfernt
### TC-BATCH-06: Entnahme übersteigt Bestand
1. Mehr entnehmen als verfügbar (z.B. 100 von 50)
- [ ] **Erwartung:** 400; NegativeStockNotAllowed
### TC-BATCH-07: Charge sperren
1. `POST /api/inventory/stocks/{stockId}/batches/{batchId}/block`
2. Body: `reason: "Qualitätsprüfung ausstehend"`
- [ ] **Erwartung:** 200 OK; Status wechselt auf BLOCKED; Grund dokumentiert
### TC-BATCH-08: Gesperrte Charge kann nicht entnommen werden
1. Entnahme aus BLOCKED-Charge versuchen
- [ ] **Erwartung:** 400; Entnahme verweigert
### TC-BATCH-09: Charge entsperren
1. `POST /api/inventory/stocks/{stockId}/batches/{batchId}/unblock`
- [ ] **Erwartung:** 200 OK; Status zurück auf AVAILABLE (oder EXPIRING_SOON)
### TC-BATCH-10: Doppeltes Sperren/Entsperren
1. Bereits gesperrte Charge erneut sperren
- [ ] **Erwartung:** Spezifischer Fehler
2. Bereits freigegebene Charge erneut entsperren
- [ ] **Erwartung:** Spezifischer Fehler
---
# Manuelle Testfälle Production BC
## Kontext
Der Production Bounded Context umfasst:
- **Recipe** Rezeptverwaltung mit Zutaten, Produktionsschritten, Status-Lifecycle
- **Batch** Chargenplanung und -produktion
- **Quantity** Value Object mit Catch-Weight-Unterstützung
API-Basis: `/api/recipes` und `/api/batches`
---
## TC-REC: Rezepte (GitHub #26, #27, #28, #29, #30, #31)
### TC-REC-01: Rezept erstellen (Happy Path)
1. `POST /api/recipes`
2. Body: `name: "Bratwurst Classic"`, `version: 1`, `recipeType: "FINISHED_PRODUCT"`, `yieldPercentage: 85`, `shelfLifeDays: 14`, `outputQuantity: {amount: 10, uom: "KILOGRAM"}`
- [ ] **Erwartung:** 201 Created; Status = DRAFT
### TC-REC-02: Rezept erstellen YieldPercentage Grenzen
1. Body: `yieldPercentage: 0`
- [ ] **Erwartung:** 400; InvalidYieldPercentage
2. Body: `yieldPercentage: 201`
- [ ] **Erwartung:** 400; InvalidYieldPercentage
### TC-REC-03: Rezept erstellen ShelfLifeDays 0 bei FINISHED_PRODUCT
1. Body: `recipeType: "FINISHED_PRODUCT"`, `shelfLifeDays: 0`
- [ ] **Erwartung:** 400; InvalidShelfLife
### TC-REC-04: Doppelter Name + Version wird abgelehnt
1. Erneut `name: "Bratwurst Classic"`, `version: 1` anlegen
- [ ] **Erwartung:** 409 Conflict
### TC-REC-05: Zutat zu DRAFT-Rezept hinzufügen (Happy Path)
1. `POST /api/recipes/{id}/ingredients`
2. Body: `position: 1`, `articleId: "{id}"`, `quantity: {amount: 5, uom: "KILOGRAM"}`, `substitutable: false`
- [ ] **Erwartung:** 200 OK; Zutat im Rezept
### TC-REC-06: Zweite Zutat hinzufügen
1. Body: `position: 2`, andere ArticleId, Menge
- [ ] **Erwartung:** 200 OK; 2 Zutaten im Rezept
### TC-REC-07: Zutat mit doppelter Position
1. Body: `position: 1` (bereits vergeben)
- [ ] **Erwartung:** 400; DuplicatePosition
### TC-REC-08: Zutat zu ACTIVE-Rezept hinzufügen
1. Rezept aktivieren, dann Zutat hinzufügen versuchen
- [ ] **Erwartung:** 400; NotInDraftStatus
### TC-REC-09: Zutat mit SubRecipeId (Zwischen-Rezept)
1. INTERMEDIATE-Rezept als SubRecipe anlegen
2. Zutat mit `subRecipeId` zum Hauptrezept hinzufügen
- [ ] **Erwartung:** 200 OK; Zutat referenziert Sub-Rezept
### TC-REC-10: Zutat entfernen
1. `DELETE /api/recipes/{id}/ingredients/{ingredientId}`
- [ ] **Erwartung:** 200 OK; Zutat entfernt, Position-Lücke erlaubt
### TC-REC-11: Produktionsschritt hinzufügen (Happy Path)
1. `POST /api/recipes/{id}/steps`
2. Body: `stepNumber: 1`, `description: "Fleisch wolfen"`, `durationMinutes: 15`, `temperatureCelsius: 4`
- [ ] **Erwartung:** 200 OK; Schritt im Rezept
### TC-REC-12: Produktionsschritt leere Beschreibung
1. Body: `stepNumber: 2`, `description: ""`
- [ ] **Erwartung:** 400; Validierungsfehler
### TC-REC-13: Produktionsschritt zu ACTIVE-Rezept
1. Schritt zu aktiviertem Rezept hinzufügen versuchen
- [ ] **Erwartung:** 400; NotInDraftStatus
### TC-REC-14: Produktionsschritt entfernen
1. `DELETE /api/recipes/{id}/steps/{stepNumber}`
- [ ] **Erwartung:** 200 OK; Schritt entfernt, keine automatische Umnummerierung
### TC-REC-15: Rezept aktivieren (Happy Path)
1. Rezept mit mindestens einer Zutat → `POST /api/recipes/{id}/activate`
- [ ] **Erwartung:** 200 OK; Status = ACTIVE
### TC-REC-16: Rezept aktivieren ohne Zutaten
1. Leeres DRAFT-Rezept aktivieren
- [ ] **Erwartung:** 400; NoIngredients
### TC-REC-17: Rezept aktivieren bereits ACTIVE
1. Aktives Rezept erneut aktivieren
- [ ] **Erwartung:** 400; InvalidStatusTransition
### TC-REC-18: Rezept archivieren (Happy Path)
1. `POST /api/recipes/{id}/archive` (Rezept ist ACTIVE)
- [ ] **Erwartung:** 200 OK; Status = ARCHIVED
### TC-REC-19: Rezept archivieren aus DRAFT
1. DRAFT-Rezept archivieren versuchen
- [ ] **Erwartung:** 400; InvalidStatusTransition
### TC-REC-20: Rezept per ID abfragen
1. `GET /api/recipes/{id}`
- [ ] **Erwartung:** 200 OK; vollständiges Rezept mit Zutaten und Schritten
### TC-REC-21: Rezept nicht gefunden
1. `GET /api/recipes/{nicht-existierende-id}`
- [ ] **Erwartung:** 404 Not Found
### TC-REC-22: Rezepte nach Status filtern
1. `GET /api/recipes?status=ACTIVE`
- [ ] **Erwartung:** Nur aktive Rezepte; Liste enthält Zutaten-Count aber nicht volle Zutaten
---
## TC-CYCLE: Zyklus-Erkennung (GitHub #32)
### TC-CYCLE-01: Lineare Verschachtelung erlaubt (A → B → C)
1. Rezept C (ACTIVE, mit Zutat)
2. Rezept B (DRAFT) → Zutat mit `subRecipeId: C`
3. Rezept A (DRAFT) → Zutat mit `subRecipeId: B`
- [ ] **Erwartung:** Alle Zuweisungen erfolgreich; keine Fehler
### TC-CYCLE-02: Direkte Zirkularität (A → B → A)
1. Rezept A enthält Zutat mit `subRecipeId: B`
2. Rezept B: Zutat mit `subRecipeId: A` hinzufügen
- [ ] **Erwartung:** 400; CyclicDependencyDetected mit Pfad-Angabe
### TC-CYCLE-03: Indirekte Zirkularität (A → B → C → A)
1. A → B → C existiert
2. Zutat mit `subRecipeId: A` zu Rezept C hinzufügen
- [ ] **Erwartung:** 400; CyclicDependencyDetected mit Pfad-Angabe
---
## TC-BAT: Chargenplanung (GitHub #33)
### TC-BAT-01: Charge planen (Happy Path)
1. `POST /api/batches`
2. Body: `recipeId: "{id}"`, `plannedQuantity: {amount: 50, uom: "KILOGRAM"}`, `productionDate: "2026-03-01"`, `bestBeforeDate: "2026-03-15"`
- [ ] **Erwartung:** 201 Created; Status = PLANNED; BatchNumber automatisch generiert (Format `P-YYYY-MM-DD-XXX`)
### TC-BAT-02: Charge planen PlannedQuantity 0
1. Body: `plannedQuantity: {amount: 0, uom: "KILOGRAM"}`
- [ ] **Erwartung:** 400; Menge muss positiv sein
### TC-BAT-03: Charge planen BestBeforeDate vor ProductionDate
1. Body: `productionDate: "2026-03-15"`, `bestBeforeDate: "2026-03-01"`
- [ ] **Erwartung:** 400; BestBeforeDate muss nach ProductionDate liegen
### TC-BAT-04: BatchNumber-Format prüfen
1. Mehrere Chargen am selben Tag planen
- [ ] **Erwartung:** BatchNumbers haben Format `P-YYYY-MM-DD-XXX` mit aufsteigender Sequenz
---
## TC-INV-CROSS: Übergreifende Tests Inventory
### TC-INV-CROSS-01: Sequenz Kompletter Lagerort-Workflow
1. Lagerort erstellen → Name ändern → Temperatur anpassen → deaktivieren (ohne Stock) → reaktivieren
- [ ] **Erwartung:** Alle Schritte funktionieren ohne Datenverlust
### TC-INV-CROSS-02: Sequenz Kompletter Chargen-Workflow
1. Lagerort erstellen → Stock anlegen → Charge einbuchen → Teilentnahme → Charge sperren → Charge entsperren → Rest entnehmen
- [ ] **Erwartung:** Konsistenz über alle Schritte; Mengen korrekt
### TC-INV-CROSS-03: Lagerort mit Bestand kann nicht deaktiviert werden
1. Lagerort mit Stock + Charge → Deaktivierung versuchen
- [ ] **Erwartung:** Fehler; Bestand muss erst entfernt werden
---
## TC-PROD-CROSS: Übergreifende Tests Production
### TC-PROD-CROSS-01: Sequenz Rezept-Lifecycle komplett
1. Rezept erstellen (DRAFT) → 2 Zutaten hinzufügen → 2 Schritte hinzufügen → 1 Zutat entfernen → aktivieren → archivieren
- [ ] **Erwartung:** Konsistenz über alle Schritte
### TC-PROD-CROSS-02: Sequenz Rezept + Chargenplanung
1. Rezept erstellen → Zutaten → aktivieren → Charge planen mit diesem Rezept
- [ ] **Erwartung:** Charge referenziert Rezept korrekt
### TC-PROD-CROSS-03: Verschachteltes Rezept vollständig
1. INTERMEDIATE-Rezept erstellen + aktivieren → FINISHED_PRODUCT-Rezept mit SubRecipe-Zutat → aktivieren → Charge planen
- [ ] **Erwartung:** Alle Abhängigkeiten korrekt aufgelöst
---
## Verifikation / Testdurchführung
```bash
@ -315,7 +655,7 @@ POST /api/customers/{b2c-id}/frame-contract
cd frontend/apps/cli && pnpm dev
# Backend-Logs beobachten (Fehler sichtbar machen)
# Direkte API-Tests (für TC-B2B-02, TC-AUTH)
# Direkte API-Tests (für TC-B2B-02, TC-AUTH, Inventory, Production)
curl -X POST http://localhost:8080/api/... -H "Authorization: Bearer <token>"
```
@ -327,3 +667,11 @@ curl -X POST http://localhost:8080/api/... -H "Authorization: Bearer <token>"
- [ ] TC-B2B (1-2) durchgeführt
- [ ] TC-AUTH (1-3) durchgeführt
- [ ] TC-CROSS (1-5) durchgeführt
- [ ] Alle TC-SL (1-15) durchgeführt
- [ ] Alle TC-STK (1-5) durchgeführt
- [ ] Alle TC-BATCH (1-10) durchgeführt
- [ ] Alle TC-REC (1-22) durchgeführt
- [ ] TC-CYCLE (1-3) durchgeführt
- [ ] TC-BAT (1-4) durchgeführt
- [ ] TC-INV-CROSS (1-3) durchgeführt
- [ ] TC-PROD-CROSS (1-3) durchgeführt