diff --git a/backend/services/series/series-service/src/main/kotlin/at/mocode/series/service/domain/Serie.kt b/backend/services/series/series-service/src/main/kotlin/at/mocode/series/service/domain/Serie.kt index cc540230..5b21d678 100644 --- a/backend/services/series/series-service/src/main/kotlin/at/mocode/series/service/domain/Serie.kt +++ b/backend/services/series/series-service/src/main/kotlin/at/mocode/series/service/domain/Serie.kt @@ -5,7 +5,7 @@ import java.util.* @Entity @Table(name = "serien") -data class Serie( +class Serie( @Id val id: String = UUID.randomUUID().toString(), @@ -16,10 +16,10 @@ data class Serie( val beschreibung: String? = null, @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column(name = "reglement_typ", nullable = false) val reglementTyp: ReglementTyp = ReglementTyp.STREICHER_NORMAL, - @Column(nullable = false) + @Column(name = "streichresultate_count", nullable = false) val streichresultateCount: Int = 1, @Enumerated(EnumType.STRING) @@ -30,7 +30,26 @@ data class Serie( @CollectionTable(name = "serie_bewerbe", joinColumns = [JoinColumn(name = "serie_id")]) @Column(name = "bewerb_id") val bewerbIds: Set = mutableSetOf() -) +) { + fun copy( + id: String = this.id, + name: String = this.name, + beschreibung: String? = this.beschreibung, + reglementTyp: ReglementTyp = this.reglementTyp, + streichresultateCount: Int = this.streichresultateCount, + bindungstyp: Bindungstyp = this.bindungstyp, + bewerbIds: Set = this.bewerbIds + ) = Serie(id, name, beschreibung, reglementTyp, streichresultateCount, bindungstyp, bewerbIds) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Serie) return false + return id == other.id + } + + override fun hashCode(): Int = id.hashCode() + + override fun toString(): String = "Serie(id='$id', name='$name')" +} enum class ReglementTyp { STREICHER_NORMAL, // z.B. 4 von 6 Wertungen zählen @@ -46,20 +65,20 @@ enum class Bindungstyp { @Entity @Table(name = "serie_punkte") -data class SeriePunkt( +class SeriePunkt( @Id val id: String = UUID.randomUUID().toString(), - @Column(nullable = false) + @Column(name = "serie_id", nullable = false) val serieId: String, - @Column(nullable = false) + @Column(name = "reiter_id", nullable = false) val reiterId: String, - @Column(nullable = false) + @Column(name = "pferd_id", nullable = false) val pferdId: String, - @Column(nullable = false) + @Column(name = "bewerb_id", nullable = false) val bewerbId: String, @Column(nullable = false) @@ -67,4 +86,23 @@ data class SeriePunkt( @Column(nullable = false) val platzierung: Int -) +) { + fun copy( + id: String = this.id, + serieId: String = this.serieId, + reiterId: String = this.reiterId, + pferdId: String = this.pferdId, + bewerbId: String = this.bewerbId, + punkte: Double = this.punkte, + platzierung: Int = this.platzierung + ) = SeriePunkt(id, serieId, reiterId, pferdId, bewerbId, punkte, platzierung) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is SeriePunkt) return false + return id == other.id + } + + override fun hashCode(): Int = id.hashCode() + + override fun toString(): String = "SeriePunkt(id='$id', serieId='$serieId', reiterId='$reiterId', pferdId='$pferdId', bewerbId='$bewerbId', punkte=$punkte)" +} diff --git a/backend/services/series/series-service/src/main/resources/db/migration/V1__Create_Series_Tables.sql b/backend/services/series/series-service/src/main/resources/db/migration/V1__Create_Series_Tables.sql new file mode 100644 index 00000000..7b9be7f0 --- /dev/null +++ b/backend/services/series/series-service/src/main/resources/db/migration/V1__Create_Series_Tables.sql @@ -0,0 +1,26 @@ +CREATE TABLE serien ( + id VARCHAR(36) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + beschreibung TEXT, + reglement_typ VARCHAR(50) NOT NULL, + streichresultate_count INTEGER NOT NULL DEFAULT 0, + bindungstyp VARCHAR(50) NOT NULL +); + +CREATE TABLE serie_bewerbe ( + serie_id VARCHAR(36) NOT NULL, + bewerb_id VARCHAR(36) NOT NULL, + PRIMARY KEY (serie_id, bewerb_id), + CONSTRAINT fk_serie FOREIGN KEY (serie_id) REFERENCES serien(id) ON DELETE CASCADE +); + +CREATE TABLE serie_punkte ( + id VARCHAR(36) PRIMARY KEY, + serie_id VARCHAR(36) NOT NULL, + reiter_id VARCHAR(36) NOT NULL, + pferd_id VARCHAR(36) NOT NULL, + bewerb_id VARCHAR(36) NOT NULL, + punkte DOUBLE PRECISION NOT NULL, + platzierung INTEGER NOT NULL, + CONSTRAINT fk_serie_punkte FOREIGN KEY (serie_id) REFERENCES serien(id) ON DELETE CASCADE +); diff --git a/docs/04_Agents/Logs/2026-04-12_Series_Context_Curator_Log.md b/docs/04_Agents/Logs/2026-04-12_Series_Context_Curator_Log.md index 69533331..02f174c1 100644 --- a/docs/04_Agents/Logs/2026-04-12_Series_Context_Curator_Log.md +++ b/docs/04_Agents/Logs/2026-04-12_Series_Context_Curator_Log.md @@ -6,6 +6,10 @@ ## Heute erledigt - **Backend (Series-Service):** + - Behebung von JPA-Warnungen durch Umwandlung von `data class` in reguläre `class` für `Serie` und `SeriePunkt`. + - Implementierung manueller `copy()`, `equals()`, `hashCode()` und `toString()` Methoden zur Sicherstellung der JPA-Kompatibilität und Code-Funktionalität. + - Erstellung der Flyway-Migration `V1__Create_Series_Tables.sql` zur Definition des Datenbankschemas. + - Korrektur der Spalten-Mappings (@Column) zur Übereinstimmung mit dem SQL-Schema (Snake Case). - Erweiterung der JPA-Entität `Serie` um `ReglementTyp`, `streichresultateCount` und `Bindungstyp`. - Implementierung der Geschäftslogik im `SeriesService` zur Berechnung von Zwischenständen unter Berücksichtigung von Streichresultaten. - Unterstützung von verschiedenen Bindungsarten (Reiter+Pferd, nur Reiter, nur Pferd). @@ -20,6 +24,8 @@ - `MASTER_ROADMAP.md` aktualisiert: Phase 10 als abgeschlossen markiert. ## Verifikation -- Kompilierungs-Check des `turnier-feature` Moduls erfolgreich. +- Kompilierungs-Check des `series-service` und `turnier-feature` Moduls erfolgreich. +- Datenbank-Schema: SQL-Migrationen für `serien`, `serie_bewerbe` und `serie_punkte` erfolgreich erstellt. +- JPA-Konformität: `data class` Warnungen beseitigt und persistente Identität via `id` in `equals/hashCode` sichergestellt. - Datenfluss-Analyse: Vom Ktor-Client bis zur Compose-UI werden die neuen Felder (`streichresultateCount`, `bindungstyp`) korrekt durchgereicht. - Geschäftslogik-Check: Der Algorithmus für Streichresultate behandelt Edge-Cases (z.B. weniger Wertungen als Streichresultate) durch Fallback auf das beste Resultat.