Compare commits
3 Commits
7bf89c58d3
...
9ff543dc14
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ff543dc14 | |||
| 92f22faf2f | |||
| 6b9177e818 |
|
|
@ -11,6 +11,8 @@ object TurnierTable : Table("turniere") {
|
||||||
val id = javaUUID("id").autoGenerate()
|
val id = javaUUID("id").autoGenerate()
|
||||||
val veranstaltungId = javaUUID("veranstaltung_id")
|
val veranstaltungId = javaUUID("veranstaltung_id")
|
||||||
val oepsTurniernummer = varchar("oeps_turniernummer", 50)
|
val oepsTurniernummer = varchar("oeps_turniernummer", 50)
|
||||||
|
val turnierNummer = varchar("turnier_nummer", 5)
|
||||||
|
val einschraenkungen = text("einschraenkungen")
|
||||||
|
|
||||||
// V3 Felder
|
// V3 Felder
|
||||||
val status = varchar("status", 16).default("DRAFT")
|
val status = varchar("status", 16).default("DRAFT")
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@
|
||||||
|
|
||||||
package at.mocode.entries.service.turniere
|
package at.mocode.entries.service.turniere
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.TeilnehmerKreisE
|
||||||
import kotlin.uuid.Uuid
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
data class Turnier(
|
data class Turnier(
|
||||||
val id: Uuid,
|
val id: Uuid,
|
||||||
val veranstaltungId: Uuid,
|
val veranstaltungId: Uuid,
|
||||||
val oepsTurniernummer: String,
|
val oepsTurniernummer: String,
|
||||||
|
val turnierNummer: String,
|
||||||
|
val einschraenkungen: List<TeilnehmerKreisE>,
|
||||||
val status: String,
|
val status: String,
|
||||||
val publishedAt: String?,
|
val publishedAt: String?,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
package at.mocode.entries.service.turniere
|
package at.mocode.entries.service.turniere
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.TeilnehmerKreisE
|
||||||
import at.mocode.entries.service.persistence.TurnierTable
|
import at.mocode.entries.service.persistence.TurnierTable
|
||||||
import at.mocode.entries.service.tenant.tenantTransaction
|
import at.mocode.entries.service.tenant.tenantTransaction
|
||||||
import org.jetbrains.exposed.v1.core.ResultRow
|
import org.jetbrains.exposed.v1.core.ResultRow
|
||||||
|
|
@ -21,6 +22,11 @@ class TurnierRepositoryImpl : TurnierRepository {
|
||||||
id = row[TurnierTable.id].toKotlinUuid(),
|
id = row[TurnierTable.id].toKotlinUuid(),
|
||||||
veranstaltungId = row[TurnierTable.veranstaltungId].toKotlinUuid(),
|
veranstaltungId = row[TurnierTable.veranstaltungId].toKotlinUuid(),
|
||||||
oepsTurniernummer = row[TurnierTable.oepsTurniernummer],
|
oepsTurniernummer = row[TurnierTable.oepsTurniernummer],
|
||||||
|
turnierNummer = row[TurnierTable.turnierNummer],
|
||||||
|
einschraenkungen = row[TurnierTable.einschraenkungen]
|
||||||
|
.split(',')
|
||||||
|
.mapNotNull { key -> key.trim().takeIf { it.isNotBlank() } }
|
||||||
|
.map(TeilnehmerKreisE::valueOf),
|
||||||
status = row[TurnierTable.status],
|
status = row[TurnierTable.status],
|
||||||
publishedAt = row[TurnierTable.publishedAt]?.toString(),
|
publishedAt = row[TurnierTable.publishedAt]?.toString(),
|
||||||
)
|
)
|
||||||
|
|
@ -31,6 +37,8 @@ class TurnierRepositoryImpl : TurnierRepository {
|
||||||
stmt[TurnierTable.id] = t.id.toJavaUuid()
|
stmt[TurnierTable.id] = t.id.toJavaUuid()
|
||||||
stmt[TurnierTable.veranstaltungId] = t.veranstaltungId.toJavaUuid()
|
stmt[TurnierTable.veranstaltungId] = t.veranstaltungId.toJavaUuid()
|
||||||
stmt[TurnierTable.oepsTurniernummer] = t.oepsTurniernummer
|
stmt[TurnierTable.oepsTurniernummer] = t.oepsTurniernummer
|
||||||
|
stmt[TurnierTable.turnierNummer] = t.turnierNummer
|
||||||
|
stmt[TurnierTable.einschraenkungen] = t.einschraenkungen.joinToString(",") { it.name }
|
||||||
stmt[TurnierTable.status] = t.status
|
stmt[TurnierTable.status] = t.status
|
||||||
stmt[TurnierTable.publishedAt] = null
|
stmt[TurnierTable.publishedAt] = null
|
||||||
stmt[TurnierTable.createdAt] = now
|
stmt[TurnierTable.createdAt] = now
|
||||||
|
|
@ -63,6 +71,8 @@ class TurnierRepositoryImpl : TurnierRepository {
|
||||||
val now = Clock.System.now()
|
val now = Clock.System.now()
|
||||||
TurnierTable.update({ TurnierTable.id eq t.id.toJavaUuid() }) { stmt ->
|
TurnierTable.update({ TurnierTable.id eq t.id.toJavaUuid() }) { stmt ->
|
||||||
stmt[TurnierTable.oepsTurniernummer] = t.oepsTurniernummer
|
stmt[TurnierTable.oepsTurniernummer] = t.oepsTurniernummer
|
||||||
|
stmt[TurnierTable.turnierNummer] = t.turnierNummer
|
||||||
|
stmt[TurnierTable.einschraenkungen] = t.einschraenkungen.joinToString(",") { it.name }
|
||||||
stmt[TurnierTable.status] = t.status
|
stmt[TurnierTable.status] = t.status
|
||||||
stmt[TurnierTable.updatedAt] = now
|
stmt[TurnierTable.updatedAt] = now
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
package at.mocode.entries.service.turniere
|
package at.mocode.entries.service.turniere
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.TeilnehmerKreisE
|
||||||
import at.mocode.entries.domain.repository.NennungRepository
|
import at.mocode.entries.domain.repository.NennungRepository
|
||||||
import at.mocode.entries.service.errors.LockedException
|
import at.mocode.entries.service.errors.LockedException
|
||||||
import at.mocode.entries.service.errors.ValidationException
|
import at.mocode.entries.service.errors.ValidationException
|
||||||
|
|
@ -12,11 +13,19 @@ class TurnierService(
|
||||||
private val nennungen: NennungRepository,
|
private val nennungen: NennungRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun create(veranstaltungId: Uuid, oepsNr: String, status: String? = null): Turnier {
|
suspend fun create(
|
||||||
|
veranstaltungId: Uuid,
|
||||||
|
oepsNr: String,
|
||||||
|
turnierNummer: String,
|
||||||
|
einschraenkungen: List<TeilnehmerKreisE>,
|
||||||
|
status: String? = null,
|
||||||
|
): Turnier {
|
||||||
val t = Turnier(
|
val t = Turnier(
|
||||||
id = Uuid.random(),
|
id = Uuid.random(),
|
||||||
veranstaltungId = veranstaltungId,
|
veranstaltungId = veranstaltungId,
|
||||||
oepsTurniernummer = oepsNr,
|
oepsTurniernummer = oepsNr,
|
||||||
|
turnierNummer = turnierNummer,
|
||||||
|
einschraenkungen = einschraenkungen,
|
||||||
status = status ?: "DRAFT",
|
status = status ?: "DRAFT",
|
||||||
publishedAt = null,
|
publishedAt = null,
|
||||||
)
|
)
|
||||||
|
|
@ -27,12 +36,24 @@ class TurnierService(
|
||||||
|
|
||||||
suspend fun list(status: String?, oepsNr: String?): List<Turnier> = repo.findAll(status, oepsNr)
|
suspend fun list(status: String?, oepsNr: String?): List<Turnier> = repo.findAll(status, oepsNr)
|
||||||
|
|
||||||
suspend fun update(id: Uuid, oepsNr: String): Turnier {
|
suspend fun update(id: Uuid, oepsNr: String, turnierNummer: String, einschraenkungen: List<TeilnehmerKreisE>): Turnier {
|
||||||
val current = get(id)
|
val current = get(id)
|
||||||
if (current.status == "PUBLISHED" && current.oepsTurniernummer != oepsNr) {
|
if (
|
||||||
|
current.status == "PUBLISHED" && (
|
||||||
|
current.oepsTurniernummer != oepsNr ||
|
||||||
|
current.turnierNummer != turnierNummer ||
|
||||||
|
current.einschraenkungen != einschraenkungen
|
||||||
|
)
|
||||||
|
) {
|
||||||
throw LockedException("Turnier ist PUBLISHED – strukturelle Felder nicht änderbar")
|
throw LockedException("Turnier ist PUBLISHED – strukturelle Felder nicht änderbar")
|
||||||
}
|
}
|
||||||
return repo.update(current.copy(oepsTurniernummer = oepsNr))
|
return repo.update(
|
||||||
|
current.copy(
|
||||||
|
oepsTurniernummer = oepsNr,
|
||||||
|
turnierNummer = turnierNummer,
|
||||||
|
einschraenkungen = einschraenkungen,
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun delete(id: Uuid): Boolean {
|
suspend fun delete(id: Uuid): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
package at.mocode.entries.service.turniere
|
package at.mocode.entries.service.turniere
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.TeilnehmerKreisE
|
||||||
import at.mocode.entries.service.persistence.VeranstaltungTable
|
import at.mocode.entries.service.persistence.VeranstaltungTable
|
||||||
import at.mocode.entries.service.tenant.tenantTransaction
|
import at.mocode.entries.service.tenant.tenantTransaction
|
||||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||||
|
|
@ -12,11 +13,15 @@ import kotlin.uuid.toKotlinUuid
|
||||||
|
|
||||||
data class CreateTurnierRequest(
|
data class CreateTurnierRequest(
|
||||||
val oepsTurniernummer: String,
|
val oepsTurniernummer: String,
|
||||||
|
val turnierNummer: String,
|
||||||
|
val einschraenkungen: List<TeilnehmerKreisE> = emptyList(),
|
||||||
val status: String? = null,
|
val status: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class UpdateTurnierRequest(
|
data class UpdateTurnierRequest(
|
||||||
val oepsTurniernummer: String,
|
val oepsTurniernummer: String,
|
||||||
|
val turnierNummer: String,
|
||||||
|
val einschraenkungen: List<TeilnehmerKreisE> = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class UpdateTurnierStatusRequest(
|
data class UpdateTurnierStatusRequest(
|
||||||
|
|
@ -34,7 +39,13 @@ class TurniereController(
|
||||||
suspend fun create(@RequestBody body: CreateTurnierRequest): Turnier {
|
suspend fun create(@RequestBody body: CreateTurnierRequest): Turnier {
|
||||||
// Veranstaltung pro Tenant auflösen: wir nehmen die einzige vorhandene ID aus dem Schema
|
// Veranstaltung pro Tenant auflösen: wir nehmen die einzige vorhandene ID aus dem Schema
|
||||||
val veranstaltungId = resolveVeranstaltungId()
|
val veranstaltungId = resolveVeranstaltungId()
|
||||||
return service.create(veranstaltungId, body.oepsTurniernummer, body.status)
|
return service.create(
|
||||||
|
veranstaltungId = veranstaltungId,
|
||||||
|
oepsNr = body.oepsTurniernummer,
|
||||||
|
turnierNummer = body.turnierNummer,
|
||||||
|
einschraenkungen = body.einschraenkungen,
|
||||||
|
status = body.status,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/turniere")
|
@GetMapping("/turniere")
|
||||||
|
|
@ -48,7 +59,12 @@ class TurniereController(
|
||||||
|
|
||||||
@PutMapping("/turniere/{id}")
|
@PutMapping("/turniere/{id}")
|
||||||
suspend fun update(@PathVariable id: String, @RequestBody body: UpdateTurnierRequest): Turnier =
|
suspend fun update(@PathVariable id: String, @RequestBody body: UpdateTurnierRequest): Turnier =
|
||||||
service.update(Uuid.parse(id), body.oepsTurniernummer)
|
service.update(
|
||||||
|
id = Uuid.parse(id),
|
||||||
|
oepsNr = body.oepsTurniernummer,
|
||||||
|
turnierNummer = body.turnierNummer,
|
||||||
|
einschraenkungen = body.einschraenkungen,
|
||||||
|
)
|
||||||
|
|
||||||
@DeleteMapping("/turniere/{id}")
|
@DeleteMapping("/turniere/{id}")
|
||||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
-- V4: Add turnier_nummer and einschraenkungen to turniere
|
||||||
|
-- Context: ÖTO § 3 Turniernummer + Teilnehmerkreis-Einschränkungen
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS turniere
|
||||||
|
ADD COLUMN IF NOT EXISTS turnier_nummer VARCHAR(5);
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS turniere
|
||||||
|
ADD COLUMN IF NOT EXISTS einschraenkungen TEXT;
|
||||||
|
|
||||||
|
UPDATE turniere
|
||||||
|
SET turnier_nummer = oeps_turniernummer
|
||||||
|
WHERE (turnier_nummer IS NULL OR turnier_nummer = '')
|
||||||
|
AND oeps_turniernummer ~ '^\d{5}$';
|
||||||
|
|
||||||
|
UPDATE turniere
|
||||||
|
SET einschraenkungen = ''
|
||||||
|
WHERE einschraenkungen IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE turniere
|
||||||
|
ALTER COLUMN turnier_nummer SET NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE turniere
|
||||||
|
ALTER COLUMN einschraenkungen SET NOT NULL;
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
package at.mocode.events.domain.model
|
package at.mocode.events.domain.model
|
||||||
|
|
||||||
import at.mocode.core.domain.model.SparteE
|
import at.mocode.core.domain.model.SparteE
|
||||||
|
import at.mocode.core.domain.model.TeilnehmerKreisE
|
||||||
import at.mocode.core.domain.model.TurnierkategorieE
|
import at.mocode.core.domain.model.TurnierkategorieE
|
||||||
import at.mocode.core.domain.model.TurnierStatusE
|
import at.mocode.core.domain.model.TurnierStatusE
|
||||||
import at.mocode.events.domain.validation.TurnierBewerbDescriptor
|
import at.mocode.events.domain.validation.TurnierBewerbDescriptor
|
||||||
|
|
@ -48,9 +49,11 @@ data class DomTurnier(
|
||||||
|
|
||||||
// Basis-Informationen
|
// Basis-Informationen
|
||||||
var name: String,
|
var name: String,
|
||||||
|
val turnierNummer: String,
|
||||||
var sparte: SparteE,
|
var sparte: SparteE,
|
||||||
var kategorie: TurnierkategorieE,
|
var kategorie: TurnierkategorieE,
|
||||||
var datum: LocalDate,
|
var datum: LocalDate,
|
||||||
|
var einschraenkungen: List<TeilnehmerKreisE> = emptyList(),
|
||||||
|
|
||||||
// Funktionäre
|
// Funktionäre
|
||||||
@Serializable(with = UuidSerializer::class)
|
@Serializable(with = UuidSerializer::class)
|
||||||
|
|
@ -98,6 +101,9 @@ data class DomTurnier(
|
||||||
if (name.isBlank()) {
|
if (name.isBlank()) {
|
||||||
warnings.add("Turniername ist erforderlich.")
|
warnings.add("Turniername ist erforderlich.")
|
||||||
}
|
}
|
||||||
|
if (!Regex("^\\d{5}$").matches(turnierNummer)) {
|
||||||
|
warnings.add("Turniernummer muss exakt 5 Ziffern enthalten (z.B. 26128).")
|
||||||
|
}
|
||||||
maxBewerbe?.let { max ->
|
maxBewerbe?.let { max ->
|
||||||
if (max <= 0) {
|
if (max <= 0) {
|
||||||
warnings.add("Maximale Bewerb-Anzahl muss positiv sein.")
|
warnings.add("Maximale Bewerb-Anzahl muss positiv sein.")
|
||||||
|
|
|
||||||
|
|
@ -441,6 +441,36 @@ enum class TurnierStatusE {
|
||||||
ABGESAGT
|
ABGESAGT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einschränkungen des Teilnehmerkreises gemäß ÖTO § 3 (Zusatz-Buchstaben bei Turnieren).
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
enum class TeilnehmerKreisE {
|
||||||
|
/** Jugend/Junioren/Junge Reiter (J) */
|
||||||
|
JUGEND_JUNIOREN_YR,
|
||||||
|
|
||||||
|
/** Ponys (P) */
|
||||||
|
PONYS,
|
||||||
|
|
||||||
|
/** Noriker (N) */
|
||||||
|
NORIKER,
|
||||||
|
|
||||||
|
/** Haflinger (H) */
|
||||||
|
HAFLINGER,
|
||||||
|
|
||||||
|
/** Ländliche Reiter (L) */
|
||||||
|
LAENDLICHE_REITER,
|
||||||
|
|
||||||
|
/** Vollblutaraber (A) */
|
||||||
|
VOLLBLUTARABER,
|
||||||
|
|
||||||
|
/** Kaltblut (K) */
|
||||||
|
KALTBLUT,
|
||||||
|
|
||||||
|
/** Damensattel (D) */
|
||||||
|
DAMENSATTEL
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status einer Ausschreibung gemäß ÖTO-Genehmigungsworkflow.
|
* Status einer Ausschreibung gemäß ÖTO-Genehmigungsworkflow.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
98
docs/01_Architecture/c4/domain_model.drawio
Normal file
98
docs/01_Architecture/c4/domain_model.drawio
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<mxfile host="Electron" modified="2026-04-07T12:00:00.000Z" agent="Lead Architect" version="21.0.0" type="device">
|
||||||
|
<diagram id="domain_model" name="Core Domain Model">
|
||||||
|
<mxGraphModel dx="1200" dy="1000" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
|
||||||
|
<!-- Entities -->
|
||||||
|
<mxCell id="ent_veranstaltung" value="<b>Veranstaltung</b><br><hr><i>Event Management Context</i><br>- Name<br>- Ort<br>- Zeitraum (z.B. Do-So)<br>- ZNS.zip (Stammdaten)<br><b>[Tenant Boundary]</b>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="120" y="80" width="200" height="120" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- NEU: Austragungsplatz und Artikel an Veranstaltung -->
|
||||||
|
<mxCell id="ent_austragungsplatz" value="<b>Austragungsplatz</b><br><hr><i>Event Management Context</i><br>- Name (z.B. Waldarena)<br>- Sparte (optional)<br>- Maße" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="360" y="80" width="160" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_artikel" value="<b>TurnierArtikel</b><br><hr><i>Billing Context</i><br>- Name (Heu, Ansage)<br>- Preis<br>- Automatisch (Nenngeld) vs. Manuell" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="560" y="80" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_kassa" value="<b>TeilnehmerKonto</b><br><hr><i>Billing Context</i><br>- Saldo<br>- Buchungen (Artikel/Gebühren)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="800" y="80" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_turnier" value="<b>Turnier</b><br><hr><i>Event Management Context</i><br>- 5-stellige Nr. (26128)<br>- Sparte &amp; Kategorie<br>- Nennschluss<br>- n2-xxxxx.dat (Nenndaten)<br>- TB (Turnierbeauftragter)<br>- Richterkollegium" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="120" y="280" width="200" height="140" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_bewerb" value="<b>Bewerb</b><br><hr><i>Competition Context</i><br>- Nummer / Name<br>- Richtverfahren / Klasse<br>- Austragungsplatz (Ref)<br>- Richter-Einsatz<br>- Zeitplan (Dauer, Beginn)<br>- Geldpreis (Ja/Nein)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="120" y="500" width="200" height="140" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_abteilung" value="<b>Abteilung</b><br><hr><i>Competition Context</i><br>- Trennungs-Kriterium<br> (z.B. R1 vs. R2)<br>- Startliste" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="120" y="720" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- NENNUNG -->
|
||||||
|
<mxCell id="ent_nennung" value="<b>Nennung (Entry)</b><br><hr><i>Registration Context</i><br>- Status (Offen, Bestätigt)<br>- Ist-Nachnennung (Flag)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="480" y="520" width="200" height="120" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_reiter" value="<b>Reiter</b><br><hr><i>Actor Context</i><br>- Name<br>- Lizenz" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="800" y="420" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ent_pferd" value="<b>Pferd</b><br><hr><i>Actor Context</i><br>- Name<br>- Kopfnummer (lokal)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="800" y="620" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- Connections (Relationships) -->
|
||||||
|
<mxCell id="edge_ver_tur" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_veranstaltung" target="ent_turnier">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- NEU: Platz/Artikel Verbindungen -->
|
||||||
|
<mxCell id="edge_ver_platz" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_veranstaltung" target="ent_austragungsplatz">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_ver_artikel" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.75;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_veranstaltung" target="ent_artikel">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_ver_konto" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_artikel" target="ent_kassa">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_tur_bew" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_turnier" target="ent_bewerb">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_bew_abt" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_bewerb" target="ent_abteilung">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- ABTEILUNG -> NENNUNG (The True Relationship) -->
|
||||||
|
<mxCell id="edge_abt_nen" value="1 : N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_abteilung" target="ent_nennung">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- BEWERB -> NENNUNG (Denormalisiert) -->
|
||||||
|
<mxCell id="edge_bew_nen" value="(Denormalisiert)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;dashed=1;strokeColor=#82b366;" edge="1" parent="1" source="ent_bewerb" target="ent_nennung">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_nen_rei" value="1 : 1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_nennung" target="ent_reiter">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_nen_pfe" value="1 : 1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.75;exitDx=0;exitDy=0;" edge="1" parent="1" source="ent_nennung" target="ent_pferd">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
73
docs/01_Architecture/c4/system_context.drawio
Normal file
73
docs/01_Architecture/c4/system_context.drawio
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
<mxfile host="Electron" modified="2026-04-07T12:00:00.000Z" agent="Lead Architect" version="21.0.0" type="device">
|
||||||
|
<diagram id="c4-level-2" name="C4 Level 2 - Bounded Contexts">
|
||||||
|
<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
|
||||||
|
<!-- Actor -->
|
||||||
|
<mxCell id="actor_user" value="Meldestelle-Mitarbeiter / Veranstalter" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="40" y="320" width="30" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- System Boundary -->
|
||||||
|
<mxCell id="system_boundary" value="Meldestelle (Compose Desktop KMP)" style="swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="160" y="80" width="760" height="640" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- SCS / Bounded Contexts -->
|
||||||
|
<mxCell id="ctx_event" value="<b>Event Management Context</b><br><br>Verwaltet die Rahmenbedingungen:<br>Veranstaltung, Turniere, Ausschreibung" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="40" y="60" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ctx_actor" value="<b>Actor Context</b><br><br>Stammdaten:<br>Reiter, Pferde, Funktionäre, Vereine" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="440" y="60" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ctx_registration" value="<b>Registration Context</b><br><br>Das Herzstück:<br>Nennungen, Nennungs-Transfers" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="240" y="220" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ctx_competition" value="<b>Competition Context</b><br><br>Der sportliche Ablauf:<br>Bewerbe, Abteilungen, Startlisten, Ergebnisse" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="440" y="380" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="ctx_billing" value="<b>Billing Context</b><br><br>Finanzen:<br>Kassa, Gebühren, Abrechnung" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="40" y="380" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- SaaS Admin Context -->
|
||||||
|
<mxCell id="ctx_saas_admin" value="<b>SaaS Admin Context / Masterdata</b><br><br>Mandanten-Verwaltung:<br>Kunden (Veranstalter), Lizenzen, Provisionierung" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="system_boundary">
|
||||||
|
<mxGeometry x="240" y="520" width="280" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- External Systems -->
|
||||||
|
<mxCell id="ext_zns" value="<b>ZNS (Zentrales Nennungs-System)</b><br><br>Externe Datenquelle für Nennungen (A-Satz, B-Satz) und Stammdaten." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;align=left;spacingTop=4;spacingLeft=8;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1000" y="300" width="200" height="100" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<!-- Connections (Relationships) -->
|
||||||
|
<mxCell id="edge_user_sys" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;" edge="1" parent="1" source="actor_user" target="system_boundary">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_zns_reg" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;dashed=1;" edge="1" parent="1" source="ext_zns" target="ctx_registration">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_zns_actor" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;dashed=1;" edge="1" parent="1" source="ext_zns" target="ctx_actor">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_reg_comp" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="system_boundary" source="ctx_registration" target="ctx_competition">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
<mxCell id="edge_saas_event" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="system_boundary" source="ctx_saas_admin" target="ctx_event">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
|
|
@ -46,13 +46,13 @@ Veranstalter (OEPS-Mitgliedsverein)
|
||||||
|
|
||||||
### A
|
### A
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
|
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
|
||||||
| **Abteilung** | **Kleinste ausführbare, atomare Einheit** für Nennungen, Startlisten, Ergebnisse und Auswertungen. Untereinheit eines Bewerbs mit eigenem Teilnehmerkreis (Lizenz, Pferdealter etc.). Erhält eine fortlaufende **Abteilungsnummer** (1, 2, ...) innerhalb des Bewerbs. Referenz auf Startliste/Ergebnisliste: `BW: 9 Abt: 1` bzw. `9-1`.
|
| **Abteilung** | **Kleinste ausführbare, atomare Einheit** für Nennungen, Startlisten, Ergebnisse und Auswertungen. Untereinheit eines Bewerbs mit eigenem Teilnehmerkreis (Lizenz, Pferdealter etc.). Erhält eine fortlaufende **Abteilungsnummer** (1, 2, ...) innerhalb des Bewerbs. Referenz auf Startliste/Ergebnisliste: `BW: 9 Abt: 1` bzw. `9-1`. | |
|
||||||
**Abteilungs-Typen:** `SEPARATE_SIEGEREHRUNG` (= eigene Platzierung, eigene Siegerehrung, separater Ergebnislauf) | `ORGANISATORISCH` (= organisatorische Teilung, z.B. zur Ablaufoptimierung; Platzierung/Preise werden gemeinsam mit anderen Abteilungen dieses Bewerbs geführt).
|
| **Abteilungs-Typen:** `SEPARATE_SIEGEREHRUNG` (= eigene Platzierung, eigene Siegerehrung, separater Ergebnislauf) | `ORGANISATORISCH` (= organisatorische Teilung, z.B. zur Ablaufoptimierung; Platzierung/Preise werden gemeinsam mit anderen Abteilungen dieses Bewerbs geführt). | |
|
||||||
Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen Startern eine Abteilung **verpflichtend** getrennt werden muss. Bei Überschreitung gibt das System eine **WARNUNG** (kein harter Fehler) – der TBA hat das letzte Wort (→ *Override-Event*). Vollständige Schwellenwert-Tabellen: → [`Abteilungs-Trennungs-Schwellenwerte.md`](../02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md) | ÖTO § 2 Abs. 7, § 39 |
|
| Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen Startern eine Abteilung **verpflichtend** getrennt werden muss. Bei Überschreitung gibt das System eine **WARNUNG** (kein harter Fehler) – der TBA hat das letzte Wort (→ *Override-Event*). Vollständige Schwellenwert-Tabellen: → [`Abteilungs-Trennungs-Schwellenwerte.md`](../02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md) | ÖTO § 2 Abs. 7, § 39 | |
|
||||||
| **Akteur** | Historischer Begriff (siehe → *Stammdaten*). Oberbegriff für alle Personen (Reiter, Richter, Funktionäre, Besitzer) und Organisationen (Vereine), die im System interagieren. | – |
|
| **Akteur** | Historischer Begriff (siehe → *Stammdaten*). Oberbegriff für alle Personen (Reiter, Richter, Funktionäre, Besitzer) und Organisationen (Vereine), die im System interagieren. | – |
|
||||||
| **Ausschreibung** | Das offizielle Dokument, das alle Bedingungen eines Turniers festlegt. Pflichtfelder gemäß ÖTO (A-Satz der ZNS-Schnittstelle). | ÖTO Ausschreibungs-Struktur |
|
| **Ausschreibung** | Das offizielle Dokument, das alle Bedingungen eines Turniers festlegt. Pflichtfelder gemäß ÖTO (A-Satz der ZNS-Schnittstelle). | ÖTO Ausschreibungs-Struktur |
|
||||||
|
|
||||||
### B
|
### B
|
||||||
|
|
||||||
|
|
@ -68,9 +68,9 @@ Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen S
|
||||||
|
|
||||||
### F
|
### F
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|----------------|------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||||
| **FEI-ID** | Eindeutige Identifikationsnummer der Internationalen Reiterlichen Vereinigung (FEI) für Reiter und Pferde. | FEI General Regulations |
|
| **FEI-ID** | Eindeutige Identifikationsnummer der Internationalen Reiterlichen Vereinigung (FEI) für Reiter und Pferde. | FEI General Regulations |
|
||||||
| **Funktionär** | Person mit einer definierten Rolle bei einem Turnier (Richter, Parcoursbauer, TBA, ...). Qualifikation wird gegen `RICHT01.DAT` geprüft. Im Code als Entität **`Funktionaer`** abgebildet. | ÖTO Funktionärs-Qualifikation |
|
| **Funktionär** | Person mit einer definierten Rolle bei einem Turnier (Richter, Parcoursbauer, TBA, ...). Qualifikation wird gegen `RICHT01.DAT` geprüft. Im Code als Entität **`Funktionaer`** abgebildet. | ÖTO Funktionärs-Qualifikation |
|
||||||
|
|
||||||
### G
|
### G
|
||||||
|
|
@ -85,19 +85,19 @@ Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen S
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
|
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
|
||||||
| **Kategorie** | Das Niveau eines Turniers und/oder seiner Bewerbe bzw. die Teilnahmeberechtigung daran. Nationale Kategorien: `C-NEU`, `C`, `B*`, `B`, `A`, `A*`. | ÖTO § 3 Abs. 4 |
|
| **Kategorie** | Das Niveau eines Turniers und/oder seiner Bewerbe bzw. die Teilnahmeberechtigung daran. Nationale Kategorien: `C-NEU`, `C`, `B*`, `B`, `A`, `A*`. | ÖTO § 3 Abs. 4 |
|
||||||
| **Bewerbsklasse** | Früher „Turnierklasse“. Schwierigkeitsgrad eines Bewerbs. Springen: E0 (60–90 cm), A (105–110 cm), L, M, S. Dressur: E, A, L, M, S (nach Aufgabe). Stammdaten in `bewerbs_klassen`. | ÖTO B-Teil |
|
| **Bewerbsklasse** | Früher „Turnierklasse“. Schwierigkeitsgrad eines Bewerbs. Springen: E0 (60–90 cm), A (105–110 cm), L, M, S. Dressur: E, A, L, M, S (nach Aufgabe). Stammdaten in `bewerbs_klassen`. | ÖTO B-Teil |
|
||||||
| **Kombination** | Zwei oder mehr Turniere (ggf. unterschiedlicher Sparten) die am selben Ort/Datum stattfinden. Jedes Turnier behält seine eigene Turniernummer. Genehmigung durch LFV/OEPS erforderlich. | ÖTO § 4 |
|
| **Kombination** | Zwei oder mehr Turniere (ggf. unterschiedlicher Sparten) die am selben Ort/Datum stattfinden. Jedes Turnier behält seine eigene Turniernummer. Genehmigung durch LFV/OEPS erforderlich. | ÖTO § 4 |
|
||||||
| **Kopfnummer** | *National (OEPS):* 4-stellige Registrierungsnummer eines Pferdes beim OEPS. **Nicht als eindeutige ID geeignet** – kann sich ändern. Dient zur schnellen Suche/Eingabe in der Meldestelle (Autocomplete), aber nicht als Datenbankschlüssel. *Turnier:* Temporäre Startnummer für das spezifische Turnier (ebenfalls nicht persistent). | – |
|
| **Kopfnummer** | *National (OEPS):* 4-stellige Registrierungsnummer eines Pferdes beim OEPS. **Nicht als eindeutige ID geeignet** – kann sich ändern. Dient zur schnellen Suche/Eingabe in der Meldestelle (Autocomplete), aber nicht als Datenbankschlüssel. *Turnier:* Temporäre Startnummer für das spezifische Turnier (ebenfalls nicht persistent). | – |
|
||||||
| **Konto** | Kontobasierte Abrechnung pro Zahler (nicht nur pro Reiter). Basis für das „Hansi-Szenario" (Guthaben bei Transfer). | Billing Context |
|
| **Konto** | Kontobasierte Abrechnung pro Zahler (nicht nur pro Reiter). Basis für das „Hansi-Szenario" (Guthaben bei Transfer). | Billing Context |
|
||||||
|
|
||||||
### L
|
### L
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|
|
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|
|
||||||
| **Lebensnummer** | 9-stellige (national) bzw. 15-stellige (international, UELN) Nummer, die ein Pferd bei der Geburt vom Zuchtverband erhält. Bei ausländischen Pferden im OEPS oft **generiert** → **nicht zur Suche geeignet**. Die ZNS-Daten zu Lebensnummern sind erfahrungsgemäß inkonsistent und widersprüchlich (z.B. Farbe `"Braun"` vs. `"Brauner"` für dasselbe Pferd). Primärer Schlüssel für den Datenaustausch bleibt die → *Satznummer*. | – |
|
| **Lebensnummer** | 9-stellige (national) bzw. 15-stellige (international, UELN) Nummer, die ein Pferd bei der Geburt vom Zuchtverband erhält. Bei ausländischen Pferden im OEPS oft **generiert** → **nicht zur Suche geeignet**. Die ZNS-Daten zu Lebensnummern sind erfahrungsgemäß inkonsistent und widersprüchlich (z.B. Farbe `"Braun"` vs. `"Brauner"` für dasselbe Pferd). Primärer Schlüssel für den Datenaustausch bleibt die → *Satznummer*. | – |
|
||||||
| **Lizenz (Reiterlizenz)** | Qualifikationsstufe eines Reiters (z.B. `R1`, `RD1`, `RD2`, `RS2`). Ein Reiter hat 0..1 Reiterlizenz. Stammdaten in `reiterlizenzen`, Referenz am Reiter `reit_lizenz_id`. | ÖTO Teilnahmeberechtigung |
|
| **Lizenz (Reiterlizenz)** | Qualifikationsstufe eines Reiters (z.B. `R1`, `RD1`, `RD2`, `RS2`). Ein Reiter hat 0..1 Reiterlizenz. Stammdaten in `reiterlizenzen`, Referenz am Reiter `reit_lizenz_id`. | ÖTO Teilnahmeberechtigung |
|
||||||
| **Fahr-Lizenz** | Lizenzkategorie für den Fahrsport (z.B. `F1`, `F2`). Ein Reiter hat 0..1 Fahr-Lizenz. Stammdaten in `fahr_lizenzen`, Referenz am Reiter `fahr_lizenz_id`. | ÖTO Teilnahmeberechtigung |
|
| **Fahr-Lizenz** | Lizenzkategorie für den Fahrsport (z.B. `F1`, `F2`). Ein Reiter hat 0..1 Fahr-Lizenz. Stammdaten in `fahr_lizenzen`, Referenz am Reiter `fahr_lizenz_id`. | ÖTO Teilnahmeberechtigung |
|
||||||
| **Startkarte** | Nachweis der Jahresgebühr. Ein Reiter hat 0..1 Startkarte. Stammdaten in `startkarten`, Referenz am Reiter `startkarte_id`. | ÖTO Teilnahmeberechtigung |
|
| **Startkarte** | Nachweis der Jahresgebühr. Ein Reiter hat 0..1 Startkarte. Stammdaten in `startkarten`, Referenz am Reiter `startkarte_id`. | ÖTO Teilnahmeberechtigung |
|
||||||
|
|
||||||
### M
|
### M
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen S
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|
|
|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|
|
||||||
| **Reiter** | Eine Person, die an einem Bewerb teilnimmt. Spezialisierung einer Person mit pferdesportlichen Attributen (Lizenz, Startkarte). Im Code als Entität **`Reiter`** abgebildet. Datenquelle primär `LIZENZ01.DAT`. | ÖTO § 2 Abs. 11 |
|
| **Reiter** | Eine Person, die an einem Bewerb teilnimmt. Spezialisierung einer Person mit pferdesportlichen Attributen (Lizenz, Startkarte). Im Code als Entität **`Reiter`** abgebildet. Datenquelle primär `LIZENZ01.DAT`. | ÖTO § 2 Abs. 11 |
|
||||||
| **Satznummer** | *Pferd:* 10-stellige, rein numerische ID (`0000123456`). **Primärer Schlüssel für den Datenaustausch.** *Reiter:* 6-stellige, rein numerische ID. | ZNS-Schnittstelle |
|
| **Satznummer** | *Pferd:* 10-stellige, rein numerische ID (`0000123456`). **Primärer Schlüssel für den Datenaustausch.** *Reiter:* 6-stellige, rein numerische ID. | ZNS-Schnittstelle |
|
||||||
| **Serie** | Synonym für → *Cup*. Übergeordneter Wettbewerb, der Ergebnisse aus Bewerben bei **mindestens zwei Turnieren** aggregiert. Besitzt ein **eigenes Reglement** (siehe Abschnitt 4). | ÖTO § 2 Abs. 8 |
|
| **Serie** | Synonym für → *Cup*. Übergeordneter Wettbewerb, der Ergebnisse aus Bewerben bei **mindestens zwei Turnieren** aggregiert. Besitzt ein **eigenes Reglement** (siehe Abschnitt 4). | ÖTO § 2 Abs. 8 |
|
||||||
| **Sparte** | Die unterschiedlichen Arten von Turnieren oder Bewerben (z.B. Dressur = CDN, Springen = CSN). Bestimmt das anzuwendende Richtverfahren und das Regelwerk. | ÖTO § 2 Abs. 9, § 3 Abs. 2 |
|
| **Sparte** | Die unterschiedlichen Arten von Turnieren oder Bewerben (z.B. Dressur = CDN, Springen = CSN). Bestimmt das anzuwendende Richtverfahren und das Regelwerk. | ÖTO § 2 Abs. 9, § 3 Abs. 2 |
|
||||||
|
|
@ -150,44 +150,45 @@ Die ÖTO definiert sparten- und klassenabhängige Schwellenwerte, ab wievielen S
|
||||||
|
|
||||||
### T
|
### T
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|
|
|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|
|
||||||
| **TBA** | Turnierbeauftragter. Hat bei Regelkonflikten immer das letzte Wort. Jede Überschreibung wird als → *Override-Event* gespeichert. | ÖTO § 24/§ 25 |
|
| **TBA** | Turnierbeauftragter. Hat bei Regelkonflikten immer das letzte Wort. Jede Überschreibung wird als → *Override-Event* gespeichert. | ÖTO § 24/§ 25 |
|
||||||
| **Tierwohl-Euro** | Gebühr, die **pro Start** anfällt (nicht pro Nennung!). | ÖTO Gebührenordnung |
|
| **Tierwohl-Euro** | Gebühr, die **pro Start** anfällt (nicht pro Nennung!). | ÖTO Gebührenordnung |
|
||||||
| **Turnier** | In unserer Software: Eine pferdesportliche Veranstaltung mit einer offiziellen **Ausschreibung** und einer vom OEPS/LFV vergebenen, eindeutigen **Turniernummer**. Entspricht ÖTO § 2 Abs. 2. Ist eine Spezialisierung von → *Veranstaltung*. | ÖTO § 2 Abs. 2, § 5, § 24 |
|
| **Turnier** | In unserer Software: Eine pferdesportliche Veranstaltung mit einer offiziellen **Ausschreibung** und einer vom OEPS/LFV vergebenen, eindeutigen **Turniernummer**. Entspricht ÖTO § 2 Abs. 2. Ist eine Spezialisierung von → *Veranstaltung*. | ÖTO § 2 Abs. 2, § 5, § 24 |
|
||||||
| **Turniernummer** | Vom OEPS vergebene, eindeutige Kennung eines Turniers (z.B. `25123`). Ohne diese Nummer darf keine offizielle Ausschreibung veröffentlicht werden. | ZNS A-Satz |
|
| **Turniernummer** | Offizielle, vom OEPS vergebene **5-stellige** Kennung eines Turniers (z.B. `26128`). Sie ist eindeutig und Voraussetzung für die offizielle Ausschreibung. | ÖTO § 3, ZNS A-Satz |
|
||||||
| **Turnierkategorie** | Siehe → *Kategorie*. | ÖTO § 3 Abs. 4 |
|
| **Teilnehmerkreis-Einschränkung** | Optionale Einschränkung des zulässigen Teilnehmerkreises eines Turniers gemäß ÖTO-Gliederung (§ 3), dargestellt über Zusatz-Buchstaben (z.B. `-H`, `-P`, `-J`). | ÖTO § 3 |
|
||||||
| **Turnierkassa** | Kassa auf Ebene des einzelnen → *Turniers*. Hält Belege, Tagesabschlüsse und Barbestände pro Turnier. Wird in der → *Veranstaltungs‑Kassa* konsolidiert. | Billing Context |
|
| **Turnierkategorie** | Siehe → *Kategorie*. | ÖTO § 3 Abs. 4 |
|
||||||
| **TeilnehmerKonto** | Konto eines Zahlers auf Ebene der → *Veranstaltung* (nicht nur eines Turniers). Aggregiert Saldo, Einzahlungen und Verrechnungen über alle → *Turniere* derselben Veranstaltung hinweg (Multi‑Turnier‑Aggregation). Ermöglicht, dass eine einzelne Zahlung mehrere Rechnungen in verschiedenen Turnieren derselben Veranstaltung ausgleicht. | Billing Context |
|
| **Turnierkassa** | Kassa auf Ebene des einzelnen → *Turniers*. Hält Belege, Tagesabschlüsse und Barbestände pro Turnier. Wird in der → *Veranstaltungs‑Kassa* konsolidiert. | Billing Context |
|
||||||
|
| **TeilnehmerKonto** | Konto eines Zahlers auf Ebene der → *Veranstaltung* (nicht nur eines Turniers). Aggregiert Saldo, Einzahlungen und Verrechnungen über alle → *Turniere* derselben Veranstaltung hinweg (Multi‑Turnier‑Aggregation). Ermöglicht, dass eine einzelne Zahlung mehrere Rechnungen in verschiedenen Turnieren derselben Veranstaltung ausgleicht. | Billing Context |
|
||||||
|
|
||||||
### V
|
### V
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
|
|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
|
||||||
| **Veranstaltung** | In unserer Software: Der Oberbegriff für jede Art von pferdesportlicher Veranstaltung, die von einem Verein durchgeführt wird. Erhält eine **intern vergebene ID**. Entspricht dem ÖTO-Oberbegriff „Pferdesportliche Veranstaltung" (§ 2 Abs. 1). Kann vom Typ Turnier, Reitertreffen, Sonderprüfung, PS&S oder Turnierartig sein. | ÖTO § 2 Abs. 1 |
|
| **Veranstaltung** | In unserer Software: Der Oberbegriff für jede Art von pferdesportlicher Veranstaltung, die von einem Verein durchgeführt wird. Erhält eine **intern vergebene ID**. Entspricht dem ÖTO-Oberbegriff „Pferdesportliche Veranstaltung" (§ 2 Abs. 1). Kann vom Typ Turnier, Reitertreffen, Sonderprüfung, PS&S oder Turnierartig sein. | ÖTO § 2 Abs. 1 |
|
||||||
| **Veranstalter** | OEPS-Mitgliedsverein (über LFV angeschlossen), der eine Veranstaltung ausrichtet. Besitzt eine **Vereinsnummer**. Im Code als Entität **`Verein`** abgebildet. | ÖTO § 2 Abs. 12 |
|
| **Veranstalter** | OEPS-Mitgliedsverein (über LFV angeschlossen), der eine Veranstaltung ausrichtet. Besitzt eine **Vereinsnummer**. Im Code als Entität **`Verein`** abgebildet. | ÖTO § 2 Abs. 12 |
|
||||||
| **Veranstaltungs‑Kassa** | Kassen- und Abrechnungsführer auf Ebene der → *Veranstaltung*. Konsolidiert alle Zahlungen, Belege und Rückgelder über mehrere → *Turniere* derselben Veranstaltung. Dient als zentrale Sammelkasse; kann Zahlvorgänge turnierübergreifend splitten und konsolidieren. | Billing Context |
|
| **Veranstaltungs‑Kassa** | Kassen- und Abrechnungsführer auf Ebene der → *Veranstaltung*. Konsolidiert alle Zahlungen, Belege und Rückgelder über mehrere → *Turniere* derselben Veranstaltung. Dient als zentrale Sammelkasse; kann Zahlvorgänge turnierübergreifend splitten und konsolidieren. | Billing Context |
|
||||||
|
|
||||||
### Z
|
### Z
|
||||||
|
|
||||||
| Begriff | Definition | ÖTO-Referenz |
|
| Begriff | Definition | ÖTO-Referenz |
|
||||||
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
|
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
|
||||||
| **Zahlvorgang** | Eine einzelne Zahlungstransaktion (Bar, Karte, Überweisung), die einen Betrag einem → *TeilnehmerKonto* gutschreibt und dabei **eine Zahlung auf mehrere Rechnungen/Belege** aufteilen kann – auch turnierübergreifend innerhalb derselben → *Veranstaltung*. | Billing Context |
|
| **Zahlvorgang** | Eine einzelne Zahlungstransaktion (Bar, Karte, Überweisung), die einen Betrag einem → *TeilnehmerKonto* gutschreibt und dabei **eine Zahlung auf mehrere Rechnungen/Belege** aufteilen kann – auch turnierübergreifend innerhalb derselben → *Veranstaltung*. | Billing Context |
|
||||||
| **ZNS** | Zentrales Nennsystem des OEPS. Datenaustausch-Format für Stammdaten (Reiter, Pferde) und Nennungen. Quelle der Wahrheit für Akteurs-Daten. | ZNS-Schnittstelle |
|
| **ZNS** | Zentrales Nennsystem des OEPS. Datenaustausch-Format für Stammdaten (Reiter, Pferde) und Nennungen. Quelle der Wahrheit für Akteurs-Daten. | ZNS-Schnittstelle |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Bounded Contexts & Zuordnung
|
## 3. Bounded Contexts & Zuordnung
|
||||||
|
|
||||||
| Begriff | Primärer Bounded Context |
|
| Begriff | Primärer Bounded Context |
|
||||||
|-------------------------------------------------------------|-------------------------------|
|
|-------------------------------------------------------------------|-------------------------------|
|
||||||
| Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` |
|
| Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` |
|
||||||
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
|
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
|
||||||
| Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-context` |
|
| Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-context` |
|
||||||
| Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `actor-context` |
|
| Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `actor-context` |
|
||||||
| Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` |
|
| Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` |
|
||||||
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
|
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
|
||||||
| Login, Rolle, Berechtigung | `identity-context` |
|
| Login, Rolle, Berechtigung | `identity-context` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
700
docs/temp/Chat-Verlauf-Gemini_2026-04-07.md
Normal file
700
docs/temp/Chat-Verlauf-Gemini_2026-04-07.md
Normal file
|
|
@ -0,0 +1,700 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
Chat-Verlauf mit Gemini
|
||||||
|
Datum: 7. April 2026
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Guten Tag!
|
||||||
|
Datum: 7. April 2026
|
||||||
|
Du bist jetzt ein Senior Softwareentwickler und bist Experte für OOP
|
||||||
|
|
||||||
|
Ich möchte, dass du dir einen Überblick verschaffst von meiner fachlichen Implementierung.
|
||||||
|
Meine starke vermutung liegt darin, dass wir ein großes grundsätzliches Problem bzw. Fehler im System haben.
|
||||||
|
|
||||||
|
Uns fehlt die Grundlegende Hirachrchie.
|
||||||
|
Quasi das große ganze Datenmodell, Klassendiagramm, wie auch immer wir dies korrekt bezeichnen wollen.
|
||||||
|
Die Aufklärung was wir Abbilden wollen und wie alles miteinander abhängt.
|
||||||
|
Jetzt haben wir Fetzen und inkonsistente Namenskonfektionen.
|
||||||
|
|
||||||
|
Mit deiner Hilfe will ich Ordnung und Struktur in das ganze geben.
|
||||||
|
|
||||||
|
Wir beginnen mit "Was wollen wir abbilden?"
|
||||||
|
|
||||||
|
Diese Software soll viele Veranstaltungen Managen.
|
||||||
|
Eine Veranstaltung ist zeitlich und örtlich begrenzt.
|
||||||
|
|
||||||
|
Und so weiter
|
||||||
|
|
||||||
|
Also kannst du mir dabei helfen wieder Ordung zu schaffen, in dem wir aus einem Abstrakteren Blickwinkel einen Überblick verschaffen?
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
Guten Tag. Ja, absolut. Es ist eine ausgezeichnete Idee, regelmäßig einen Schritt zurückzutreten und das große Ganze zu betrachten. Eine klare und konsistente Domänen-Sprache ist das Fundament für saubere Software-Architektur und verhindert genau die von Ihnen beschriebenen Probleme wie Inkonsistenzen und "Fetzen".
|
||||||
|
|
||||||
|
Ich habe mir einen ersten Überblick über das Projekt verschafft. Es existiert bereits eine beachtliche Menge an Struktur und Dokumentation, die uns als hervorragende Ausgangsbasis dient. Insbesondere die `MASTER_ROADMAP.md` und die darin erwähnten Bounded Contexts zeigen, dass bereits viel grundlegende konzeptionelle Arbeit geleistet wurde.
|
||||||
|
|
||||||
|
Lassen Sie uns genau da ansetzen, wo Sie es vorschlagen: **"Was wollen wir abbilden?"**
|
||||||
|
|
||||||
|
Ihre Definition ist der perfekte Startpunkt:
|
||||||
|
|
||||||
|
> Eine Veranstaltung ist zeitlich und örtlich begrenzt.
|
||||||
|
|
||||||
|
Basierend auf den Projektdokumenten, insbesondere der `Ubiquitous_Language.md`, lässt sich dieses Bild weiter schärfen. Das System unterscheidet fundamental zwischen:
|
||||||
|
|
||||||
|
1. Veranstaltung (Event): Der organisatorische Rahmen. Eine Veranstaltung kann über mehrere Tage gehen und mehrere Turniere umfassen. Sie hat einen Veranstalter, einen Ort und einen Zeitraum. (z.B. "Pferdesporttage Sommerlust 2026").
|
||||||
|
|
||||||
|
2. Turnier (Tournament): Ein sportlicher Teil innerhalb einer Veranstaltung. Ein Turnier ist an einen bestimmten Tag oder Zeitraum innerhalb der Veranstaltung gebunden und gehört zu einer Sparte (z.B. Dressur, Springen). Es ist das, was umgangssprachlich oft als "das Turnier am Samstag" bezeichnet wird.
|
||||||
|
|
||||||
|
Diese Trennung ist eine wichtige, im Projekt bereits verankerte Kernaussage (siehe ADR-0003).
|
||||||
|
|
||||||
|
Von hier aus entfaltet sich das restliche Modell:
|
||||||
|
|
||||||
|
- Ein Turnier besteht aus mehreren Bewerben (Competitions).
|
||||||
|
- Ein Bewerb ist die kleinste sportliche Einheit, für die man sich nennen kann (z.B. "Dressurprüfung Klasse L").
|
||||||
|
- Für einen Bewerb gibt es Nennungen (Entries) von Reitern (Riders) mit ihren Pferden (Horses).
|
||||||
|
- Abhängig von der Anzahl der Nennungen kann ein Bewerb in mehrere Abteilungen (Divisions) aufgeteilt werden, aus denen dann die Startlisten (Start Lists) generiert werden.
|
||||||
|
|
||||||
|
Dieses Grundgerüst bildet das Herz der Anwendung. Alle weiteren Konzepte wie `Funktionäre`, `Vereine`, `Abrechnung` (`billing-context`) und Regelwerke (`ÖTO/FEI Rulebook`) gruppieren sich um diesen Kern.
|
||||||
|
|
||||||
|
Mein Vorschlag für das weitere Vorgehen:
|
||||||
|
|
||||||
|
1. Wir validieren und verfeinern gemeinsam dieses high-level Domänenmodell.
|
||||||
|
2. Wir erstellen ein visuelles Diagramm (z.B. ein einfaches Klassendiagramm oder ein C4-Container-Diagramm), um die Beziehungen zwischen diesen Kernkonzepten zu visualisieren.
|
||||||
|
3. Wir gleichen die Namen im Code mit der definierten "Ubiquitous Language" ab und identifizieren Inkonsistenzen.
|
||||||
|
|
||||||
|
Sind Sie mit diesem Vorgehen einverstanden? Und spiegelt diese erste Zusammenfassung Ihr Verständnis der Domäne wider?
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Bezüglich C4-Diagramm, kannst du es in draw.io generieren?
|
||||||
|
Ich habe PlantUML und Mermaid ausprobiert, bin aber mit diesen nicht wirklich zufrieden. Jetzt will ich draw.io ausprobieren und hoffe das ich damit besser und leichter umgehen kann.
|
||||||
|
|
||||||
|
"Sind Sie mit diesem Vorgehen einverstanden? Und spiegelt diese erste Zusammenfassung Ihr Verständnis der Domäne wider?"
|
||||||
|
- Ja, das machen wir.
|
||||||
|
|
||||||
|
Um einen großen Überblick zu bekommen, glaube ich ist ein C4-Modell besser geeignet. Was sagst du?
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Sehr gute Entscheidung. draw.io (auch bekannt als diagrams.net) ist in der Tat oft wesentlich flexibler und visuell ansprechender für diese Art von Architektur- und Domänendiagrammen als reine Text-to-Diagramm Tools.
|
||||||
|
|
||||||
|
Ich habe direkt zwei .drawio Dateien für Sie generiert, um sowohl die Architektur als auch die fachliche Hierarchie greifbar zu machen:
|
||||||
|
|
||||||
|
1. `docs/01_Architecture/c4/system_context.drawio`
|
||||||
|
- **Inhalt:** Ein C4 Level 2 (Container/Context) Diagramm.
|
||||||
|
- **Zweck:** Es zeigt die 6 Bounded Contexts (Ihre "großen Bausteine"), wie sie in der Roadmap definiert sind. Es visualisiert, wer mit dem System interagiert (Mitarbeiter/ZNS) und welche Verantwortlichkeiten die einzelnen Bereiche haben (z.B. Registration Context vs. Competition Context).
|
||||||
|
|
||||||
|
2. `docs/01_Architecture/c4/domain_model.drawio`
|
||||||
|
- **Inhalt:** Ein Core Domain Model (Entity-Relationship).
|
||||||
|
- **Zweck:** Das ist die Antwort auf Ihre Frage nach der grundlegenden Hierarchie. Es zeigt den exakten Fluss: Veranstaltung (1) -> (N) Turnier (1) -> (N) Bewerb (1) -> (N) Abteilung. Gleichzeitig zeigt es, wie eine Nennung an einem Bewerb hängt und genau einen Reiter sowie ein Pferd verknüpft. Auch die Zuordnung zu den jeweiligen Bounded Contexts ist farblich und textlich markiert.
|
||||||
|
|
||||||
|
**So können Sie die Dateien öffnen:** Sie können diese Dateien direkt in der IDE öffnen, wenn Sie ein Draw.io Plugin installiert haben, oder sie einfach auf app.diagrams.net (bzw. in der Draw.io Desktop App) laden.
|
||||||
|
|
||||||
|
**Nächster Schritt:** Öffnen Sie bitte das `domain_model.drawio`. Ist diese grundlegende Kaskade (`Veranstaltung` -> `Turnier` -> `Bewerb` -> `Nennung`/`Abteilung`) exakt das, was wir im Code abbilden wollen und müssen? Wenn wir uns auf dieses Bild geeinigt haben, können wir anfangen, den Code (die "Fetzen") daraufhin zu untersuchen, wo die Benennungen oder Relationen aktuell noch abweichen.
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
draw.io ist gut, dass gefällt mir.
|
||||||
|
|
||||||
|
Ja lass uns über das Domain-Model diskutieren.
|
||||||
|
Ich brauche was über Veranstaltung um diese zu verwalten und zu managen.
|
||||||
|
In weiterer Ausbauphase will ich die Nutzung meiner Software vermieten und dies will steuern können.
|
||||||
|
Die Ausstellung der Nutzungs-Lizenz für Veranstaltung/Turnier etc.
|
||||||
|
Veranstaltungen/Turniere vorkonfigurieren für Kunden/Veranstalter, so das dieser einen Link zugeschickt bekommt mit der vorkonfigurierten Desktop-App und Aktivierungs-Schlüssel für seine Veranstaltung/Turnier.
|
||||||
|
Verstehst du was ich meine?
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Ja, ich verstehe Sie zu 100 %. Das ist ein klassisches **B2B SaaS (Software as a Service)** Modell. Sie wechseln damit von der reinen Software-Bereitstellung in die Rolle eines Plattform-Betreibers.
|
||||||
|
|
||||||
|
Das ist architektonisch ein sehr wichtiger Schritt, der perfekt mit unserer bestehenden "Tenant-Isolation" (ADR-0021) harmoniert. In unserer Architektur ist eine **Veranstaltung = ein Tenant (Mandant)**.
|
||||||
|
|
||||||
|
Ich habe das `domain_model.drawio` und das `system_context.drawio` entsprechend um den **SaaS Admin / Masterdata Context** erweitert.
|
||||||
|
|
||||||
|
Hier ist die logische Kette, die wir nun abbilden:
|
||||||
|
|
||||||
|
1. **Veranstalter (Kunde/Verein):** Das ist Ihr Vertragspartner. Im ÖTO-Sinn ist das ein "Verein" mit einer OEPS-Nummer. Dieser Veranstalter bekommt einen Zugang (Login) zu Ihrem zukünftigen SaaS-Admin-Portal.
|
||||||
|
|
||||||
|
2. **Nutzungslizenz:** Sie als Betreiber generieren eine Lizenz (einen Aktivierungs-Schlüssel) für diesen Veranstalter. Diese Lizenz regelt, was der Veranstalter darf (welcher Zeitraum, wie viele Veranstaltungen, welche Features).
|
||||||
|
|
||||||
|
3. **Veranstaltung (Der Tenant):** Der Veranstalter löst die Lizenz ein und erstellt eine Veranstaltung. Genau an diesem Punkt wird im Backend eine komplett isolierte Datenbank (ein Tenant-Schema) für diese Veranstaltung hochgefahren.
|
||||||
|
|
||||||
|
4. **Turnier -> Bewerb -> Nennung:** Ab hier läuft alles streng isoliert innerhalb der gekauften Veranstaltung.
|
||||||
|
|
||||||
|
**Der Workflow für Ihren Kunden sieht dann so aus:**
|
||||||
|
|
||||||
|
1. Sie (Admin) legen den Verein im System an und vergeben eine Lizenz.
|
||||||
|
|
||||||
|
2. Das System schickt dem Veranstalter eine E-Mail mit einem Download-Link für die Desktop-App und dem Aktivierungs-Schlüssel.
|
||||||
|
|
||||||
|
3. Der Veranstalter startet die App, gibt den Schlüssel ein, die App verbindet sich mit dem Backend und synchronisiert exakt die vorkonfigurierte `Veranstaltung` auf seinen Rechner.
|
||||||
|
|
||||||
|
4. Fertig. Er kann offline arbeiten.
|
||||||
|
|
||||||
|
Öffnen Sie bitte erneut das `docs/01_Architecture/c4/domain_model.drawio`. Sie sehen jetzt oben rot markiert den "SaaS Admin Context".
|
||||||
|
|
||||||
|
Spiegelt das Ihre Vision für das Vermietungsmodell wider? Wenn ja, haben wir jetzt das vollständige Bild: Vom kaufmännischen Rahmen (SaaS) bis hinunter zur einzelnen Nennung (Core Domain).
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Ja das sieht schlüssig aus. Aber diese "B2B SaaS (Software as a Service)" ist noch Zukunftsmusik.
|
||||||
|
Mein jetztiges Ziel sind die Neumarkt Turniere
|
||||||
|
docs/Neumarkt2026
|
||||||
|
In der Hitze des Gefechtes will ich es verhindern, dass wir das große Ziel nicht verbauen.
|
||||||
|
|
||||||
|
Zurück zum Domain-Modell.
|
||||||
|
SaaS ist Zukunftsmusik.
|
||||||
|
Nennung:
|
||||||
|
Ja, als Reiter nenne ich für ein Turnier und wähle mir Prüfungen/Bewerbe aus an denen ich mit meinem Pferd starten/teilnehmen will aus.
|
||||||
|
Das heißt eigentlich, das die Nennung dem Turnier gehört, oder nicht?
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Das ist eine hervorragende und extrem wichtige Frage! Das ist ein klassisches Dilemma in der Datenmodellierung von Pferdesport-Software und trifft genau den Kern von Domain-Driven Design (DDD).
|
||||||
|
|
||||||
|
Ihre Sichtweise aus der Praxis ist zu 100 % richtig: Ein Reiter sagt "Ich nenne für das Turnier in Neumarkt" und kreuzt auf seinem Formular (bzw. im ZNS) dann 3 verschiedene Bewerbe mit seinem Pferd an.
|
||||||
|
|
||||||
|
In unserer Code-Architektur (speziell in der Klasse DomNennung) betrachten wir die Nennung jedoch auf der kleinsten granularen Ebene: **Ein Reiter-Pferd-Paar für genau einen Bewerb (bzw. dessen Abteilung)**.
|
||||||
|
|
||||||
|
Warum haben wir das technisch so tief angesiedelt?
|
||||||
|
|
||||||
|
1. **Der sportliche Ablauf (Competition):** Wenn ein Bewerb (z.B. wegen hoher Starterzahlen) in zwei Abteilungen (R1 und R2) geteilt wird, muss die Nennung exakt einer Abteilung zugeordnet werden können, denn daraus entsteht die Startliste.
|
||||||
|
|
||||||
|
2. **Der Storno-Fall (Nennungs-Transfer):** Wenn ein Reiter für das Turnier 3 Bewerbe genannt hat und sich am Samstag verletzt, zieht er vielleicht nur die Nennung für den Sonntags-Bewerb zurück. Wir müssen Nennungen einzeln pro Bewerb verwalten, stornieren oder umbuchen können.
|
||||||
|
|
||||||
|
**Wie wir Ihre Sichtweise im Code trotzdem unterstützen:** Wenn Sie sich das `domain_model.drawio` ansehen, das ich gerade aktualisiert habe, sehen Sie Folgendes:
|
||||||
|
|
||||||
|
- Die **harte, fachliche Bindung** (durchgezogene Linie) besteht zwischen `Abteilung` und `Nennung`.
|
||||||
|
|
||||||
|
- **ABER:** Jede Nennung speichert zusätzlich ihre turnierId und bewerbId mit ab (gestrichelte Linien). Wir nennen das Denormalisierung.
|
||||||
|
|
||||||
|
**Das bedeutet:** Das System "weiß" bei jeder einzelnen Nennung immer sofort, zu welchem Turnier sie gehört. Wenn Sie als Veranstalter sagen: "Gib mir alle Nennungen für das gesamte Turnier", kann das Backend diese blitzschnell auswerfen, ohne sich mühsam durch alle Bewerbe und Abteilungen wühlen zu müssen.
|
||||||
|
|
||||||
|
**Zusammenfassend:** Fachlich (für den Reiter) ist es ein "Turnier-Warenkorb". Technisch (für Startlisten, Ergebnisse und das Regelwerk) ist es eine "Bewerbs- bzw. Abteilungs-Nennung".
|
||||||
|
|
||||||
|
Macht diese technische Granularität (jede Prüfung ist eine eigene Nennungs-Zeile in der Datenbank, die aber ihr Turnier kennt) für Sie Sinn, oder fehlt Ihnen im Tagesgeschäft zwingend ein "Nennungs-Kopfblatt" (eine Art Akte, die alle Einzelnennungen eines Reiters für ein Turnier zusammenfasst)?
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Das gefällt mir so, danke.
|
||||||
|
Okay, jedes Turnier beginnt mit der offizellen Turnier-Ausschreibung welche die vom Verband ausgestellte Tunier-Nr beinhaltet.
|
||||||
|
In dieser Ausschreibung sind alle relevanten Informationen für dieses Turnier enthalten.
|
||||||
|
Jetzt will ich das Turnier anlegen.
|
||||||
|
Was brauche ich dafür?
|
||||||
|
- Einen Veranstalter - habe ich diesen schon in meiner System-Verwaltung?
|
||||||
|
- Wenn ja, wähle ich diesen aus
|
||||||
|
- Wenn Nein, muss ich diesen erst einmal in mein System anlegen.
|
||||||
|
"Veranstalter anlegen"
|
||||||
|
|
||||||
|
Okay, ich habe jetzt den richtigen Veranstalter für das Turnier
|
||||||
|
Mit diesem Veranstalter möchte ich jetzt die Möglichkeit haben:
|
||||||
|
- Eine übergeordnete Veranstaltung anzulegen, weil an diesem WE beim selben Veranstalter 2 oder mehr "Pferdesportliche Veranstaltungen" stattfinden werden.
|
||||||
|
- Nur das Turnier mit/für diesem Veranstalter anlegen
|
||||||
|
|
||||||
|
Dann komme ich zum Konfigurieren des Turniers.
|
||||||
|
Das besprechen wir im nächsten Stint
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Perfekt zusammengefasst! Sie haben exakt den Lebenszyklus beschrieben, wie eine Meldestelle in der Realität arbeitet. Und das Beste daran: Genau diesen Flow haben wir in unserer Architektur (und auch schon in den Entwürfen für das neue Desktop-Frontend) vorbereitet.
|
||||||
|
|
||||||
|
Lassen Sie uns Ihren Flow kurz mit unserem Domain-Modell abgleichen, damit Sie sehen, dass wir auf demselben Nenner sind:
|
||||||
|
|
||||||
|
1. **"Einen Veranstalter - habe ich diesen schon in meiner System-Verwaltung?"**
|
||||||
|
|
||||||
|
- **Im System:** Das ist unser SaaS Admin / Masterdata Context. Wenn Sie einen neuen Veranstalter (Verein) anlegen, holt sich das System idealerweise die Stammdaten (Name, OEPS-Nr., Bundesland) aus den zentralen ZNS-Stammdaten.
|
||||||
|
|
||||||
|
- **Check:** ✔️ Passt perfekt. Der Veranstalter ist die absolute Basis.
|
||||||
|
|
||||||
|
2. **"Eine übergeordnete Veranstaltung anlegen (für 2 oder mehr Turniere) ODER nur das Turnier anlegen"** Hier zeigt sich die wahre Stärke unserer Trennung zwischen Veranstaltung und Turnier (die wir vorher im Diagramm festgezurrt haben):
|
||||||
|
|
||||||
|
- **Der Fall "Großes Wochenende" (2+ Turniere):** Sie legen eine `Veranstaltung` an (z.B. "Pferdesporttage Neumarkt"). Diese `Veranstaltung` ist unsere "Schublade" (Datenbank / Tenant). Innerhalb dieser einen Schublade legen Sie nun **Turnier A (z.B. Springen, Nr. 26128)** und **Turnier B (z.B. Dressur, Nr. 26129)** an. **Der Vorteil:** Reiter, die bei beiden Turnieren starten, müssen nur einmal angelegt/abgerechnet werden (Gemeinsame Kassa für die gesamte Veranstaltung).
|
||||||
|
|
||||||
|
- **Der Fall "Standard-Wochenende" (Nur 1 Turnier):** Sie sagen in der Oberfläche einfach "Neues Turnier anlegen". Unter der Haube macht das System folgendes für Sie automatisch: Es erstellt eine `Veranstaltung` (als Hülle/Datenbank) und legt exakt ein Turnier (mit der offiziellen Turnier-Nr.) hinein. Der Vorteil: Sie als Meldestelle müssen sich nicht mit künstlichen "Veranstaltungs-Namen" herumschlagen, wenn es sowieso nur ein einziges Turnier an dem Wochenende gibt. Das System nennt die Veranstaltung dann einfach wie das Turnier.
|
||||||
|
|
||||||
|
**Zusammenfassung für den nächsten Stint:** Ihr Flow ist absolut realitätstauglich und unsere Architektur stützt ihn zu 100%. Die Veranstaltung ist unsere unsichtbare "Datenbank-Klammer", in die Sie beliebig viele (oder eben nur ein einziges) Turniere aus der offiziellen Ausschreibung stecken können.
|
||||||
|
|
||||||
|
Geben Sie mir Bescheid, sobald Sie bereit sind. Dann stürzen wir uns im nächsten Stint auf die **Konfiguration des Turniers (Ausschreibung, Bewerbe, Nenngelder)**!
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Okay, "Turnier anlegen"
|
||||||
|
Ich habe die Ausschreibung.
|
||||||
|
Was brauche ich noch?
|
||||||
|
Jetzt brauche ich einen "Wizzard" der mich Inteligent durch diesen Prozess führt.
|
||||||
|
Bevor ich noch irgendeteas anderes machen kann, muss ich die Turnier-Nr. eingeben welche numerisch 5-stellig ist. Ich werde darauf hingewiesen, dass diese Turnier-Nr. nicht mehr zu verändern ist und werde gefragt, ob diese korrekt ist um sicher zu gehen.
|
||||||
|
Wenn diese Turnier-Nr. Validiert ist und bestätigt ist, wird eine Turnier-DB angelegt.
|
||||||
|
Dann muss ich das, für dieses Turnier gültige Reglement auswählen.
|
||||||
|
ÖTO für ein nationales- oder FEI für ein internationales-Turnier.
|
||||||
|
Dem entsprechend wird sich die weitere Eingabe-Maske in Zukunft auslegen.
|
||||||
|
Wir machen jetzt aber "nur" ÖTO nationale Turniere
|
||||||
|
Zur Erkärung, internationale Sprache der Reiterei ist französisch.
|
||||||
|
Dass heißt, mit diesen ersten Schritten haben wir folgendes festgehalten:
|
||||||
|
- "C" steht für "Concours" als wir die Turnier-Nr. bestätig haben, haben wir einen Wettbewerb eröffnet.
|
||||||
|
- "N" steht für "National" als wir das Regelment bestimmt haben wonach sich dieser Wettbewerb orientiert. "I" währe dann "International"
|
||||||
|
|
||||||
|
Als nächstes müssen wir diesen Wettbewerb/Turnier weiter eingränzen.
|
||||||
|
Sparte:
|
||||||
|
- Dressur
|
||||||
|
- Springen
|
||||||
|
- Vielseitigkeit
|
||||||
|
mehr wollen wir noch nicht machen. Ich muss jetzt das auswählen wofür dieses Turnier augeschrieben ist. Dies kann auch kombiniert werden.
|
||||||
|
Dem entsprechend haben wir bis jetzt folgendes für dieses Turnier festgehalten
|
||||||
|
- Dressur CDN
|
||||||
|
- Springen CSN
|
||||||
|
- Vielseitigkeit CCN
|
||||||
|
ÖTO § 3 "Gliederung der Turniere und Bewerbe"
|
||||||
|
|
||||||
|
Weiter müssen wir eingränzen:
|
||||||
|
--- ÖTO § 3 "Gliederung der Turniere und Bewerbe" ---
|
||||||
|
Einschränkungen des Teilnehmerkreises für Turniere oder
|
||||||
|
einzelne Bewerbe auf die folgenden Reiter oder Pferde durch
|
||||||
|
die Ausschreibung sind in der Bezeichnung durch Anhängen
|
||||||
|
des angegebenen Buchstaben zu berücksichtigen:
|
||||||
|
• JG, JN und/oder YR .......................................... J
|
||||||
|
• Ponys ................................................................ P
|
||||||
|
• Noriker ............................................................... N
|
||||||
|
• Haflinger ............................................................ H
|
||||||
|
• Ländliche Reiter auf Warmblutpferden ............. L
|
||||||
|
• Vollblutaraberbewerbe ...................................... A
|
||||||
|
• Kaltblut .............................................................. K
|
||||||
|
• Damensattel ...................................................... D
|
||||||
|
---
|
||||||
|
|
||||||
|
Weiter geht es mit
|
||||||
|
--- ÖTO § 3 "Gliederung der Turniere und Bewerbe" ---
|
||||||
|
Zur Gliederung nach den Anforderungen werden nationale Turniere in die Kategorien A*, A, B*, B, C und C-NEU eingeteilt. Der
|
||||||
|
Kurzbezeichnung gemäß Abs. 2 und 3 ist zur Kennzeichnung
|
||||||
|
entweder -A*, -A, -B*, -B, -C oder -C-NEU anzuhängen.
|
||||||
|
---
|
||||||
|
|
||||||
|
Wenn ich dies alles ordnungsgemäs nach Turnier-Ausschreibung aufgewählt habe, kommen wir zum anlegen der einzelnen Profungen/Bewerben.
|
||||||
|
nächster Stint
|
||||||
|
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Das ist eine exzellente und messerscharfe Analyse des ÖTO-Regelwerks § 3! Sie haben den Prozess exakt so heruntergebrochen, wie er fachlich stattfindet – vom generellen Rahmen (Concours) hin zur spezifischen Einschränkung.
|
||||||
|
|
||||||
|
Lassen Sie uns das direkt auf unseren Code (`DomTurnier`) mappen. Ich habe mir parallel unsere aktuelle Implementierung in `core/core-domain/.../Enums.kt` und `DomTurnier.kt` angesehen.
|
||||||
|
|
||||||
|
**Das haben wir bereits perfekt abgebildet:**
|
||||||
|
|
||||||
|
1. **Sparte:** Unser SparteE Enum hat bereits DRESSUR (CDN), SPRINGEN (CSN), VIELSEITIGKEIT (CCN) etc.
|
||||||
|
2. **Kategorie:** Unser TurnierkategorieE Enum hat bereits A_STERN, A, B_STERN, B, C, C_NEU.
|
||||||
|
|
||||||
|
**Das fehlt uns aktuell noch im Backend (und das ist ein super Fund von Ihnen!):**
|
||||||
|
|
||||||
|
1. Die offizielle Turnier-Nummer (5-stellig): Aktuell hat unser DomTurnier nur einen name und eine interne UUID. Die echte, vom OEPS vergebene 5-stellige Nummer (z.B. "26128") fehlt in der Entität! Die müssen wir zwingend aufnehmen (val turnierNummer: String).
|
||||||
|
2. Einschränkung des Teilnehmerkreises: Das von Ihnen zitierte Regelwerk (§ 3) mit den Kürzeln J (Jugend), P (Ponys), H (Haflinger) etc. haben wir als eigenes Konzept noch nicht abgebildet. Wir haben zwar Altersklassen (JG, JR etc.) für Reiter, aber noch kein Enum für die Turnier/Bewerbs-Einschränkung als Ganzes.
|
||||||
|
|
||||||
|
**Wie der "Turnier anlegen" Wizard im Frontend arbeiten wird (Ihr Flow):**
|
||||||
|
|
||||||
|
- **Schritt 1: Die Identität**. Eingabe der 5-stelligen Turnier-Nummer. Das System prüft: Ist das eine gültige Nummer? Existiert sie in dieser Veranstaltung schon? Wenn ja -> Lock (Unveränderbar).
|
||||||
|
|
||||||
|
- **Schritt 2: Das Reglement**. Auswahl: National (ÖTO). (International FEI blenden wir für den MVP aus oder setzen es fix auf ÖTO).
|
||||||
|
|
||||||
|
- **Schritt 3: Die Sportliche Ausprägung (Sparte & Kategorie)**. Auswahl Sparte (z.B. Springen) -> Daraus ergibt sich das Präfix CSN. Auswahl Kategorie (z.B. C-NEU) -> Ergibt das Suffix -C-NEU. Zusammenfassung auf dem Bildschirm: CSN-C-NEU.
|
||||||
|
|
||||||
|
- **Schritt 4: Einschränkungen (Teilnehmerkreis)**. Sind es Ländliche Reiter (L)? Oder Haflinger (H)? Wenn "H" ausgewählt wird, baut der Wizard den finalen Namen zusammen: CSN-C-NEU-H.
|
||||||
|
|
||||||
|
**Mein Vorschlag für den nächsten Schritt (Code-Anpassung):**
|
||||||
|
|
||||||
|
Bevor wir in die einzelnen Bewerbe abtauchen, sollten wir unser Fundament reparieren. Sind Sie einverstanden, wenn der Backend Developer beauftragt wird:
|
||||||
|
|
||||||
|
1. Die Eigenschaft `turnierNummer: String` (mit Validierung auf genau 5 Ziffern) in das `DomTurnier` einzubauen.
|
||||||
|
2. Ein neues Enum `TeilnehmerkreisE` (J, P, N, H, L, A, K, D) im Core-Modul anzulegen und als Liste `einschraenkungen: List<TeilnehmerkreisE>` dem `DomTurnier` hinzuzufügen?
|
||||||
|
|
||||||
|
Damit wäre der Kopf Ihres Turniers 100% ÖTO-konform, bevor wir den ersten Bewerb anlegen!
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Schreibe mir einen genauen Prompt für:
|
||||||
|
- 🏗️ [Lead Architect] & 👷 [Backend Developer]
|
||||||
|
Dann werde ich es gleich veranlassen.
|
||||||
|
|
||||||
|
---- Gemini ---
|
||||||
|
|
||||||
|
Hier ist der exakte, detaillierte Prompt, den Sie 1:1 kopieren und im nächsten Chat (oder direkt hier) abschicken können.
|
||||||
|
Er richtet sich genau an die beiden Agenten und enthält alle Dateipfade und fachlichen Regeln aus der ÖTO, damit der Code auf Anhieb sitzt:
|
||||||
|
|
||||||
|
```Markdown
|
||||||
|
# 🤖 Project Agents & Protocol: Turnier-Fundament (ÖTO § 3)
|
||||||
|
|
||||||
|
🏗️ **@Lead Architect** & 👷 **@Backend Developer**
|
||||||
|
Bitte führt gemeinsam das folgende Domain-Update für das Turnier-Fundament durch. Wir haben festgestellt, dass für den künftigen "Turnier anlegen"-Wizard wichtige ÖTO-Eigenschaften am `DomTurnier` fehlen.
|
||||||
|
|
||||||
|
**Kontext:** Gemäß ÖTO § 3 ("Gliederung der Turniere und Bewerbe") besitzt jedes Turnier eine offizielle 5-stellige Nummer (z.B. "26128") und optionale Einschränkungen des Teilnehmerkreises (Zusatz-Buchstaben wie -H, -P).
|
||||||
|
|
||||||
|
## 🏗️ Aufgaben für [Lead Architect]
|
||||||
|
* **Ubiquitous Language:** Ergänze in `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` die Begriffe **Turniernummer** (offizielle 5-stellige OEPS-Nummer) und **Teilnehmerkreis-Einschränkung** (ÖTO § 3 Gliederung).
|
||||||
|
|
||||||
|
## 👷 Aufgaben für [Backend Developer]
|
||||||
|
Führe die folgenden Code-Anpassungen durch und schreibe die Dateien sofort via Tool-Call:
|
||||||
|
|
||||||
|
**1. Neues Enum anlegen (`core/core-domain/src/commonMain/kotlin/at/mocode/core/domain/model/Enums.kt`):**
|
||||||
|
* Erstelle das Enum `TeilnehmerKreisE` mit den Werten gemäß ÖTO § 3:
|
||||||
|
* `JUGEND_JUNIOREN_YR` (Kürzel: J)
|
||||||
|
* `PONYS` (Kürzel: P)
|
||||||
|
* `NORIKER` (Kürzel: N)
|
||||||
|
* `HAFLINGER` (Kürzel: H)
|
||||||
|
* `LAENDLICHE_REITER` (Kürzel: L)
|
||||||
|
* `VOLLBLUTARABER` (Kürzel: A)
|
||||||
|
* `KALTBLUT` (Kürzel: K)
|
||||||
|
* `DAMENSATTEL` (Kürzel: D)
|
||||||
|
|
||||||
|
**2. Domänen-Modell erweitern (`backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/DomTurnier.kt`):**
|
||||||
|
* Füge `val turnierNummer: String` als Pflichtfeld hinzu.
|
||||||
|
* Füge `var einschraenkungen: List<TeilnehmerKreisE> = emptyList()` hinzu.
|
||||||
|
* Ergänze die Validierung (`validateFuerPlanung()`): Die `turnierNummer` muss exakt 5 Ziffern lang sein (Regex: `^\d{5}$`). Wenn nicht, gib eine Warnung zurück.
|
||||||
|
|
||||||
|
**3. Datenbank & Persistenz anpassen (`backend/services/events/events-infrastructure/...`):**
|
||||||
|
* Ergänze in der `TurnierTable.kt` die Spalten `turnierNummer` (varchar) und `einschraenkungen` (JSON-String oder Text).
|
||||||
|
* Passe das Mapping im `TurnierRepositoryImpl.kt` an (Insert, Update, rowToTurnier).
|
||||||
|
* Erstelle eine neue Flyway-Migration (z.B. `V3__add_turniernummer_and_einschraenkungen.sql`) im Ordner `backend/services/entries/entries-service/src/main/resources/db/tenant/` (Achtung: Turniere liegen im Tenant-Schema des Entries-Service!). *Hinweis: ALTER TABLE turniere ADD COLUMN ...*
|
||||||
|
|
||||||
|
**4. APIs & DTOs anpassen:**
|
||||||
|
* Aktualisiere die DTOs in `TurnierController` / `CreateTurnierUseCase` (falls vorhanden) um die beiden neuen Felder, damit das Frontend sie beim Anlegen übergeben kann.
|
||||||
|
|
||||||
|
Bitte führt diese Schritte nacheinander aus und bestätigt den erfolgreichen Build!
|
||||||
|
```
|
||||||
|
|
||||||
|
Tipp: Wenn Sie diesen Prompt abschicken, wird der Backend Developer die Datenbank, das Modell und die Schnittstelle exakt so vorbereiten, dass Ihr zukünftiges Frontend (der Wizard) einfach die Nummer "26128" und die Checkbox "Haflinger" an das Backend schicken kann und alles automatisch validiert wird.
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Okay, dass sollte erledigt sein.
|
||||||
|
===
|
||||||
|
### Summary
|
||||||
|
- 🏗️👷 Das Turnier-Fundament wurde gemäß ÖTO § 3 erweitert: `Turniernummer` (5-stellig) und optionale `Teilnehmerkreis-Einschränkungen` sind jetzt in Domain, Persistenz, Migration und API verfügbar.
|
||||||
|
- Der Projekt-Build läuft erfolgreich durch.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- `core/core-domain/.../Enums.kt`: neues Enum `TeilnehmerKreisE` mit allen geforderten Werten (`JUGEND_JUNIOREN_YR`, `PONYS`, `NORIKER`, `HAFLINGER`, `LAENDLICHE_REITER`, `VOLLBLUTARABER`, `KALTBLUT`, `DAMENSATTEL`).
|
||||||
|
- `events-domain/.../DomTurnier.kt`: Felder `turnierNummer` (Pflicht) und `einschraenkungen: List<TeilnehmerKreisE> = emptyList()` ergänzt; `validateFuerPlanung()` prüft `^\d{5}$` und liefert Warnung bei Verstoß.
|
||||||
|
- `entries-service` angepasst: `TurnierTable` (neue Spalten `turnier_nummer`, `einschraenkungen`), `TurnierRepository`/`TurnierRepositoryImpl` (Insert/Update/Row-Mapping inkl. Enum-Serialisierung als CSV-String), `TurnierService` + `TurniereController` Requests/Updates um beide Felder erweitert.
|
||||||
|
- Flyway-Migration ergänzt: `backend/services/entries/entries-service/src/main/resources/db/tenant/V4__add_turniernummer_and_einschraenkungen.sql` (`ALTER TABLE turniere ADD COLUMN ...`, Backfill, `NOT NULL`).
|
||||||
|
- Glossar aktualisiert: `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` um präzisierte `Turniernummer` (offiziell 5-stellig) und neuen Begriff `Teilnehmerkreis-Einschränkung`.
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
- Projektweiter Build erfolgreich: `build`-Tool meldet `Build completed successfully`.
|
||||||
|
- Zusätzlicher Check: `lint` auf `TurniereController.kt` ohne Fehler/Warnungen.
|
||||||
|
===
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Hervorragend! Das war ein extrem wichtiger Schritt. Das Fundament für das Turnier ist nun felsenfest und 100 % ÖTO-konform. Mit der 5-stelligen Turniernummer, der Sparte, der Kategorie und den Teilnehmerkreis-Einschränkungen weiß unser System jetzt exakt, welchen Rahmenbedingungen dieses Turnier unterliegt.
|
||||||
|
|
||||||
|
Damit können wir direkt in den nächsten Stint starten: Das Anlegen der einzelnen Prüfungen / Bewerbe.
|
||||||
|
|
||||||
|
Stellen wir uns wieder vor, Sie haben die offizielle Ausschreibung (den B-Satz) vor sich liegen. Wir befinden uns jetzt im Competition Context (Der sportliche Ablauf).
|
||||||
|
Wenn wir einen Bewerb anlegen, fordert unser Domain-Modell (DomBewerb) aktuell folgende Kerndaten:
|
||||||
|
|
||||||
|
1. Die Identifikation:
|
||||||
|
• Bewerbsnummer: Die laufende Nummer aus der Ausschreibung (z.B. "1", "2", "14a").
|
||||||
|
• Offizielle Bezeichnung: Der Texttext aus der Ausschreibung (z.B. "Standardspringprüfung", "Dressurreiterprüfung").
|
||||||
|
2. Das sportliche Niveau (abhängig von der Sparte):
|
||||||
|
• Klasse: (z.B. "E", "A", "L", "LM", "S").
|
||||||
|
• Höhe in cm: (Nur beim Springen relevant, z.B. "105", "130").
|
||||||
|
• Prüfungs-Typ (Richtverfahren): Wie wird gewertet? (z.B. STIL_SPRINGEN, FEHLER_ZEIT, DRESSUR_AUFGABE). Unser System braucht das, um später die richtige Ergebnisliste zu generieren.
|
||||||
|
3. Die Teilungs-Regel (Das Herzstück für die Meldestelle!): Das ist der Moment, in dem die Meldestelle entscheidet, wie das Starterfeld aufgeteilt wird (teilungsTyp in unserem Code):
|
||||||
|
• `KEINE_TEILUNG`: Alle reiten gegeneinander.
|
||||||
|
• `NACH_LIZENZ`: Trennung nach R1, R2/RS2, etc. (Sehr typisch!).
|
||||||
|
• `NACH_ALTER`: Trennung nach Jugend, Junioren, Allgemeine Klasse.
|
||||||
|
• `NACH_PFERD`: Trennung nach Noriker, Haflinger, Warmblut.
|
||||||
|
|
||||||
|
Wie der "Bewerb anlegen" Wizard arbeiten sollte:
|
||||||
|
|
||||||
|
1. Das System weiß bereits, dass es sich z.B. um ein CSN-C (Springen, National, Kat. C) handelt.
|
||||||
|
2. Wenn Sie nun einen Bewerb anlegen, warnt das System sofort, wenn Sie versuchen, ein S-Springen (140cm) anzulegen, da dies bei einem C-Turnier laut ÖTO verboten ist (diese Validierung haben wir bereits im TurnierValidation Service vorbereitet!).
|
||||||
|
3. Das System fragt Sie beim Anlegen: "Wie soll dieser Bewerb geteilt werden?" Wenn Sie NACH_LIZENZ wählen, generiert das Backend später automatisch die passenden Abteilungen (z.B. Abt. 1 für R1-Reiter, Abt. 2 für R2-Reiter).
|
||||||
|
|
||||||
|
Ihre Einschätzung aus der Praxis: Fehlt uns in dieser Liste noch ein essenzieller Parameter, den Sie zwingend aus der Ausschreibung abtippen müssen, wenn Sie einen neuen Bewerb in der Software anlegen?
|
||||||
|
Denken Sie z.B. an:
|
||||||
|
• Gibt es Nenngeld-Ausnahmen pro Bewerb?
|
||||||
|
• Müssen wir eintragen, an welchem Tag oder auf welchem Platz der Bewerb stattfindet?
|
||||||
|
• Brauchen wir ein Flag für "Qualifikation für Meisterschaft XY"?
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Bring mich nocht aus dem Konzept in dem du mir schon so viele Sachen vorlegst.
|
||||||
|
Darum geht es hier ja, um's "Querdenken"
|
||||||
|
|
||||||
|
Bevor wir noch die Prüfungen anlegen, brauchen wir noch
|
||||||
|
- Richter und evtl. Parcoursbauer/Assistenten, Steward, usw.
|
||||||
|
Auf jedem Fall Richter und einer davon bekommt die ehrenvolle Aufgabe als Turnierbeauftragter Richter zu sein, kurz "TB".
|
||||||
|
Dieser ist für dieses Turnier die offizielle Vertretung vom OEPS.
|
||||||
|
|
||||||
|
Dann brauchen wir zumindest einen Austragungsplatz den ich evtl. benennen kann, wie in Stadl-Paura üblich, dass die eizelnen Austragungs-Plätze ihre eigenen Namen haben. Zum Beispiel "Waldarena" oder "Paradeplatz". Das ist ganz pratisch, dann weis sofort ein jeder welcher Platz gemeint ist.
|
||||||
|
Diesen Plätzen könnte man dann auch noch einschränken wofür dieser gedacht ist, für Dressur oder Springen, dann kann es beim Prüfungs-anlegen keine Missverständnisse geben.
|
||||||
|
Angenommen "Wald-Arena" ist für Springen vorgesehen, dann kann ich keinen Dressur-Bewerb/Prüfung auf diesem austragen. Nur so eine Idee.
|
||||||
|
|
||||||
|
Dann sollte ich eigentlich alle Eckdaten zum anlegen der Prüfungen/Bewerbe haben.
|
||||||
|
|
||||||
|
Preisliste bzw. Artikel-Liste dürfen wir nicht vergessen. Diese beinhaltet natürlich laut ÖTO Nenngeld, Startgeld etc. mit den Standard-Werten laut ÖTO-Gebührenordnung plus Artikel die der Veranstalter am Turnier verkaufen kann.
|
||||||
|
Wie Zum Beispiel "Ansage", der Veranstalter stellt als zusätzliches Service einen Ansager zur Verfügung der die Dressur-Aufgabe laut und deutlich dem Starter während der Prüfung ansagst. Viele Veranstalter hätten gerne eine kleine Entschädigung, quasi als Trinkgeld für den Ansager € 2,- pro Ansage.
|
||||||
|
Was häufig am Turnier verkauft wird ist Heu, Späne (Holzspäne zum einstreuen in der Turnier-Box), Tages-Boxen usw.
|
||||||
|
|
||||||
|
Okay, aber jetzt sollten wir alle nötigen Eckdaten haben um die Bewerbe anlegen zu können, oder fällt dir noch was ein?
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Entschuldigung, Sie haben völlig recht! Ich bin in der Euphorie einen Schritt zu weit nach vorne gesprungen. Bleiben wir exakt in Ihrem Rhythmus und bei Ihrem Praxis-Blick ("Querdenken"). Das ist genau der Input, den eine Software braucht, um am Ende wirklich bedienbar zu sein.
|
||||||
|
|
||||||
|
Ihre Reihenfolge ist absolut logisch. Bevor wir überhaupt wissen, was geritten wird (Bewerbe), müssen wir festlegen, wer aufpasst (Funktionäre), wo geritten wird (Plätze) und was es kostet (Preisliste).
|
||||||
|
|
||||||
|
Lassen Sie uns Ihre Punkte architektonisch einordnen:
|
||||||
|
|
||||||
|
1. Funktionäre (Richter, Parcoursbauer, Stewards)
|
||||||
|
• Der TB (Turnierbeauftragte): Absolut kritisch. Er ist der "Chef" und Repräsentant des OEPS. In unserem aktuellen DomTurnier-Entwurf hieß das Feld bisher richterObmannId. Ich nehme sofort mit: Wir benennen das in der UI und im Glossar ganz klar als Turnierbeauftragter (TB).
|
||||||
|
• Dazu kommen das restliche Richterkollegium, Parcoursbauer (beim Springen/Vielseitigkeit) und Stewards.
|
||||||
|
|
||||||
|
2. Austragungsplätze (Die "Waldarena")
|
||||||
|
• Ihre Idee, die Plätze auf eine Sparte (Dressur oder Springen) einzuschränken, ist genial! Das ist genau die Art von "Poka-Yoke" (Fehlervermeidung), die eine gute Software ausmacht. Wenn die Meldestelle um 22 Uhr abends den Zeitplan für den nächsten Tag baut, darf das System gar nicht erst erlauben, eine L-Dressur in die "Waldarena" (Springplatz) zu ziehen.
|
||||||
|
• Das bedeutet: Wir brauchen ein kleines Modell Austragungsplatz (Name: "Waldarena", Erlaubte Sparte: "SPRINGEN").
|
||||||
|
|
||||||
|
3. Preisliste / Zusatzartikel
|
||||||
|
• Auch das ist aus der Praxis gegriffen. Neben den streng regulierten ÖTO-Gebühren (Nenngeld, Startgeld) verkauft der Veranstalter Dienstleistungen und Artikel.
|
||||||
|
• Heu, Späne, Boxen und die "Ansage" (super Beispiel für ein Service-Feature!) müssen als TurnierArtikel in der Preisliste des Turniers angelegt werden können, damit die Reiter das direkt bei der Anmeldung (oder später vor Ort) auf ihre Rechnung ("Teilnehmerkonto") buchen können.
|
||||||
|
|
||||||
|
|
||||||
|
Zu Ihrer Frage: "Fällt dir noch was ein?"
|
||||||
|
|
||||||
|
Wenn wir diese Basis haben (Nummer, Reglement, Funktionäre, Plätze, Preisliste), haben wir 95 % des Fundaments gegossen. Aus meiner Architekten-Brille fehlen eigentlich nur noch zwei organisatorische Daten:
|
||||||
|
|
||||||
|
1. Der Nennschluss (Datum & Uhrzeit): Wir müssen dem System sagen, bis wann die Reiter regulär nennen dürfen. Jede Nennung, die nach dieser Minute reinkommt, bekommt automatisch vom System das Flag istNachnennung = true und die Software bucht automatisch die Nachnenngebühr auf die Rechnung (außer der Veranstalter erlässt sie manuell).
|
||||||
|
2. Geldpreis-Auszahlung (Ja/Nein): Zahlt das Turnier Preisgelder aus? (Viele kleine C-NEU Turniere machen das z.B. nur mit Sachpreisen). Das ist wichtig für das Startgeld-Limit laut ÖTO.
|
||||||
|
|
||||||
|
Fazit: Ihr "Vor-Bewerbs-Flow" (Funktionäre -> Plätze -> Artikel -> Nennschluss) ist wasserdicht. Sind Sie einverstanden, dass wir diese vier Säulen als abgeschlossen betrachten? Dann hätten wir das perfekte Fundament, um im nächsten Stint endlich die Bewerbe (Prüfungen) darauf aufzubauen!
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
"2. Austragungsplätze (Die "Waldarena")" - Ja, aber optional, wenn keine Auswahl getroffen wurde könnte ich troztdem Dressur und Springen auf einem Platz durchführen lassen.
|
||||||
|
|
||||||
|
"Der Nennschluss (Datum & Uhrzeit)"
|
||||||
|
- Du hast Recht. Meine Idee/Vision von unserem Nenn-System ist ja, dass wenn das Turnier inkl. seiner Prüfungen/Bewerbe eingerichtet ist, unser System
|
||||||
|
- Diese Veranstaltung und dessen Turniere auf unserer Web-Seite prässentiert werden und bei der Präsentation des Turniers sind Buttons, für die Ausschreibung, damit Interessierte sich die offizelle Ausschreibung ansehen können via PDF zum Beispiel, ein Button Nennen der zu einem Web-Formular leitet mit diesem man sich für dieses Turnier einfach nennen kann, diese Nennung wird validiert und anschließend an unser System geschickt. Das heißt für unser System, jedes Turnier hat einen Post-Eingang indem die Nennungen landen und darauf warten weiter bearbeitet zu werden. Warum so? Weil wir Datenschutzkonform bleiben müssen und um den jenigen die Möglichkeit zum nennen zu geben welche noch nicht in den ZNS-Daten vorkommen. Beispiel hierfür sind Lizenzfreie Teilnehmer, diese sind nicht in LIZENZ01.dat enthalten und Pferde die nicht Turnierpferderegistriet sind kommen auch nicht in PFERDE01.dat vor. An Turnieren wie C-NEU gibt es viele kleine Bewerbe an denen man ohne Reiterlizenz und ohne Turnierpferderegistrierung teilnehmen darf.
|
||||||
|
|
||||||
|
Ja und dieses Nenn-Formular soll sich automatisch aus unserem System generieren.
|
||||||
|
Dieser Button "Nennen" der zu diesem Formular führt, wird sich zum Nennschluß automatisch entfernen bzw. bei mehrtägigen Turnieren wird der jeweilige Turniertag ausgeblendet. Meistens ist Nennschluß bis 19 Uhr des Vortages.
|
||||||
|
|
||||||
|
"Geldpreis-Auszahlung (Ja/Nein)"
|
||||||
|
Darauf habe ich nicht vergessen, diese Einstellung will ich beim konfigurieren des jeweiligen Bewerb/Abteilung durchführen und sobald das Ergebnis dieser Prüfung/Bewerb/Abteilung bestätigt ist, wird an die Glücklichen das Preisgeld verbucht.
|
||||||
|
|
||||||
|
Ja, wo geben wir den "Nennschluß" jetzt am besten hin?
|
||||||
|
Zu den Turnier-Stammdaten?
|
||||||
|
Aja, was wir vergessen hatten nachdem wir
|
||||||
|
- Turnier-Nr.
|
||||||
|
- Reglement
|
||||||
|
usw. eingegeben haben fehlt uns noch ob unser Turnier über das ZNS Nennungen vom Verband bekommt oder nicht, das ist die n2-xxxxx.dat die wir vom Verband oder vom Veranstalter erhalten.
|
||||||
|
Verlangt der Veranstalter Nachnenn-Gebühr oder nicht?
|
||||||
|
Führt dieses Turnier eine Nenntausch-Bösere und verlangt der Veranstalter dafür eine Gebühr oder nicht?
|
||||||
|
Datum von bis
|
||||||
|
Logo für das Turnier
|
||||||
|
Slogan für das Turnier
|
||||||
|
Hier bei den Turnier-Stammdaten sollten wir auch die ZNS.zip (unser ZNS-Importer) laden. Pflicht! Denn für die Nennungen, Richter usw. brauchen wir die Daten.
|
||||||
|
|
||||||
|
Hier eine Frage, was ist besser?
|
||||||
|
Wir laden die ZNS-Daten eine Etage höher bei Veranstaltung und jedes Turnier dieser Veranstaltung kann darauf zugreifen, oder wir laden die Daten auf Turnier-Ebene?
|
||||||
|
Die n2-xxxxx.dat ist klar auf Turnier-Ebene, denn diese Daten gehen die anderen Turniere nichts an.
|
||||||
|
Zum archivieren brauchen wir nur die Daten der tatsächlichen Teilnehmer Reiter, Pferde usw.
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Das ist echtes "Querdenken" aus der Schützengraben-Perspektive der Meldestelle! Genau diese Unterscheidungen zwischen Verbands-Theorie und Meldestellen-Praxis retten uns später den Hals.
|
||||||
|
|
||||||
|
Lassen Sie uns Ihre Fragen und Anforderungen Punkt für Punkt durchgehen und entscheiden, wo wir sie architektonisch verankern:
|
||||||
|
|
||||||
|
## 1. ZNS.zip (Stammdaten) vs. n2-xxxxx.dat (Nenndaten)
|
||||||
|
|
||||||
|
Hier haben Sie den Nagel auf den Kopf getroffen. Wir müssen das strikt trennen:
|
||||||
|
|
||||||
|
• Die ZNS.zip (Stammdaten): Beinhaltet Reiter, Pferde, Vereine und Richter. Diese Daten sind global bzw. für die gesamte Veranstaltung gültig. Wenn Sie an einem Wochenende ein Spring- und ein Dressurturnier haben, reiten dieselben Leute mit denselben Pferden. 👉 Architektur-Entscheidung: Die ZNS.zip wird auf Veranstaltungs-Ebene (oder sogar global im System) hochgeladen und aktualisiert unsere Masterdata-Datenbank.
|
||||||
|
• Die n2-xxxxx.dat (Nenndaten): Das xxxxx steht für die 5-stellige Turniernummer (z.B. n2-26128.dat). Diese Datei gehört exakt zu einem Turnier. 👉 Architektur-Entscheidung: Der Upload-Button für diese Datei kommt in die Turnier-Konfiguration.
|
||||||
|
|
||||||
|
## 2. Der "Nennschluss" – Wohin damit?
|
||||||
|
|
||||||
|
In der OEPS-Welt gibt es zwei Begriffe, die oft verwechselt werden:
|
||||||
|
|
||||||
|
• Nennschluss (z.B. 2 Wochen vor dem Turnier): Bis hierhin kann man über das ZNS-Webportal nennen. Danach generiert der OEPS die n2-xxxxx.dat. Dieser Nennschluss gehört in die Ausschreibung (also an das Turnier bzw. die Veranstaltung gekoppelt).
|
||||||
|
• Meldeschluss (z.B. 19:00 Uhr des Vortages): Das ist die Deadline für die Bestätigung der Startbereitschaft vor Ort.
|
||||||
|
• Zu Ihrer Vision des Web-Formulars (Datenschutzkonform, lizenzfrei, Nachnennungen): Das ist genial! Wir binden das an unser System an. Das Formular schließt automatisch, wenn der Nennschluss (aus den Turnier-Stammdaten) erreicht ist, oder blendet abgelaufene Tage aus. 👉 Architektur-Entscheidung: Der Nennschluss wandert (bzw. bleibt) in den Turnier-Stammdaten (bzw. in der daran hängenden DomAusschreibung).
|
||||||
|
|
||||||
|
## 3. Austragungsplätze ("Waldarena", "Paradeplatz")
|
||||||
|
|
||||||
|
Ihre Idee, die Plätze auf Sparten einzuschränken, ist ein perfektes Feature für die Fehlervermeidung.
|
||||||
|
|
||||||
|
• 👉 Architektur-Entscheidung: Die Plätze ("Infrastruktur") gehören physisch zur Veranstaltung (dem Gelände). In der Veranstaltung legen wir eine Liste von Plätzen an (Name: "Waldarena", Maße: "20x60m", Sparte: "SPRINGEN").
|
||||||
|
• Wenn Sie später einen Bewerb anlegen, bietet das Dropdown-Menü nur noch die Plätze an, die zur Sparte des Bewerbs passen.
|
||||||
|
|
||||||
|
## 4. Preisliste / Artikel ("Ansage", "Heu", "Späne")
|
||||||
|
|
||||||
|
Das ist der Kern unseres billing-context (Abrechnung). Wir trennen zwischen automatischen und manuellen Artikeln:
|
||||||
|
|
||||||
|
• Automatisch (ÖTO): Nenngeld (pro Pferd) und Startgeld (pro Bewerb). Das System weiß anhand des Regelwerks, was berechnet werden muss.
|
||||||
|
• Manuell (Veranstalter-Artikel): Wir brauchen ein Modell TurnierArtikel (Name, Preis, Steuersatz). Hier legt der Veranstalter seine "Ansage (€ 2,-)", "Heu (€ 10,-)", "Tagesbox" an.
|
||||||
|
• 👉 Architektur-Entscheidung: Diese Preisliste wird pro Veranstaltung gepflegt (da die Boxen und das Heu für das ganze Wochenende gelten), kann aber den Nennungen flexibel hinzugefügt werden.
|
||||||
|
|
||||||
|
## 5. Geldpreis-Auszahlung (Ja/Nein)
|
||||||
|
|
||||||
|
Völlig richtig, das ist eine Einstellung pro Bewerb (oder Abteilung). Das platzieren wir exakt dort im Wizard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Zusammenfassung für den "Prüfungen anlegen" Stint:
|
||||||
|
Wir haben jetzt das absolute Profi-Setup für das Backend definiert:
|
||||||
|
|
||||||
|
1. Veranstaltung (Die Klammer): Enthält die Plätze ("Waldarena") und die Preisliste ("Heu", "Ansage"). Hier wird die ZNS.zip (Stammdaten) hochgeladen.
|
||||||
|
2. Turnier (Das Sport-Event): Hat die Nummer (26128), das Reglement (ÖTO), den Nennschluss, den TB (Turnierbeauftragten). Hier wird die n2-26128.dat hochgeladen.
|
||||||
|
3. Bewerb (Die Prüfung): Bekommt die Auswahl des Platzes, das Startgeld, das Richtverfahren und das Flag "Geldpreis Auszahlung".
|
||||||
|
|
||||||
|
Wenn Sie mit dieser Struktur einverstanden sind, können wir gedanklich (und architektonisch) zum Erstellen der Bewerbe und deren Abteilungs-Regeln übergehen! Passt das so für Sie?
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
Du hast mit dem Thema "Austragungsplätze", gehören der Veranstaltung wieder eine Frage eröffnet.
|
||||||
|
"Richter-Einteilung"
|
||||||
|
Das ist immer ein heikles Tehma und auch oft schwer den Überblick zu behalten bei Veranstaltungen mit mehreren Turnieren sind meistens auch die selben Richter eingeladen. Eines der schwierigsten Veranstaltungen, welche ich selber schon als Meldestelle gearbeitet hatte, ist der "AWÖ-Cup" in Stadl-Paura.
|
||||||
|
Bei dieser Veranstaltung sind auf dem gesamten Areal die Sparten:
|
||||||
|
- Dressur
|
||||||
|
- Springen
|
||||||
|
- Vielseitigkeit
|
||||||
|
- Fahren
|
||||||
|
zeitgleich bzw. leicht verschoben. Jetzt hast du eine Handvoll Richter, die du korrekt einteilen musst wobei eingige Richter alle Sparten richten dürfen und andere nicht.
|
||||||
|
Das ist immer eine Herausforderung für alle beteiligten um dabei keine Fehler zu machen.
|
||||||
|
|
||||||
|
Was heist das für uns? Bei größeren Veranstaltungen müssen wir die Richter-Einteilung Veranstaltungsweit organisieren können.
|
||||||
|
|
||||||
|
"4. Preisliste / Artikel "
|
||||||
|
- "Automatisch (ÖTO)" du hast Recht, aber es muss noch immer flexibel zu Ändern sein, aber als Default-Wert können wir diese Werte voreintragen.
|
||||||
|
- "Manuell (Veranstalter-Artikel)" Veranstalter-Ebene - Okay
|
||||||
|
|
||||||
|
"1. Veranstaltung (Die Klammer): Enthält die Plätze ("Waldarena") und die Preisliste ("Heu", "Ansage"). Hier wird die ZNS.zip (Stammdaten) hochgeladen."
|
||||||
|
- Bin damit einverstanden
|
||||||
|
|
||||||
|
"2. Turnier (Das Sport-Event): Hat die Nummer (26128), das Reglement (ÖTO), den Nennschluss, den TB (Turnierbeauftragten). Hier wird die n2-26128.dat hochgeladen."
|
||||||
|
- n2-26128.dat wenn vorhanden und notwendig
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
🏗️ [Lead Architect]
|
||||||
|
|
||||||
|
Das ist eine absolute Punktlandung! Die Richter-Einteilung (bzw. Funktionärs-Einteilung) veranstaltungsweit zu organisieren, ist die einzig richtige Lösung für Events wie den AWÖ-Cup, wo Funktionäre zwischen den Plätzen und Sparten hin und her springen.
|
||||||
|
|
||||||
|
Wir ziehen daraus folgende finale Architektur-Beschlüsse für das Fundament:
|
||||||
|
|
||||||
|
1. Funktionärs-Pool (Veranstaltungsebene): Das gesamte Richterkollegium wird an der Veranstaltung angemeldet (oft kommen diese Daten ja aus der ZNS.zip).
|
||||||
|
2. Turnierbeauftragter (Turnierebene): Jedes Turnier (die 26128) pickt sich aus diesem Pool genau einen Funktionär heraus, der als TB fungiert.
|
||||||
|
3. Richter-Einsatz (Bewerbsebene): Jeder Bewerb (Prüfung) pickt sich aus dem Veranstaltungs-Pool die Richter heraus, die am Richtertisch sitzen.
|
||||||
|
4. ZNS.zip: Wird an der Veranstaltung hochgeladen (aktualisiert Stammdaten und den Funktionärs-Pool).
|
||||||
|
5. n2-xxxxx.dat: Wird (wenn vorhanden/nötig) direkt am Turnier hochgeladen.
|
||||||
|
|
||||||
|
(Ich habe das domain_model.drawio bereits im Hintergrund um den Austragungsplatz, die Preisliste/TurnierArtikel und das TeilnehmerKonto erweitert, damit unser Architekturbild absolut synchron mit der Realität ist).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nächster Stint: "Prüfungen (Bewerbe) anlegen"
|
||||||
|
|
||||||
|
Wir haben die Halle gebaut, den Sand gestreut, das Heu bepreist und die Richter eingeladen. Jetzt geht es an die Ausschreibung der Bewerbe.
|
||||||
|
Wenn Sie in der Software auf "+ Neuer Bewerb" klicken, haben wir folgende Eckdaten aus der Ausschreibung vorliegen:
|
||||||
|
|
||||||
|
• Bewerbsnummer: z.B. "1", "14a"
|
||||||
|
• Bezeichnung: z.B. "Standardspringprüfung"
|
||||||
|
• Sparte & Niveau: z.B. "Springen", "130 cm", Klasse "LM"
|
||||||
|
• Richtverfahren: z.B. "Fehler/Zeit", "Stilspringen"
|
||||||
|
• Austragungsplatz: z.B. "Waldarena"
|
||||||
|
• Geldpreis: Ja/Nein
|
||||||
|
|
||||||
|
Jetzt kommt das Wichtigste für die Meldestelle: Die Teilung in Abteilungen. Hier passieren die meisten Fehler, und hier muss die Software Ihnen helfen. Die ÖTO gibt uns in § 39 strenge Schwellenwerte vor (z.B. "ab 80 Startern MUSS geteilt werden").
|
||||||
|
|
||||||
|
Welche Teilungs-Logiken brauchen Sie in der Praxis beim Anlegen des Bewerbs zwingend als Auswahlmöglichkeit, damit das System die Startlisten später korrekt generiert?
|
||||||
|
|
||||||
|
Ich schlage folgende Optionen vor, die das System "verstehen" muss:
|
||||||
|
|
||||||
|
1. Keine Teilung: Alle Starter reiten in einer Abteilung (Standard für kleine Prüfungen).
|
||||||
|
2. Nach Lizenz: (R1 vs. R2/RS2 vs. R3+).
|
||||||
|
3. Nach Alter: (Jugend vs. Junioren vs. Allg. Klasse).
|
||||||
|
4. Nach Pferd: (Ponys vs. Warmblut bzw. 4-jährig vs. 5-jährig).
|
||||||
|
5. Pures Starter-Limit (Organisatorisch): "Wenn mehr als 50 Starter, teile ich in Abteilung 1 und 2, einfach in der Mitte durchgeschnitten".
|
||||||
|
|
||||||
|
Passt diese Einteilung für Sie? Oder gibt es noch exotischere Teilungsregeln, die wir beim Anlegen des Bewerbs unbedingt vorsehen müssen (wie z.B. "Separate Siegerehrung für den besten Ländlichen Reiter", auch wenn alle zusammen reiten)?
|
||||||
|
|
||||||
|
--- Ich ---
|
||||||
|
|
||||||
|
"3. Richter-Einsatz (Bewerbsebene): Jeder Bewerb (Prüfung) pickt sich aus dem Veranstaltungs-Pool die Richter heraus, die am Richtertisch sitzen."
|
||||||
|
- Die Richter, die die nötige Qualifikation haben stehen zur Auswahl, aber weil wir ja flexibel sind und am Turnier der TB Regeln, sagen wir flexibel auslegen darf, stehen auch die Richter zur Auswahl, dessen Qualifikation nicht dieser Proüfung entsprechen aber ausgegraut, also optisch sichtbar, dass diese nicht die erste Wahl sein sollten bzw. eine Bestätigung des TB erfordert.
|
||||||
|
|
||||||
|
"Bewerb anlegen"
|
||||||
|
Das sind Screenshots vom "alten" Meldestellen-Programm "SuDo"
|
||||||
|
docs/BilderSuDo/Bewerbe.PNG
|
||||||
|
docs/BilderSuDo/Bewerbe-Bewertung.PNG
|
||||||
|
docs/BilderSuDo/Bewerbe-Geldpreis.PNG
|
||||||
|
docs/BilderSuDo/Bewerbe-OrtZeit.PNG
|
||||||
|
|
||||||
|
Das ist wieder ein kleiner Wizzard.
|
||||||
|
Ich drücke auf den Button "+ Neuer Bewerb"
|
||||||
|
|
||||||
|
"Bewerbsnummer" wird mir automatisch vorgeschlagen, aber ich sollte diese auch ändern können auf eine Bewerbs-Nr die noch nicht vergeben ist, wenn notwendig.
|
||||||
|
|
||||||
|
"Sparte" - wenn es ein kombiniertes Turnier ist, ansonsten bleibt es bei der Turnier-Sparte
|
||||||
|
|
||||||
|
"Kategorie" - hier habe ich eine Auswahlmöglichkeit der Turnier-Kategorien. In unserem Neumarkt-Beispiel CDN-C_NEU oder CDNP-C_NEU
|
||||||
|
|
||||||
|
"Klasse/Höhe" - wenn Dressur steht hier Klasse und diese sind dann zur Auswahl bereit bzw. bei Springen Höhe und ebenfalls Sparten spezifisch
|
||||||
|
|
||||||
|
"Prüfung" - Spartenspezifische Auswahl an Prüfungen
|
||||||
|
"Richtverfahren" - Auswahlmöglichkeiten gefiltert durch die zuvor gewählten Möglichkeiten
|
||||||
|
"Para Grade" - sollten wir vorbereitet sein, aber dabei kenne ich mich zuwenig aus.
|
||||||
|
|
||||||
|
"Bezeichnung" - Dressurreiterprüfung Reiter
|
||||||
|
"Beschreibung" - Pony Einsteiger Cup OÖ
|
||||||
|
|
||||||
|
"Aufgabe" - hier das Beispiel Aufgabe "R" steht für Reiterpass
|
||||||
|
"Aufgaben-Nr" - es gibt mehrere Reiterpass-Aufgaben, diese haben Nummern oder Bezeichnungen und hier kann ich dann die genaue Aufgabe selektieren
|
||||||
|
|
||||||
|
"Richteranzahl" - ein, zwei usw. und ein Fenster in dem ich die Richter zu dieser Prüfung laden kann.
|
||||||
|
Sparten-spezifisch, natürlich.
|
||||||
|
Bei Dressur müssen wir auch die Position angeben wo der/die Richter sitzen.
|
||||||
|
Richter bei "C"
|
||||||
|
Richter bei "B"
|
||||||
|
Zur Erklärung, die Buschstaben sind die jenigen an einem Dressurviereck. Bei getrennten Richtverfahren kann es bis zu 5 Richter rund um das Dressurviereck geben. Aber das ist noch Zukunftsmusik, denn bei getrennten Richtverfahren ist eine separate "Rechenstelle" verpflichtet.
|
||||||
|
|
||||||
|
"Ort/Zeit" -
|
||||||
|
- Tag: Turniertag
|
||||||
|
- Beginn-Zeit - "fix um" - Bewerb beginnt fix um, "anschliessend" errechnete Uhrzeit
|
||||||
|
- Uhrzeit - hier sehe ich entweder die errechnete beginnzeit des Bewerbs und/oder ich kann hier die gewünschte Zeit eingeben, aber nicht überschneident mit dem Bewerbsende des Vorbewerbes.
|
||||||
|
- Reitdauer - wie lange braucht ein Starter für diese Prüfung, im Springen Standardwert 2 min, in der Dressur je nach Aufgabe 3:30 min - 7:00 min
|
||||||
|
- Umbau/Bodenpflege - Die Austragungsplätze müssen auch mal zwischen den Bewerben gepflegt werden. Damit meint man, dass der Boden wieder glatt gemacht wird und oder gewässert wird, bzw. bei Springen muss ein neuer Parcours aufgebaut werden. Hier kann ich dies zeitlich zwischen den Bewerben einplanen.
|
||||||
|
- Besichtigung - bei Springturnieren nachdem der neue Parcours aufgebaut ist, ein Richter diesen Parcours abgenommen und freigegeben hat, ist der Parcours für die Teilnehmer dieser Prüfung zur Besichtigung frei. Dies dauert in der Regel 10 min - 15 min.
|
||||||
|
- Stechen - ist auch ein Feld zum planen wenn eine Springprüfung mit Stechen geplant ist.
|
||||||
|
|
||||||
|
Du merkst, für einen ausgereiften und durchdachten Zeitplan ist viel zu kalkulieren.
|
||||||
|
|
||||||
|
- Start/Geldpreis - hier kann ich die Startgelder bzw. die Geldpreise genau einstellen. Geldpreise nach ÖTO aber flexibel
|
||||||
|
|
||||||
|
|
||||||
|
Wenn ich den Bewerb eingeichtet habe und laut Ausschreibung sonst keine Abteilungstrennung notwendig ist, haben wir eine Prüfung/Bewerb-Abteilung in einem
|
||||||
|
Sonst klicke ich auf Prüfung/Bewerb-Teilen und wir kommen zu einer Übersicht in dieser ich diese Prüfung/Bewerb in verschiedene Vorlagen Teilen kann, auch eine Manuelle Teilung muss machbar sein, so dass ich jedem eizelnen Starter selber eine Abteilungsnummer vergeben kann und die Abteilungen selber bezeichnen/benennen kann. Wir sind ja felxibel ;-)
|
||||||
|
|
||||||
|
--- Gemini ---
|
||||||
|
|
||||||
|
The server encountered a resource exhausted error. This is likely due to the number of requests issued reaching your quota.
|
||||||
|
|
||||||
|
----
|
||||||
Loading…
Reference in New Issue
Block a user