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
@@ -1,9 +1,11 @@
plugins {
kotlin("jvm")
alias(libs.plugins.kotlinJvm)
alias(libs.plugins.kotlinSerialization)
}
dependencies {
implementation(projects.core.coreDomain)
implementation(projects.core.coreUtils)
testImplementation(projects.platform.platformTesting)
implementation(projects.core.coreDomain)
implementation(projects.core.coreUtils)
implementation(libs.kotlinx.datetime)
testImplementation(projects.platform.platformTesting)
}
@@ -4,8 +4,9 @@ package at.mocode.events.domain.model
import at.mocode.core.domain.model.AusschreibungsStatusE
import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.serialization.KotlinxInstantSerializer
import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
import kotlin.time.Clock
@@ -44,7 +45,7 @@ import kotlin.uuid.Uuid
* @property updatedAt Letzter Änderungszeitpunkt.
*/
@Serializable
data class DomAusschreibung(
data class Ausschreibung(
@Serializable(with = UuidSerializer::class)
val ausschreibungsId: Uuid = Uuid.random(),
@@ -88,9 +89,9 @@ data class DomAusschreibung(
var genehmigungsNummer: String? = null,
// Audit
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
val createdAt: Instant = Clock.System.now(),
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
var updatedAt: Instant = Clock.System.now()
) {
/**
@@ -150,5 +151,5 @@ data class DomAusschreibung(
/**
* Erstellt eine Kopie mit aktualisiertem Zeitstempel.
*/
fun withUpdatedTimestamp(): DomAusschreibung = this.copy(updatedAt = Clock.System.now())
fun withUpdatedTimestamp(): Ausschreibung = this.copy(updatedAt = Clock.System.now())
}
@@ -8,7 +8,7 @@ import at.mocode.core.domain.model.TurnierkategorieE
import at.mocode.core.domain.model.TurnierStatusE
import at.mocode.events.domain.validation.TurnierBewerbDescriptor
import at.mocode.events.domain.validation.TurnierkategoriePolicy
import at.mocode.core.domain.serialization.KotlinxInstantSerializer
import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
@@ -39,7 +39,7 @@ import kotlin.uuid.Uuid
* @property updatedAt Letzter Änderungszeitpunkt.
*/
@Serializable
data class DomTurnier(
data class Turnier(
@Serializable(with = UuidSerializer::class)
val turnierId: Uuid = Uuid.random(),
@@ -72,13 +72,13 @@ data class DomTurnier(
var bemerkungen: String? = null,
// Audit
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
val createdAt: Instant = Clock.System.now(),
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
var updatedAt: Instant = Clock.System.now()
) {
/**
* Prüft ob das Turnier Pflicht-Funktionäre zugewiesen hat.
* Prüft, ob das Turnier Pflicht-Funktionäre zugewiesen hat.
* Gibt Warnungen zurück keine harten Fehler (Warn-Logik statt Exception, ADR-0007).
*/
fun validateFunktionaerBesetzung(): List<String> {
@@ -115,13 +115,13 @@ data class DomTurnier(
/**
* Erstellt eine Kopie mit aktualisiertem Zeitstempel.
*/
fun withUpdatedTimestamp(): DomTurnier = this.copy(updatedAt = Clock.System.now())
fun withUpdatedTimestamp(): Turnier = this.copy(updatedAt = Clock.System.now())
/**
* Validiert die im Turnier geplanten Bewerbe gegen die Limits der Turnierkategorie.
*
* Hinweis: Die konkreten Regeln stammen aus der ÖTO-Spezifikation und werden vom 📜 Rulebook Expert (A-5)
* bereitgestellt. Diese Methode delegiert daher an eine Policy-Schnittstelle, um Kopplung zu vermeiden und
* bereitgestellt. Diese Methode delegiert sich daher an eine Policy-Schnittstelle, um Kopplung zu vermeiden und
* die Regeln austauschbar zu halten.
*
* Rückgabe: Liste von Meldungen (Fehler/Warnungen) Formulierung/Schweregrad ist Teil der Policy.
@@ -2,15 +2,15 @@
package at.mocode.events.domain.model
import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.serialization.KotlinxInstantSerializer
import at.mocode.core.domain.serialization.KotlinLocalDateSerializer
import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.LocalDateSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlin.uuid.Uuid
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.serialization.Serializable
import kotlin.time.Clock
import kotlin.time.Instant
/**
* Domain model representing an event/competition in the event management system.
@@ -35,40 +35,40 @@ import kotlinx.serialization.Serializable
*/
@Serializable
data class Veranstaltung(
@Serializable(with = UuidSerializer::class)
@Serializable(with = UuidSerializer::class)
val veranstaltungId: Uuid = Uuid.random(),
// Basic Information
var name: String,
var untertitel: String? = null,
var beschreibung: String? = null,
var logoUrl: String? = null,
var sponsoren: String? = null, // JSON string or comma-separated for now
var name: String,
var untertitel: String? = null,
var beschreibung: String? = null,
var logoUrl: String? = null,
var sponsoren: String? = null, // JSON string or comma-separated for now
// Dates
@Serializable(with = KotlinLocalDateSerializer::class)
@Serializable(with = LocalDateSerializer::class)
var startDatum: LocalDate,
@Serializable(with = KotlinLocalDateSerializer::class)
@Serializable(with = LocalDateSerializer::class)
var endDatum: LocalDate,
// Location and Organization
var ort: String,
@Serializable(with = UuidSerializer::class)
var ort: String,
@Serializable(with = UuidSerializer::class)
var veranstalterVereinId: Uuid,
// Event Details
var sparten: List<SparteE> = emptyList(),
var istAktiv: Boolean = true,
var istOeffentlich: Boolean = true,
var maxTeilnehmer: Int? = null,
var sparten: List<SparteE> = emptyList(),
var istAktiv: Boolean = true,
var istOeffentlich: Boolean = true,
var maxTeilnehmer: Int? = null,
@Serializable(with = KotlinLocalDateSerializer::class)
@Serializable(with = LocalDateSerializer::class)
var anmeldeschluss: LocalDate? = null,
// Audit Fields
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
val createdAt: Instant = Clock.System.now(),
@Serializable(with = KotlinxInstantSerializer::class)
@Serializable(with = InstantSerializer::class)
var updatedAt: Instant = Clock.System.now()
) {
/**
@@ -127,7 +127,7 @@ data class Veranstaltung(
}
/**
* Creates a copy of this event with updated timestamp.
* Creates a copy of this event with an updated timestamp.
*/
fun withUpdatedTimestamp(): Veranstaltung {
return this.copy(updatedAt = Clock.System.now())
@@ -15,7 +15,7 @@ data class TurnierBewerbDescriptor(
/**
* Policy-Schnittstelle für die Validierung der Turnierkategorie-Limits (ÖTO-Regelwerk).
* Implementierung wird durch den 📜 Rulebook Expert (A-5) spezifiziert.
* Die Implementierung wird durch den 📜 Rulebook Expert (A-5) spezifiziert.
*/
fun interface TurnierkategoriePolicy {
/**
@@ -4,12 +4,13 @@ import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.model.TurnierkategorieE
import at.mocode.events.domain.validation.TurnierBewerbDescriptor
import at.mocode.events.domain.validation.TurnierkategoriePolicy
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.uuid.Uuid
import kotlinx.datetime.LocalDate
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import kotlin.uuid.ExperimentalUuidApi
class DomTurnierKategorieValidationTest {
class TurnierKategorieValidationTest {
private val fakePolicy = TurnierkategoriePolicy { kategorie, bewerbe ->
val msgs = mutableListOf<String>()
@@ -29,11 +30,13 @@ class DomTurnierKategorieValidationTest {
msgs
}
@OptIn(ExperimentalUuidApi::class)
@Test
fun `C Turnier verbietet 135cm Springen`() {
val turnier = DomTurnier(
val turnier = Turnier(
veranstaltungId = Uuid.random(),
name = "CSN-C Samstag",
turnierNummer = "12345",
sparte = SparteE.SPRINGEN,
kategorie = TurnierkategorieE.C,
datum = LocalDate(2026, 6, 1)
@@ -48,11 +51,13 @@ class DomTurnierKategorieValidationTest {
assertEquals(1, msgs.size, "Erwartet genau eine Limitverletzung (135cm auf C-Turnier)")
}
@OptIn(ExperimentalUuidApi::class)
@Test
fun `C-NEU Turnier verbietet 120cm`() {
val turnier = DomTurnier(
val turnier = Turnier(
veranstaltungId = Uuid.random(),
name = "CSN-C-NEU",
turnierNummer = "12345",
sparte = SparteE.SPRINGEN,
kategorie = TurnierkategorieE.C_NEU,
datum = LocalDate(2026, 6, 1)
@@ -2,8 +2,9 @@ package at.mocode.events.domain.validation
import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.model.TurnierkategorieE
import kotlin.test.Test
import kotlin.test.assertEquals
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class OeToTurnierkategoriePolicyTest {