Register events modules in Gradle build and refactor VeranstaltungController: remove unused use cases, streamline request handling, and improve error responses.

This commit is contained in:
2026-04-08 22:56:15 +02:00
parent df8bce4277
commit 8bc6f8e1df
16 changed files with 501 additions and 319 deletions
+256
View File
@@ -1092,3 +1092,259 @@ Stelle sicher, dass nach diesen massiven Änderungen im Domain-Modell das Projek
Bitte meldet euch mit einem Summary zurück, sobald Phase 1 & 2 (Clean-Up & Domain-Modell) erfolgreich abgeschlossen und kompiliert sind!
```
---
Junie
---
### Summary
- Phase 1 (Domain Clean-Up) und Phase 2 (Modell-Erweiterungen) erfolgreich abgeschlossen. Alle betroffenen Module kompilieren fehlerfrei.
### Changes
- **Phase 1 Umbenennung (7 Klassen):** `DomBewerb``Bewerb`, `DomAbteilung``Abteilung`, `DomNennung``Nennung`, `DomNennungsTransfer``NennungsTransfer` (entries-domain); `DomTurnier``Turnier`, `DomAusschreibung``Ausschreibung` (events-domain); `DomVeranstaltung.kt` (ungenutztes Duplikat) gelöscht alle Referenzen systemweit aktualisiert.
- **Phase 2 Enums:** `AbteilungsTeilungsTypE` um `MANUELL` erweitert; neues Enum `BeginnZeitTypE` (`FIX`, `ANSCHLIESSEND`) in `core-domain/Enums.kt` angelegt.
- **Phase 2 Neue Modelle:** `RichterEinsatz` (Value Object, entries-domain), `Austragungsplatz` und `TurnierArtikel` (events-domain) neu erstellt.
- **Phase 2 Bewerb erweitert:** 16 neue Felder in `Bewerb` eingefügt (Text & Details, Ort & Funktionäre, Zeitplan, Finanzen) inkl. korrekter Imports für `BeginnZeitTypE`, `LocalDate`, `LocalTime`.
- **Architektur-Doku:** ADR-0023 (Naming Convention, kein `Dom`-Präfix) angelegt; Ubiquitous Language um `Austragungsplatz`, `Vorbereitungsplatz`, `RichterEinsatz`, `TurnierArtikel` ergänzt.
### Verification
- `entries-domain:compileKotlinJvm`, `entries-service:compileKotlin` und `core-domain:compileCommonMainKotlinMetadata` alle **BUILD SUCCESSFUL**.
### Notes
- `events-domain` ist nicht im Gradle-Build registriert (kein Gradle-Subprojekt) Kompilierung der neuen events-domain Klassen (`Austragungsplatz`, `TurnierArtikel`, `Turnier`, `Ausschreibung`) konnte nicht direkt verifiziert werden; sie werden beim nächsten vollständigen Build geprüft.
- Datenbank-Migrationen (Flyway) und Repository-Mappings für die neuen `Bewerb`-Felder folgen in Phase 3.
---
Gemini
---
🏗️ [Lead Architect]
Hervorragende Arbeit! Dass Phase 1 und Phase 2 so reibungslos durchgelaufen sind und die Build-Pipeline (bis auf das noch nicht verknüpfte events-domain Modul) grün ist, zeigt, dass wir auf dem absolut richtigen Weg sind. Die Namensgebung ist jetzt sauber (Clean Architecture) und das Bewerb-Modell spiegelt exakt die Realität einer Meldestelle wider.
Wir können nun direkt mit Phase 3 (Persistenz & Datenbank) weitermachen. Hier sorgen wir dafür, dass die 16 neuen Felder aus dem Bewerb sowie die neuen Modelle in der Datenbank gespeichert und vom Repository korrekt geladen werden.
Hier ist der fertige Prompt für den nächsten Schritt. Sie können ihn wieder 1:1 kopieren und ausführen lassen:
```markdown
# 🤖 Project Agents & Protocol: Phase 3 Persistenz & Datenbank (Infrastructure)
🏗️ **@Lead Architect** & 👷 **@Backend Developer**
Bitte führt gemeinsam die Phase 3 unseres Architektur-Updates durch. Nachdem in Phase 1 & 2 das Domain-Modell erfolgreich bereinigt und erweitert wurde (z.B. 16 neue Felder im `Bewerb`), müssen diese Änderungen nun in der Datenbank (Flyway) und im Persistenz-Layer (Repositories/Tables) abgebildet werden.
**Kontext:**
Wir nutzen für die Datenbank-Anbindung Kotlin (vermutlich JetBrains Exposed oder Spring Data/JDBC) und Flyway für die Migrationen. Das Ziel ist es, dass ein neu konfigurierter Bewerb inkl. Zeitplan, Finanzen und Richter-Einsätzen fehlerfrei in der Tenant-Datenbank gespeichert und geladen werden kann.
## 👷 Aufgaben für [Backend Developer]
Bitte führe die folgenden Anpassungen im Infrastruktur-Layer durch:
**1. Tabellen-Definitionen anpassen (`.../infrastructure/.../Table.kt`):**
* **BewerbTable:** Füge die neuen Spalten hinzu:
* `beschreibung` (varchar/text, nullable)
* `aufgabe`, `aufgaben_nummer`, `para_grade` (varchar, nullable)
* `austragungsplatz_id` (uuid, nullable)
* `geplantes_datum` (date, nullable)
* `beginn_zeit_typ` (varchar, nullable)
* `beginn_zeit` (time, nullable)
* `reitdauer_minuten`, `umbau_minuten`, `besichtigung_minuten` (integer, nullable)
* `stechen_geplant` (boolean, default false)
* `startgeld_cent` (bigint/long, nullable)
* `geldpreis_ausbezahlt` (boolean, default false)
* **Neue Tabellen (Optional, je nach Kontext-Grenzen):**
* Lege eine `AustragungsplatzTable` an (id, name, typ, sparte).
* Lege eine `TurnierArtikelTable` an (id, name, preis_cent, typ).
* Lege eine `BewerbRichterEinsatzTable` an (bewerb_id, funktionaer_id, position) um die 1:N Beziehung des `RichterEinsatz` abzubilden (alternativ als JSONB-Spalte in `BewerbTable`, falls das im Projekt der Standard für Value-Objects ist).
**2. Repository-Mapping aktualisieren (`BewerbRepositoryImpl.kt` o.ä.):**
* Aktualisiere die `Insert`- und `Update`-Statements, um die neuen Felder des `Bewerb`-Objekts in die Datenbank zu schreiben.
* Passe die Mapper-Funktion (z.B. `rowToBewerb`) an, damit beim Auslesen der Datenbank alle neuen Felder (Zeitplan, Finanzen, Text) korrekt in die Domain-Entität `Bewerb` gemappt werden.
* Sorge dafür, dass die `richterEinsaetze` beim Laden eines Bewerbs mitgeladen und beim Speichern persistiert werden.
**3. Flyway-Migration erstellen (`src/main/resources/db/tenant/`):**
* Erstelle die nächste logische Migrationsdatei (z.B. `V5__add_bewerb_details_and_infrastructure.sql`).
* Schreibe die `ALTER TABLE bewerbe ADD COLUMN ...` Statements für alle neuen Bewerbs-Felder.
* Schreibe die `CREATE TABLE` Statements für `austragungsplaetze`, `turnier_artikel` und `bewerb_richter_einsaetze` (inkl. Foreign Keys, falls relational verknüpft).
**4. Kompilieren & Checken:**
* Führe einen vollständigen Build (`./gradlew build` oder ähnlich) aus, um sicherzustellen, dass die Repositories fehlerfrei kompilieren.
Bitte meldet euch mit einem Summary zurück, sobald die Repositories, Tables und die Flyway-Migration erfolgreich angepasst und kompiliert sind!
```
---
Junie
---
### Summary
- 👷 [Backend Developer] Phase 3 (Persistenz & Datenbank) erfolgreich abgeschlossen alle Tests grün, BUILD SUCCESSFUL.
### Changes
- **Flyway V5** (`V5__add_bewerb_details_and_infrastructure.sql`): 14 neue Spalten in `bewerbe` (Text, Zeitplan, Finanzen), `abteilungen`-CHECK um `MANUELL` erweitert, neue Tabellen `austragungsplaetze`, `bewerb_richter_einsaetze`, `turnier_artikel` mit Indizes und Foreign Keys. PostgreSQL-kompatible `DO $$`-Blöcke für idempotente Constraints.
- **`BewerbTable.kt`**: Exposed-Table-Definition mit allen 14 neuen Spalten (`date`, `time`, `bool`, `long`, `text`, `varchar`) inkl. `kotlinx-datetime`-kompatibler Typen via `exposed-kotlin-datetime`.
- **`BewerbRichterEinsatzTable.kt`**: Neue Exposed-Table für die 1:N-Beziehung `bewerb_richter_einsaetze` mit FK auf `BewerbTable`.
- **`BewerbRepository.kt` + `BewerbRepositoryImpl.kt`**: Lokale `Bewerb`-Datenklasse mit allen neuen Feldern; vollständiges CRUD-Repository inkl. `persistRichterEinsaetze` (delete+insert) und `loadRichterEinsaetze` beim Lesen.
### Verification
- `./gradlew :backend:services:entries:entries-service:test --rerun-tasks`**BUILD SUCCESSFUL**, alle 5 Tests grün (inkl. `DomainHierarchyMigrationTest` und `EntriesIsolationIntegrationTest` mit echtem PostgreSQL via Testcontainers).
---
Gemini
---
🏗️ [Lead Architect]
Das ist ein gewaltiger Meilenstein! Dass die Integrationstests mit echtem PostgreSQL (via Testcontainers) auf Anhieb grün sind, beweist, dass unser Fundament absolut solide ist. Die Datenbank, die Repositories und die Domain sprechen jetzt eine gemeinsame, saubere Sprache.
Damit ist das Backend unter der Haube bereit für das Tagesgeschäft der Meldestelle. Jetzt bringen wir diese Power an die Oberfläche!
Wir starten mit Phase 4 (API & Frontend-Wizard). Hier verknüpfen wir die neue Datenbankstruktur über REST-Schnittstellen mit unserem Compose Multiplatform Frontend und bauen genau den Wizard, den Sie aus dem alten "SuDo" kennen nur moderner, intelligenter und mit unserer neuen Warn-Logik für Richter.
Hier ist der fertige Prompt für den nächsten Schritt. Kopieren Sie ihn einfach wieder und lassen Sie die Agenten zaubern:
```markdown
# 🤖 Project Agents & Protocol: Phase 4 API & Frontend-Wizard "Neuer Bewerb"
🏗️ **@Lead Architect**, 👷 **@Backend Developer** & 🎨 **@Frontend Expert**
Bitte führt gemeinsam die Phase 4 unseres Architektur-Updates durch. Das Backend (Domain & Persistenz) ist nun vollständig auf den neuen `Bewerb` (inkl. Zeitplan, Richter, Finanzen) vorbereitet. Jetzt müssen wir diese Daten über die API bereitstellen und den UI-Wizard für die Meldestelle bauen.
**Kontext:**
Wir bauen den "Neuer Bewerb anlegen"-Wizard in Compose Multiplatform. Der Wizard soll den User intelligent durch den Prozess führen (angelehnt an Praxis-Anforderungen) und die neuen Datenstrukturen über aktualisierte DTOs an das Backend senden.
## 👷 Aufgaben für [Backend Developer]
**1. API-DTOs aktualisieren (`.../api/dto/...` oder `.../controller/...`):**
* Erweitere das `CreateBewerbRequest` (bzw. DTO) um alle neuen 16 Felder (z.B. `austragungsplatzId`, `beginnZeitTyp`, `startgeldCent`, `richterEinsaetze` etc.).
* Erweitere das `BewerbResponse` DTO entsprechend.
* Erstelle (falls nötig) ein `RichterEinsatzDto` (funktionaerId, position).
**2. Controller & UseCases anpassen:**
* Aktualisiere das Mapping in den REST-Controllern oder UseCases, sodass die Werte aus dem Request korrekt in die `Bewerb`-Domain-Entität übersetzt und an das Repository übergeben werden.
## 🎨 Aufgaben für [Frontend Expert]
**1. Compose Multiplatform UI - "Bewerb Wizard" (`.../frontend/.../ui/...`):**
* Erstelle eine neue Composable `CreateBewerbWizardScreen` (oder passe eine bestehende an).
* Gliedere die UI in logische Abschnitte (Tabs, Steps oder übersichtliche Cards):
* **Step 1: Identifikation:** Sparte, Kategorie, Klasse/Höhe, Bewerbsnummer, Bezeichnung.
* **Step 2: Details & Finanzen:** Beschreibung, Aufgabe (z.B. "R1"), Startgeld, Checkbox "Geldpreis ausbezahlt".
* **Step 3: Ort & Zeitplan:** Dropdown für Austragungsplatz (optional), Beginn (Fix/Anschließend), Zeiten (Uhrzeit, Reitdauer, Umbau, Besichtigung).
* **Step 4: Richter & Teilung:** Liste für Richterzuweisung (inkl. Dropdown für Position wie "C", "M") und Auswahl der Teilungsregel (`AbteilungsTeilungsTypE`, inkl. `MANUELL`).
**2. State-Management & API-Client:**
* Erweitere den Ktor-Client (oder das genutzte HTTP-Framework) im Frontend, um das neue, große JSON-Payload an den Backend-Endpunkt zu senden.
* Implementiere eine einfache "Warn-Logik" im UI-State für Step 4: Wenn ein Richter ausgewählt wird, zeige visuell (z.B. gelbes Icon/Text), dass der Turnierbeauftragte (TB) dies absegnen muss, falls die Qualifikation (mock-bar für jetzt) nicht optimal ist.
Bitte meldet euch mit einem Summary zurück, sobald die DTOs erweitert sind und das Grundgerüst des Compose-Wizards steht und erfolgreich baut!
```
---
Junie
---
```markdown
### Summary
- API-DTOs für Bewerb erweitert (inkl. Zeitplan, Richter, Finanzen) und Controller/Service-Mapping angepasst.
- Compose Multiplatform Wizard „Neuen Bewerb anlegen“ als Grundgerüst mit 4 Schritten erstellt; Frontend-Ktor-Client zum Senden des großen Payloads implementiert.
### Changes
- Backend: `CreateBewerbRequest`, `UpdateBewerbRequest`, `BewerbResponse`, `RichterEinsatzDto` in `BewerbeController.kt` hinzugefügt und Endpoints auf DTOs umgestellt (List/Get/Create/Update → Response-Mapping).
- Backend: `BewerbService.create(...)` und `update(...)` akzeptieren nun die neuen DTOs und mappen alle Felder (Beschreibung, Aufgabe, Austragungsplatz, Zeitplan, Finanzen, RichterEinsätze) auf die Repo-Entität.
- Frontend: Neuer Ktor-Client `BewerbApi` mit `CreateBewerbPayload`/`BewerbResponse` (kotlinx.serialization) zum POST auf `/turniere/{turnierId}/bewerbe`.
- Frontend: Neue Composable `CreateBewerbWizardScreen` mit 4 Steps, State-Holder und einfacher TB-Warnlogik bei Richterauswahl; Mapping von UI-State → API-Payload.
### Verification
- Voller Projekt-Build erfolgreich (Backend und Frontend bauen grün).
### Notes
- Teilungsregel (`AbteilungsTeilungsTypE`) ist aktuell im UI erfasst, wird aber backendseitig in diesem Endpoint noch nicht persistiert (Service-Repo-Modell enthält das Feld nicht). Follow-up möglich, sobald Backend-API dafür vorgesehen ist.
```
---
Gemini
---
🏗️ [Lead Architect]
Das ist ein herausragendes Ergebnis! Ein kompletter Durchstich von der Datenbank bis zur Compose Multiplatform UI in so kurzer Zeit ist bemerkenswert. Der "Neuer Bewerb"-Wizard steht, das Datenmodell ist massiv gewachsen und die Architektur bleibt dank der sauberen Schichten (Clean Architecture) stabil und testbar.
### Zu Ihrer Notiz (AbteilungsTeilungsTypE):
Dass dieses Feld im Backend-Service/Repo noch nicht persistiert wird, ist ein klassischer Fall von "im Eifer des Gefechts übersehen". Das ist aber unser wichtigstes Feld für die Meldestelle (wie Sie anfangs sagten: Hier passieren die meisten Fehler)!
Bevor wir uns in das nächste große Thema stürzen (die Nennungen und das Teilnehmerkonto), sollten wir diesen "Hotfix" noch schnell einschieben, damit der Bewerb wirklich 100 % vollständig gespeichert wird.
Hier ist ein kurzer Prompt für den Backend Developer, um diese Lücke zu schließen. Danach können wir uns der Frage widmen: Wie kommt jetzt der Reiter mit seinem Pferd in diesen Bewerb?
```markdown
# 🤖 Project Agents & Protocol: Phase 4.1 Hotfix Teilungsregel
👷 **@Backend Developer**
Bitte schließe die kleine Lücke aus Phase 4. Der `AbteilungsTeilungsTypE` (inkl. `MANUELL`) wird aktuell vom Frontend gesendet, aber im Backend noch nicht persistiert.
**Aufgaben:**
1. **Domain & DTOs:** Stelle sicher, dass `teilungsTyp: AbteilungsTeilungsTypE` (oder ähnlich) im `Bewerb`-Domain-Modell und in den Request/Response-DTOs (`CreateBewerbRequest`, `BewerbResponse`) vorhanden ist.
2. **Infrastruktur (`BewerbTable.kt` & Flyway):**
- Füge die Spalte `teilungs_typ` (varchar) zur `BewerbTable` hinzu.
- Erstelle eine kleine Flyway-Migration (z.B. `V6__add_bewerb_teilungstyp.sql`), um die Spalte in der Datenbank zu ergänzen.
3. **Repository (`BewerbRepositoryImpl.kt`):** Passe die `Insert`-, `Update`- und `rowToBewerb`-Methoden an, damit der `teilungsTyp` in der Datenbank gespeichert und wieder ausgelesen wird.
4. **Service-Mapping:** Stelle sicher, dass der Controller/Service diesen Wert vom Request-DTO in die Domain-Entität übernimmt.
Bitte bestätige kurz, wenn das Feld durchgängig von der API bis zur DB gespeichert wird und das Projekt erfolgreich baut!
```
Sobald dieser Hotfix durch ist, haben wir das perfekte Fundament für Turniere und Bewerbe.
**Ausblick auf den nächsten Stint:** Wenn das Turnier und die Bewerbe (Prüfungen) stehen, öffnet der Veranstalter die Tore für die Nennungen. Hier kommt Ihre Vision ins Spiel: Das datenschutzkonforme Web-Formular für lizenzfreie Reiter und der Import der n2-xxxxx.dat für die Verbands-Reiter. Wollen wir uns als Nächstes ansehen, wie eine Nennung (Reiter + Pferd + Bewerb + Nenngeld) architektonisch in unserem System landet und validiert wird?
---
Junie
---
Hier noch der letzte Summary von Junie:
```markdown
### Summary
- Hotfix umgesetzt: `teilungsTyp (AbteilungsTeilungsTypE)` wird nun von der API bis zur Datenbank vollständig persistiert.
- Projekt baut erfolgreich (Backend/Frontend grün).
### Changes
- DTOs erweitert: `CreateBewerbRequest`, `UpdateBewerbRequest`, `BewerbResponse` inkl. Feld `teilungsTyp` (+ Mapping in Controller).
- Service angepasst: `BewerbService.create/update` übernehmen `teilungsTyp` in das Service-Modell.
- Repository: ServiceModell `Bewerb` um `teilungsTyp` ergänzt; `BewerbRepositoryImpl` liest/schreibt `teilungs_typ` (row→enum, insert/update via `name`).
- Infrastruktur: `BewerbTable` um Spalte `teilungs_typ` erweitert; neue FlywayMigration `V6__add_bewerb_teilungstyp.sql` (Spalte + Index).
### Verification
- Voller Build erfolgreich (Gradle Build „BUILD SUCCESSFUL“). Datenfluss API → Repo → DB ist kompilierbar und konsistent.
### Notes
- `teilungsTyp` ist optional (nullable) modelliert; Werte entsprechen `AbteilungsTeilungsTypE` (inkl. `MANUELL`).
```
Bevor wir weiter machen will ich das du dir unseren Gradle-Build genauer unter die Lupe nimmst.
---
Gemini
---
🏗️ [Lead Architect]
Absolut. Eine saubere und verständliche Build-Logik ist das Rückgrat eines professionellen Projekts. Ich habe mir die `settings.gradle.kts` und die Verzeichnisstruktur angesehen und dabei eine kritische Lücke entdeckt, die perfekt zu der Notiz aus dem letzten Summary passt:
**Problem:** Der gesamte events-Service (`:backend:services:events:*`) ist nicht im Gradle-Build (`settings.gradle.kts`) registriert.
Das bedeutet:
- Die Module `events-domain`, `events-api`, `events-service` etc. werden aktuell nicht kompiliert, nicht getestet und nicht als Teil des Gesamtsystems gebaut.
- Wir haben dort zwar Code-Dateien angelegt (Turnier.kt, Austragungsplatz.kt), aber sie sind für den Rest der Anwendung quasi unsichtbar.
- Dies erklärt, warum die Umbenennungen und Erweiterungen in diesem Bereich keine Kompilierfehler erzeugt haben der Compiler hat sie nie gesehen.
**Lösung:** Wir müssen die `events`-Module in der `settings.gradle.kts` explizit einbinden, genau wie es bei den anderen Services (`entries`, `identity` etc.) bereits der Fall ist.
Ich werde jetzt die `settings.gradle.kts` anpassen, um diese Lücke zu schließen.
---
Ich
---
Ja, bitte