feat(docs): expand masterdata documentation with Reiter- and Pferdeprüfungen

- Added `REITER_PRUEFUNGEN.md` and `PFERDEPRUEFUNGEN_BEWERTUNG.md` to document evaluation criteria, scoring logic, and system requirements for dressage and show jumping.
- Updated `README.md` with links to new documentation on rider- and horse-specific regulations.
- Created database schemas for `TurnierklasseTable`, `RichtverfahrenTable`, `GebuehrTable`, `LicenseTable`, and `RegulationConfigTable`, aligning with ÖTO 2026.
- Logged architectural decisions and analysis in `session-logs` and created ADRs `0017-masterdata-importer-worker` and `0019-api-ingestion-layers`.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-30 14:29:55 +02:00
parent 6375ec23c3
commit e8757c5c32
29 changed files with 1663 additions and 18 deletions
@@ -0,0 +1,29 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Exposed-Tabellendefinition für die Gebührenordnung.
* Basierend auf ÖTO 2026.
*/
object GebuehrTable : Table("gebuehr") {
val id = uuid("gebuehr_id")
val bezeichnung = varchar("bezeichnung", 200)
val typ = varchar("typ", 50) // NENNUNG, STARTGELD, BOX, STALLGELD, SONSTIGES
val betrag = decimal("betrag", 10, 2)
val waehrung = varchar("waehrung", 3).default("EUR")
// Versionierung gemäß ADR-0018
val validFrom = timestamp("valid_from").defaultExpression(CurrentTimestamp)
val validTo = timestamp("valid_to").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
}
@@ -303,7 +303,7 @@ class HorseRepositoryImpl : HorseRepository {
it[verantwortlichePersonId] = toUpdate.verantwortlichePersonId
it[zuechterName] = toUpdate.zuechterName
it[zuchtbuchNummer] = toUpdate.zuchtbuchNummer
it[lebensnummer] = toUpdate.lebensnummer
it[HorseTable.lebensnummer] = toUpdate.lebensnummer
it[chipNummer] = toUpdate.chipNummer
it[passNummer] = toUpdate.passNummer
it[oepsNummer] = toUpdate.oepsNummer
@@ -12,7 +12,7 @@ import org.jetbrains.exposed.v1.datetime.timestamp
*/
object HorseTable : Table("horse") {
val id = uuid("horse_id")
val pferdeName = varchar("pferde_name", 200)
val pferdeName = varchar("pferde_name", 200).index()
val geschlecht = varchar("geschlecht", 20)
val geburtsdatum = date("geburtsdatum").nullable()
val rasse = varchar("rasse", 100).nullable()
@@ -21,7 +21,7 @@ object HorseTable : Table("horse") {
val verantwortlichePersonId = uuid("verantwortliche_person_id").nullable()
val zuechterName = varchar("zuechter_name", 200).nullable()
val zuchtbuchNummer = varchar("zuchtbuch_nummer", 50).nullable()
val lebensnummer = varchar("lebensnummer", 50).nullable()
val lebensnummer = varchar("lebensnummer", 50).nullable().index()
val chipNummer = varchar("chip_nummer", 50).nullable()
val passNummer = varchar("pass_nummer", 50).nullable()
val oepsNummer = varchar("oeps_nummer", 50).nullable()
@@ -37,9 +37,4 @@ object HorseTable : Table("horse") {
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_horse_lebensnummer", isUnique = false, lebensnummer)
index("idx_horse_name", isUnique = false, pferdeName)
}
}
@@ -0,0 +1,32 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Exposed-Tabellendefinition für die Lizenz-Matrix (Reiter-Lizenz vs. Turnierklasse).
* Basierend auf ÖTO 2026.
*/
object LicenseTable : Table("license_matrix") {
val id = uuid("license_id")
val sparte = varchar("sparte", 20) // DRESSUR, SPRINGEN, ALLGEMEIN
val lizenzKlasse = varchar("lizenz_klasse", 20) // R1, R2, R3, RD1, RD2, RD3, LF
val maxTurnierklasseCode = varchar("max_turnierklasse_code", 10) // E, A, L, LM, M, S
// Versionierung gemäß ADR-0018
val validFrom = timestamp("valid_from").defaultExpression(CurrentTimestamp)
val validTo = timestamp("valid_to").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_license_sparte_klasse", false, sparte, lizenzKlasse)
}
}
@@ -0,0 +1,32 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Exposed-Tabellendefinition für die allgemeine Regelkonfiguration.
* Basierend auf ADR-0018.
*/
object RegulationConfigTable : Table("regulation_config") {
val id = uuid("config_id")
val key = varchar("config_key", 100)
val value = text("config_value") // JSON oder einfacher String
val beschreibung = varchar("beschreibung", 255).nullable()
// Versionierung gemäß ADR-0018
val validFrom = timestamp("valid_from").defaultExpression(CurrentTimestamp)
val validTo = timestamp("valid_to").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_regulation_config_key", false, key)
}
}
@@ -0,0 +1,33 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Exposed-Tabellendefinition für Richtverfahren.
* Basierend auf ÖTO 2026.
*/
object RichtverfahrenTable : Table("richtverfahren") {
val id = uuid("richtverfahren_id")
val sparte = varchar("sparte", 20) // DRESSUR, SPRINGEN
val code = varchar("code", 10) // A1, A2, AM5, RV_A, RV_B
val bezeichnung = varchar("bezeichnung", 200)
val beschreibung = text("beschreibung").nullable()
// Versionierung gemäß ADR-0018
val validFrom = timestamp("valid_from").defaultExpression(CurrentTimestamp)
val validTo = timestamp("valid_to").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_richtverfahren_sparte_code", false, sparte, code)
}
}
@@ -0,0 +1,34 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
/**
* Exposed-Tabellendefinition für Turnierklassen (Springen/Dressur).
* Basierend auf ÖTO 2026.
*/
object TurnierklasseTable : Table("turnierklasse") {
val id = uuid("turnierklasse_id")
val sparte = varchar("sparte", 20) // DRESSUR, SPRINGEN
val code = varchar("code", 10) // E, A, L, LM, M, S
val bezeichnung = varchar("bezeichnung", 100)
val maxHoehe = integer("max_hoehe").nullable() // in cm (Springen)
val aufgabenNiveau = varchar("aufgaben_niveau", 100).nullable() // (Dressur)
// Versionierung gemäß ADR-0018
val validFrom = timestamp("valid_from").defaultExpression(CurrentTimestamp)
val validTo = timestamp("valid_to").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_turnierklasse_sparte_code", false, sparte, code)
}
}