# Effigenix ERP – Agent Guide ## Stack Java 21, Spring Boot 3.2, PostgreSQL, Liquibase, JWT (JJWT), Maven ## Architektur DDD + Clean Architecture. Einweg-Abhängigkeit: `domain → application → infrastructure`. ``` de.effigenix. ├── domain.{bc}/ # Reine Geschäftslogik, KEINE Framework-Deps ├── application.{bc}/ # Use Cases, Commands, DTOs ├── infrastructure.{bc}/ # JPA, REST, Security, Audit └── shared/ # Shared Kernel (Result, AuthorizationPort, Action) ``` Bounded Contexts: `usermanagement` (implementiert), `production`, `quality`, `inventory`, `procurement`, `sales`, `labeling`, `filiales` (Platzhalter). ## Namenskonventionen | Artefakt | Muster | Beispiel | |---|---|---| | Use Case | `{Verb}{Noun}` | `CreateUser`, `AuthenticateUser` | | Command | `{Verb}{Noun}Command` | `CreateUserCommand` | | Domain Entity | `{Noun}` | `User`, `Role` | | Value Object | `{Noun}` | `UserId`, `PasswordHash`, `RoleName` | | Create-Draft | `{Noun}Draft` | `SupplierDraft` | | Update-Draft | `{Noun}UpdateDraft` | `SupplierUpdateDraft` | | Domain Error | `{Noun}Error` (sealed interface) | `UserError.UsernameAlreadyExists` | | JPA Entity | `{Noun}Entity` | `UserEntity` | | Mapper | `{Noun}Mapper` | `UserMapper` (Domain↔JPA) | | Repository (Domain) | `{Noun}Repository` | `UserRepository` (Interface) | | Repository (Impl) | `Jpa{Noun}Repository` | `JpaUserRepository` | | Controller | `{Noun}Controller` | `UserController` | | Web DTO | `{Verb}{Noun}Request` | `CreateUserRequest` | | Action Enum | `{Noun}Action implements Action` | `ProductionAction` | ## EntityDraft-Pattern Für Aggregate mit komplexer VO-Konstruktion (Address, ContactInfo, PaymentTerms u.ä.) gilt: Der Application Layer baut **keine** VOs – er erzeugt einen **Draft-Record** mit rohen Strings und übergibt ihn ans Aggregate. Das Aggregate orchestriert Validierung und VO-Konstruktion intern. ```java // Application Layer – nur Daten weitergeben, kein VO-Wissen var draft = new SupplierDraft(cmd.name(), cmd.phone(), ...); switch (Supplier.create(draft)) { ... } // Domain Layer – validiert intern, gibt Result zurück public static Result create(SupplierDraft draft) { ... } public Result update(SupplierUpdateDraft draft) { ... } ``` **Regeln:** - Pflichtfelder: non-null im Draft-Record - Optionale VOs (z.B. Address, PaymentTerms): `null`-Felder → VO wird nicht konstruiert - Primitive `int` → `Integer` wenn das Feld optional/nullable sein muss - Einzelne `updateXxx(VO)`-Methoden entfallen → ersetzt durch ein `update({Noun}UpdateDraft)` - Uniqueness-Check bleibt im Application Layer (Repository-Concern), nach `Aggregate.create()` - Invarianten-Kommentar im Aggregat aktuell halten ## Error Handling Funktional via `Result` (`shared.common.Result`). Domain-Fehler sind sealed interfaces mit Records. Keine Exceptions im Domain/Application Layer. ## Commits Conventional Commits. Kein `Co-Authored-By` Header – niemals. ## DDD Skill Für neue Bounded Contexts: `/ddd-implement` Skill verwenden. Dokumentation unter `.claude/skills/ddd-implement/SKILL.md`. ## Doku - `docs/QUICK_START.md` – Lokale Entwicklung, Docker, Seed-Daten - `docs/USER_MANAGEMENT.md` – Referenz-BC mit AuthorizationPort, JWT, Audit - `TODO.md` – Offene Aufgaben und Waves