feat(event-feature): enhance Veranstaltungs- & Turnier-Workflow
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Waiting to run

- Extended `Veranstaltung` domain model with new fields: `untertitel`, `logoUrl`, and `sponsoren`.
- Refined navigation in `DesktopMainLayout.kt` to check turnier context and improve routing.
- Overhauled `TurnierStammdatenTab` with enhanced interactivity: dynamic chip-based selectors for Spartens, Klassen, and Sponsors, as well as date pickers and ZNS import handling.
- Implemented validations for date ranges and required fields.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-31 17:33:07 +02:00
parent 496e801943
commit f44b2c8126
13 changed files with 1199 additions and 257 deletions
@@ -40,7 +40,10 @@ data class Veranstaltung(
// 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
// Dates
@Serializable(with = KotlinLocalDateSerializer::class)
@@ -153,7 +153,10 @@ class VeranstaltungRepositoryImpl : VeranstaltungRepository {
return Veranstaltung(
veranstaltungId = row[VeranstaltungTable.id].value,
name = row[VeranstaltungTable.name],
untertitel = row[VeranstaltungTable.untertitel],
beschreibung = row[VeranstaltungTable.beschreibung],
logoUrl = row[VeranstaltungTable.logoUrl],
sponsoren = row[VeranstaltungTable.sponsoren],
startDatum = row[VeranstaltungTable.startDatum],
endDatum = row[VeranstaltungTable.endDatum],
ort = row[VeranstaltungTable.ort],
@@ -173,7 +176,10 @@ class VeranstaltungRepositoryImpl : VeranstaltungRepository {
*/
private fun veranstaltungToStatement(statement: UpdateBuilder<*>, veranstaltung: Veranstaltung) {
statement[VeranstaltungTable.name] = veranstaltung.name
statement[VeranstaltungTable.untertitel] = veranstaltung.untertitel
statement[VeranstaltungTable.beschreibung] = veranstaltung.beschreibung
statement[VeranstaltungTable.logoUrl] = veranstaltung.logoUrl
statement[VeranstaltungTable.sponsoren] = veranstaltung.sponsoren
statement[VeranstaltungTable.startDatum] = veranstaltung.startDatum
statement[VeranstaltungTable.endDatum] = veranstaltung.endDatum
statement[VeranstaltungTable.ort] = veranstaltung.ort
@@ -16,7 +16,10 @@ object VeranstaltungTable : UUIDTable("veranstaltungen") {
// Basic Information
val name = varchar("name", 255)
val untertitel = varchar("untertitel", 255).nullable()
val beschreibung = text("beschreibung").nullable()
val logoUrl = varchar("logo_url", 255).nullable()
val sponsoren = text("sponsoren").nullable() // JSON array of Sponsor data
// Dates
val startDatum = date("start_datum")
@@ -67,6 +67,7 @@ data class DomVerein(
// Status & Verwaltung
var istAktiv: Boolean = true,
var logoUrl: String? = null,
var bemerkungen: String? = null,
var datenQuelle: DatenQuelleE = DatenQuelleE.IMPORT_ZNS,
@@ -34,6 +34,7 @@ class ExposedVereinRepository : VereinRepository {
oepsRegionNummer = row[VereinTable.oepsRegionNummer],
istVeranstalter = row[VereinTable.istVeranstalter],
istAktiv = row[VereinTable.istAktiv],
logoUrl = row[VereinTable.logoUrl],
bemerkungen = row[VereinTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[VereinTable.datenQuelle]),
createdAt = row[VereinTable.createdAt],
@@ -106,6 +107,7 @@ class ExposedVereinRepository : VereinRepository {
it[oepsRegionNummer] = verein.oepsRegionNummer
it[istVeranstalter] = verein.istVeranstalter
it[istAktiv] = verein.istAktiv
it[logoUrl] = verein.logoUrl
it[bemerkungen] = verein.bemerkungen
it[datenQuelle] = verein.datenQuelle.name
it[updatedAt] = verein.updatedAt
@@ -127,6 +129,7 @@ class ExposedVereinRepository : VereinRepository {
it[oepsRegionNummer] = verein.oepsRegionNummer
it[istVeranstalter] = verein.istVeranstalter
it[istAktiv] = verein.istAktiv
it[logoUrl] = verein.logoUrl
it[bemerkungen] = verein.bemerkungen
it[datenQuelle] = verein.datenQuelle.name
it[createdAt] = verein.createdAt
@@ -169,6 +172,7 @@ class ExposedVereinRepository : VereinRepository {
it[oepsRegionNummer] = toUpdate.oepsRegionNummer
it[istVeranstalter] = toUpdate.istVeranstalter
it[istAktiv] = toUpdate.istAktiv
it[logoUrl] = toUpdate.logoUrl
it[bemerkungen] = toUpdate.bemerkungen
it[datenQuelle] = toUpdate.datenQuelle.name
it[updatedAt] = toUpdate.updatedAt
@@ -0,0 +1,22 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Verknüpfungstabelle zwischen Verein und Reiter (Ansprechpersonen/Funktionäre).
*/
object VereinAnsprechpersonTable : Table("verein_ansprechperson") {
val vereinId = uuid("verein_id").references(VereinTable.id)
val reiterId = uuid("reiter_id").references(ReiterTable.id)
val rolle = varchar("rolle", 100).nullable() // z.B. "Obmann", "Meldestelle", "Sportwart"
val istHauptkontakt = bool("ist_hauptkontakt").default(false)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(vereinId, reiterId)
}
@@ -24,6 +24,7 @@ object VereinTable : Table("verein") {
val oepsRegionNummer = varchar("oeps_region_nummer", 10).nullable()
val istVeranstalter = bool("ist_veranstalter").default(false)
val istAktiv = bool("ist_aktiv").default(true)
val logoUrl = varchar("logo_url", 255).nullable()
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)