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

69 commits

Author SHA1 Message Date
Sebastian Frick
0e5d8f7025 feat(inventory): Bestandsbewegungen abfragen mit Zeitraum- und Chargen-Filter – Issue #16
Erweitert die StockMovement-Abfrage um batchReference- und from/to-Filter
mit Filter-Priorität stockId > articleId > batchReference > movementType > from/to.
Inkl. DB-Index auf batch_id, Unit-/Integrationstests und Lasttest-Szenarien.
2026-02-25 08:37:46 +01:00
Sebastian Frick
fa6c0c2d70 feat(inventory): Bestandsbewegung erfassen (StockMovement) – Issue #15
Immutables StockMovement-Aggregate als Audit-Trail für jede Bestandsveränderung.
Domain-Invarianten: positive Quantity, Reason bei WASTE/ADJUSTMENT,
ReferenceDocumentId bei INTER_BRANCH_TRANSFER, Direction-Ableitung aus MovementType.

Domain: StockMovement, MovementType (8 Typen), MovementDirection, StockMovementError
Application: RecordStockMovement, GetStockMovement, ListStockMovements
Infrastructure: JPA-Persistence, REST-Controller (POST/GET), Liquibase 028+029
Tests: ~40 Domain-Unit-Tests, 18 Application-Tests, ~27 Integrationstests
Loadtest: Gatling-Szenarien für Bestandsbewegungen (Seeding, Read, Write)
2026-02-24 23:57:01 +01:00
Sebastian Frick
85f96d685e docs: Sequenzdiagramme 2026-02-24 22:19:37 +01:00
Sebastian Frick
11fb62383b feat(loadtest): Gatling-Lasttests mit ~2500 Requests für komprimiertes Jahres-Volumen
Szenarien: Stammdaten-CRUD, Produktions-Workflow, Lagerverwaltung,
Read-Only-Zugriffe. Batch-Repository auf Summary-Projektion umgestellt,
Permissions-Changeset Merge-Konflikt aufgelöst, Unit-Enum im
JsonBodyBuilder korrigiert (KILOGRAM → KG).
2026-02-24 21:53:25 +01:00
Sebastian Frick
8a9bf849a9 test: Unit-Tests für Masterdata-Domain und Application Layer
Domain-Tests: Article, Customer, ProductCategory, Supplier
Application-Tests: ArticleUseCase, CustomerUseCase,
  ProductCategoryUseCase, SupplierUseCase, ListStorageLocations

JaCoCo: Stub-Paket von Coverage-Analyse ausgeschlossen
2026-02-24 09:50:34 +01:00
Sebastian Frick
d7fcc946e7 test: Blackbox-Integrationstests für dokumentierte Domain-Invarianten
Neue Testdateien:
- RecipeLifecycleIntegrationTest (7 Tests): Aktivierung ohne Zutaten,
  Modifikation aktiver Rezepte, Archivierung, Duplikat-Prüfungen
- RoleControllerIntegrationTest (3 Tests): GET /api/roles mit/ohne
  Berechtigung und ohne Token

Erweiterte Testdateien:
- BatchControllerIntegrationTest (+2): start/cancel von COMPLETED
- StockControllerIntegrationTest (+3): removeBatch und FEFO-Allokation
- StorageLocationControllerIntegrationTest (+2): active=false Filter
- ArticleControllerIntegrationTest (+4): updatePrice, removeSupplier,
  filterByCategory, updateArticle
- CustomerControllerIntegrationTest (+3): removeFrameContract,
  updateCustomer, duplicateLineItems
2026-02-24 09:50:34 +01:00
Sebastian Frick
a77f0ec5df feat(shared): Länderauswahl mit ISO 3166-1 Mapping und CountryPicker
Backend: Country-Record (Shared Kernel), InMemoryCountryRepository mit
~249 Ländern und DACH-Priorisierung, ListCountries-UseCase,
GET /api/countries?q= Endpoint.

Frontend: CountryPicker-Komponente mit Fuzzy-Suche, DACH-Favoriten bei
leerem Query. SupplierCreate-, CustomerCreate- und AddDeliveryAddress-
Screens verwenden jetzt den CountryPicker statt Freitext. Detail-Screens
zeigen den Ländercode in der Adressanzeige.

Closes #71
2026-02-24 09:28:56 +01:00
Sebastian Frick
2811836039 fix(inventory): Aktiv/Inaktiv-Filter für Lagerorte-Liste
ListStorageLocations ignorierte active=false und gab stattdessen
alle Lagerorte zurück. Jetzt wird bei gesetztem active-Parameter
korrekt nach aktivem/inaktivem Status gefiltert.
2026-02-24 08:46:17 +01:00
Sebastian Frick
376557925a feat(tui): TUI für Produktionsauftrag-Freigabe, Bestandsreservierung und Reservierungs-Freigabe
- ProductionOrderCreateScreen: Nach Anlage Freigabe per [F] mit Statusanzeige
- StockDetailScreen: Reservierungen-Tabelle, Menü für Reservieren/Freigeben
- ReserveStockScreen: Neues Formular (Referenztyp, Referenz-ID, Menge, Einheit, Priorität)
- API-Client: release(), reserveStock(), releaseReservation() Methoden
- Hooks: releaseProductionOrder(), reserveStock(), releaseReservation()
- Types: ReservationDTO, StockBatchAllocationDTO, ReserveStockRequest exportiert
- DB: Migration 027 erweitert chk_production_order_status um RELEASED
2026-02-24 00:57:40 +01:00
Sebastian Frick
2938628db4 feat(inventory): Reservierung freigeben (#13)
DELETE /api/inventory/stocks/{stockId}/reservations/{reservationId}
gibt eine bestehende Reservierung frei und stellt die verfügbare
Menge wieder her. Zusätzlich Liquibase-Changeset 025 idempotent
gemacht (ON CONFLICT DO NOTHING).
2026-02-24 00:18:51 +01:00
Sebastian Frick
0b49bb2977 feat(inventory): Bestand reservieren mit FEFO-Allokation (#12)
Implementiert Story 4.1: Reservierung von Beständen mit automatischer
FEFO-Allokation (First-Expired-First-Out) über verfügbare Chargen.

Domain: Reservation-Entity, StockBatchAllocation, ReservationDraft,
FEFO-Logik in Stock.reserve(), availableQuantity() berücksichtigt
bestehende Allokationen. Neue Error-Varianten für InsufficientStock,
InvalidReferenceType, InvalidReservationPriority, ReservationNotFound.

API: POST /api/inventory/stocks/{stockId}/reservations → 201 Created.
Liquibase: reservations + stock_batch_allocations Tabellen mit FK- und
CHECK-Constraints.

Tests: 43 neue Tests (22 Domain, 10 UseCase, 11 Integration) für
FEFO-Logik, Validierung, Mengenprüfung, Auth und Edge Cases.
2026-02-24 00:18:51 +01:00
Sebastian Frick
b77b209f10 feat(production): Produktionsauftrag freigeben (US-P14, #39) 2026-02-24 00:05:41 +01:00
Sebastian Frick
ba37ff647b feat(production): Produktionsauftrag anlegen (US-P13, #38)
ProductionOrder-Aggregate mit DDD + Clean Architecture eingeführt.
Produktionsleiter können Aufträge mit Rezept, Menge, Termin und
Priorität planen. Validierung: Quantity > 0, PlannedDate nicht in
Vergangenheit, Priority (LOW/NORMAL/HIGH/URGENT), Recipe ACTIVE.
2026-02-23 23:26:08 +01:00
Sebastian Frick
792d5f0d97 fix(inventory): Stock-Existenz-Check bei Lagerort-Deaktivierung
DeactivateStorageLocation prüft jetzt via StockRepository ob Bestände am
Lagerort existieren bevor deaktiviert wird (Story 1.2 Akzeptanzkriterium).
5 Unit Tests und 1 Integrationstest für den neuen Check.
2026-02-23 22:40:39 +01:00
Sebastian Frick
42c9ca9d19 feat(inventory): GET Endpoint für einzelnen Lagerort (StorageLocation by ID)
GetStorageLocation Use Case mit AuthorizationPort, GET /{id} Endpoint im Controller.
6 Unit Tests und 5 Integrationstests für alle Edge Cases.
2026-02-23 22:40:30 +01:00
Sebastian Frick
df1d1dfdd3 feat: Sentry-kompatibles Error-Tracking (Bugsink) für Frontend und Backend
Frontend: @sentry/node mit instrument.ts, globale Error-Handler, 5xx-Interceptor.
Backend: sentry-spring-boot-starter-jakarta, Sentry.captureException im GlobalExceptionHandler.
Konfiguration über SENTRY_DSN Env-Variable, Bugsink via make bugsink startbar.
2026-02-23 22:40:19 +01:00
Sebastian Frick
b2b3b59ce9 feat(inventory): Bestände unter Mindestbestand ermitteln (ListStocksBelowMinimum)
GET /api/inventory/stocks/below-minimum zeigt Bestände, deren verfügbare
Menge (AVAILABLE + EXPIRING_SOON) unter dem konfigurierten Mindestbestand
liegt. DB-Prefilter via findAllWithMinimumLevel() + Domain-Filter als
Defense in Depth. StockResponse.from() nutzt nun Stock.availableQuantity()
statt duplizierter Logik.

Closes #11
2026-02-23 16:07:51 +01:00
Sebastian Frick
3c660650e5 feat(production): Charge stornieren (CancelBatch)
PLANNED und IN_PRODUCTION Chargen können mit Angabe eines
Stornierungsgrundes storniert werden. COMPLETED und bereits
CANCELLED Chargen werden abgelehnt.
2026-02-23 14:18:38 +01:00
Sebastian Frick
a08e4194ab feat(production): Charge abschließen (CompleteBatch)
Batch.complete() mit Ist-Menge, Ausschuss und Bemerkungen.
Invarianten: nur IN_PRODUCTION→COMPLETED, mind. eine Consumption,
ActualQuantity > 0, Waste >= 0. Full Vertical Slice mit Domain Event
Stub (BatchCompleted), REST POST /api/batches/{id}/complete und
Liquibase-Migration für die neuen Spalten.
2026-02-23 13:42:23 +01:00
Sebastian Frick
f63790c058 chore: remove lombok 2026-02-23 13:38:02 +01:00
Sebastian Frick
c4a1e59987 feat(inventory): abgelaufene und bald ablaufende Chargen automatisch markieren (CheckStockExpiry)
Täglicher Scheduler prüft alle StockBatches und setzt Status auf
EXPIRED bzw. EXPIRING_SOON basierend auf MHD und MinimumShelfLife.
Reihenfolge: erst EXPIRED, dann EXPIRING_SOON — BLOCKED bleibt unangetastet.
2026-02-23 13:36:42 +01:00
Sebastian Frick
9eb9c93fb7 fix(production): JPA-Save-Pattern, Optimistic Locking und Domain-Validierung
- Managed-Entity-Update statt detach/merge (verhindert DELETE+INSERT-Churn)
- @Version für Optimistic Locking mit ConcurrentModification-Error
- Null-Checks für quantityUsed/quantityUnit vor BigDecimal-Parsing
- Duplicate-Check nach Consumption.create() für robustere Validierung
- FetchType.EAGER→LAZY für BatchEntity.consumptions
- Liquibase-Migration 020 für version-Spalte
2026-02-20 16:52:33 +01:00
Sebastian Frick
a9f5956812 feat(production): Produktion starten und Rohstoffverbrauch dokumentieren (StartBatch, RecordConsumption)
PLANNED-Chargen können in Produktion genommen werden (IN_PRODUCTION),
anschließend wird der Rohstoff-Verbrauch pro InputBatch dokumentiert.
Bildet die Grundlage für die Chargen-Genealogie (Tracing).
2026-02-20 16:52:33 +01:00
Sebastian Frick
8c042925eb 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
2026-02-20 16:40:39 +01:00
Sebastian Frick
e8cbb948b7 feat(inventory): Bestandsparameter ändern (MinimumLevel, MinimumShelfLife)
Stock.update(StockUpdateDraft) ermöglicht optionale Aktualisierung von
MinimumLevel und MinimumShelfLife mit identischer Validierung wie create().
PUT /api/inventory/stocks/{id} Endpoint, UpdateStock Use Case + Tests.

Closes #9
2026-02-20 16:39:02 +01:00
Sebastian Frick
1c65ac7795 feat(production): Chargen abfragen und suchen (GetBatch, ListBatches, FindBatchByNumber)
Full Vertical Slice für Batch-Lese-Endpoints:
- GET /api/production/batches/{id}
- GET /api/production/batches (Filter: status, productionDate, articleId)
- GET /api/production/batches/by-number/{batchNumber}

articleId-Filter löst über RecipeRepository.findByArticleId() die
zugehörigen Recipes auf und sucht dann Batches per findByRecipeIds().

Closes #34
2026-02-20 09:22:25 +01:00
Sebastian Frick
fef3baa0ae refactor(inventory): InvalidFilterCombination Error und CreateStockResponse trennen
- StockError.InvalidFilterCombination statt InvalidArticleId für
  ungültige Filter-Kombination in ListStocks
- CreateStockResponse als eigenständiges DTO für POST createStock
  (ohne batches/quantities), StockResponse bleibt für GET-Endpoints
- MinimumLevelResponse als shared Top-Level-Record extrahiert
2026-02-20 09:13:56 +01:00
Sebastian Frick
1ef37497c3 feat(inventory): GET-Endpoints für Bestandsposition und Chargen abfragen
Query-Endpoints für Stock-Aggregate: GET /api/inventory/stocks (mit
optionalen Filtern storageLocationId/articleId) und GET /api/inventory/stocks/{id}.
StockResponse enthält nun Batches, totalQuantity, availableQuantity und
quantityUnit. Abgesichert über @PreAuthorize STOCK_READ.
2026-02-20 09:13:56 +01:00
Sebastian Frick
e0ac2c2f41 test: TC-ART getestet 2026-02-20 08:46:39 +01:00
Sebastian Frick
6c1e6c24bc feat(production): articleId für Rezepte, TUI-Verbesserungen mit UoM-Carousel, ArticlePicker und Zutaten-Reorder
Backend:
- articleId als Pflichtfeld im Recipe-Aggregate (Domain, Application, Infrastructure)
- Liquibase-Migration 015 mit defaultValue für bestehende Daten
- Alle Tests angepasst (Unit, Integration)

Frontend:
- UoM-Carousel-Selektor in RecipeCreateScreen, AddBatchScreen, AddIngredientScreen
- ArticlePicker-Komponente mit Typeahead-Suche für Artikelauswahl
- Auto-Position bei Zutatenzugabe (kein manuelles Feld mehr)
- Automatische subRecipeId-Erkennung bei Artikelauswahl
- Zutaten-Reorder per Drag im RecipeDetailScreen (Remove + Re-Add)
- Artikelnamen statt UUIDs in der Rezept-Detailansicht
- Navigation-Context: replace()-Methode ergänzt
2026-02-20 01:15:34 +01:00
Sebastian Frick
b46495e1aa refactor: OffsetDateTime-Migration, atomare Batch-Sequenznummern und Quantity.reconstitute-Overload
- LocalDateTime → OffsetDateTime (UTC) in allen Domain-Klassen, JPA Entities, DTOs und Tests
- Liquibase-Migration 017: TIMESTAMP → TIMESTAMP WITH TIME ZONE für bestehende Spalten
- Custom DateTimeProvider für Spring Data @CreatedDate-Kompatibilität mit OffsetDateTime
- Neue Sequenztabelle (016) mit JPA Entity + PESSIMISTIC_WRITE Lock statt COUNT-basierter
  Batch-Nummernvergabe (Race Condition Fix)
- Quantity.reconstitute(amount, uom) 2-Parameter-Overload für bessere Lesbarkeit
2026-02-20 00:41:11 +01:00
Sebastian Frick
b06157b92c feat(production): Charge planen (PlanBatch) (#33)
Batch-Aggregat mit plan()-Factory, automatischer BatchNumber-Generierung
(P-YYYY-MM-DD-XXX) und Validierung (Quantity > 0, bestBeforeDate > productionDate).
Full Vertical Slice: Domain, Application, Infrastructure (JPA, REST, Liquibase).
2026-02-20 00:41:11 +01:00
Sebastian Frick
d963d7fccc fix(inventory): Audit-Logging, testbare Zeitlogik und defensive Null-Prüfung für blockBatch/unblockBatch
- AuditEvents STOCK_BATCH_BLOCKED/UNBLOCKED hinzugefügt, reason wird als Audit-Details geloggt
- LocalDate.now() aus Stock.unblockBatch() entfernt, referenceDate als Parameter (Application Layer übergibt)
- Defensive Null-Prüfung für expiryDate in unblockBatch MHD-Check
- Ticket 003 erstellt zur Klärung ob reason im Domain-Model persistiert werden soll
2026-02-20 00:17:03 +01:00
Sebastian Frick
e7c3258f07 feat(inventory): Charge sperren/entsperren (blockBatch/unblockBatch) (#7)
Gesperrte Chargen können nicht entnommen oder reserviert werden.
blockBatch: AVAILABLE/EXPIRING_SOON → BLOCKED; unblockBatch: BLOCKED → AVAILABLE/EXPIRING_SOON (MHD-Check).
2026-02-19 23:46:34 +01:00
Sebastian Frick
8a9d2bfc30 feat(production): Zyklus-Erkennung bei verschachtelten Rezepten (#32)
Verhindert zirkuläre Abhängigkeiten (A→B→A, A→B→C→A) beim Hinzufügen
von Sub-Rezepten als Zutaten. Iterative DFS-Prüfung mit Pfad-Tracking
für aussagekräftige Fehlermeldungen.
2026-02-19 23:00:22 +01:00
Sebastian Frick
05147227d1 feat(inventory): Charge entnehmen (removeBatch) (#6) 2026-02-19 22:55:12 +01:00
Sebastian Frick
f2003a3093 feat(production): Rezepte abfragen per ID und nach Status filtern (#31)
GET /api/recipes/{id} liefert vollständiges Rezept inkl. Zutaten und Schritte.
GET /api/recipes?status=ACTIVE liefert Summary-Liste mit ingredientCount/stepCount.
2026-02-19 22:30:55 +01:00
Sebastian Frick
6feb3a9f1c feat(inventory): Charge einbuchen (addBatch) (#5)
StockBatch als Child-Entity im Stock-Aggregat mit BatchReference
(batchId + batchType), Quantity, ExpiryDate und Status AVAILABLE.
POST /api/inventory/stocks/{stockId}/batches → 201.
2026-02-19 22:28:48 +01:00
Sebastian Frick
1e12353b9b test(production): Tests für ActivateRecipe und ArchiveRecipe Use Cases
Domain-Tests für archive() in RecipeTest, Application-Layer-Tests
für beide Use Cases mit Mockito (Auth, NotFound, Statusübergänge).
2026-02-19 22:01:10 +01:00
Sebastian Frick
408813a5b5 feat(production): Rezept archivieren (#30) 2026-02-19 21:56:11 +01:00
Sebastian Frick
7b1c114693 refactor(test): gemeinsame AbstractIntegrationTest Base-Class
Alle 9 Integration-Test-Klassen nutzen eine gemeinsame Base-Class mit
geteiltem Spring Context (MOCK statt RANDOM_PORT), vorberechnetem
BCrypt-Hash und gemeinsamen Helper-Methoden. Eliminiert ~600 Zeilen
Duplikation und Runtime-BCrypt-Aufrufe im Test-Setup.
2026-02-19 21:37:47 +01:00
Sebastian Frick
5219c93dd1 feat(inventory): Bestandsposition anlegen (#4)
Stock-Aggregate mit MinimumLevel, MinimumShelfLife und StockDraft.
Quantity/UnitOfMeasure nach shared.common verschoben für BC-übergreifende
Nutzung. REST-Endpoint POST /api/inventory/stocks mit Duplikat-Prüfung,
Validierung und Liquibase-Migration.
2026-02-19 21:37:47 +01:00
Sebastian Frick
7079f12475 feat: Stub-Repositories für no-db Profil (Recipe, StorageLocation) 2026-02-19 21:24:43 +01:00
Sebastian Frick
a132211a74 feat(production): Rezept aktivieren (#29)
Rezepte können vom DRAFT- in den ACTIVE-Status überführt werden.
Voraussetzung: mindestens eine Zutat muss vorhanden sein.
Inkl. Use Case, REST-Endpoint POST /recipes/{id}/activate,
Domain-Tests und Error Handling.
2026-02-19 21:24:39 +01:00
Sebastian Frick
cf93b847e5 feat(production): Produktionsschritte zum Rezept verwalten + AuthorizationPort
Erweitert das Recipe-Aggregate um ProductionStep-Child-Entities (Add/Remove)
mit vollständiger DDD-Konformität. Führt AuthorizationPort-Prüfung in allen
Production Use Cases ein (analog zum usermanagement-Referenz-BC).

Fixes: Request-Validierung (Size, Min/Max), Error-Code-Konsistenz,
Defense-in-Depth für durationMinutes und temperatureCelsius.
2026-02-19 17:37:18 +01:00
Sebastian Frick
c26d72fbe7 feat: TUI-Screens für Inventar und Produktion + API-Client Typ-Migration
Neue TUI-Features:
- Inventar: Lageorte auflisten, anlegen, bearbeiten, (de-)aktivieren
- Produktion: Rezepte auflisten, anlegen, Detail-Ansicht
- Navigation erweitert (Hauptmenü, Routing)

API-Client auf generierte OpenAPI-Typen umgestellt:
- 6 neue Alias-Dateien in @effigenix/types (supplier, category, article,
  customer, inventory, production)
- api-client Re-Exports direkt von @effigenix/types statt via Resources
- Backend: @Schema(requiredProperties) auf 16 Response-Records
- Backend: OpenApiCustomizer für application-layer DTOs (UserDTO, RoleDTO)

Hinweis: Backend-Endpoints für GET /api/recipes und
GET /api/inventory/storage-locations/{id} fehlen noch (separate Issues).
2026-02-19 13:54:29 +01:00
Sebastian Frick
bee3f28b5f feat(production): Zutaten zum Rezept verwalten (#27)
Ingredient als Child Entity des Recipe Aggregates implementiert.
Folgt dem Article → SalesUnit Pattern als Full Vertical Slice.

Domain: IngredientId, Ingredient, IngredientDraft, Recipe.addIngredient/removeIngredient
Application: AddRecipeIngredient, RemoveRecipeIngredient Use Cases
Infrastructure: IngredientEntity (JPA), REST-Endpoints (POST/DELETE), Liquibase Migration
Tests: RecipeTest (9 neue), IngredientTest (11 Tests)
2026-02-19 12:53:11 +01:00
Sebastian Frick
6010820944 feat(inventory): Lagerorte abfragen mit Filter nach Typ und Status (#3)
Query UseCase: ListStorageLocations mit optionalen Filtern storageType und active
GET /api/inventory/storage-locations mit STOCK_READ oder STOCK_WRITE
Tests: 10 neue Integrationstests (35 gesamt)
2026-02-19 12:42:25 +01:00
Sebastian Frick
9b9b7311d1 feat(production): Recipe Aggregate als Full Vertical Slice (#26)
Domain: Recipe Aggregate Root mit create(RecipeDraft), RecipeId, RecipeName,
RecipeType, RecipeStatus, RecipeError, RecipeRepository Interface.
Application: CreateRecipe Use Case mit Name+Version Uniqueness-Check.
Infrastructure: JPA Entity/Mapper/Repository, REST POST /api/recipes,
Liquibase Migration, ProductionErrorHttpStatusMapper, Spring Config.
Tests: 15 Unit Tests für Recipe Aggregate (75 total im Production BC).
2026-02-19 10:12:48 +01:00
Sebastian Frick
24a6869faf feat(inventory): StorageLocation bearbeiten und (de-)aktivieren (#2)
Use Cases: UpdateStorageLocation, DeactivateStorageLocation, ActivateStorageLocation
Endpoints: PUT /{id}, PATCH /{id}/deactivate, PATCH /{id}/activate
Repository: existsByNameAndIdNot für Uniqueness-Check bei Update
Tests: 14 neue Integrationstests (25 gesamt)
2026-02-19 10:12:25 +01:00