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
+7
View File
@@ -59,8 +59,15 @@ Die APIs sind unter `/api/v1/masterdata/...` erreichbar.
Sämtliche Stammdaten (insbesondere Altersklassen und Sparten) sind strikt nach dem **ÖTO (Österreichische
Turnierordnung)** Regelwerk modelliert. Detaillierte Aufstellungen der verwendeten Definitionen finden sich hier:
* [Strategische Roadmap](docs/ROADMAP.md) (Phasen, Meilensteine, Verantwortlichkeiten)
* [ÖTO-Stammdaten Dokumentation](docs/OETO_STAMMDATEN.md) (Fachliche Logik)
* [Turnier-Sparten & Klassen](docs/TURNIER_KLASSEN.md) (Detaillierte Übersicht Springen/Dressur & C-NEU)
* [Reiter-Lizenzen & Startberechtigungen](docs/REITER_LIZENZEN.md) (Lizenzstufen & Sportliche Relevanz)
* [Richter & Parcoursbauer Qualifikationen](docs/FUNKTIONAERE_QUALIFIKATIONEN.md) (Befugnisse & Einsatzvorgaben)
* [Gebührenordnung ÖTO 2026](docs/GEBUEHRENORDNUNG.md) (Nenn-/Startgelder & Geldpreise)
* [Pferdeprüfungen (Jungpferde)](docs/PFERDEPRUEFUNGEN.md) (Dressur-/Springpferdeprotokolle)
* [Pferdeprüfungen (Bewertungssystem)](docs/PFERDEPRUEFUNGEN_BEWERTUNG.md) (Abzugslogik & qualitative Noten)
* [Reiter-Prüfungen (Dressur & Stilspringen)](docs/REITER_PRUEFUNGEN.md) (Fokus auf Sitz & Einwirkung)
* [ZNS-Schnittstellen Spezifikation](docs/ZNS_SCHNITTSTELLE.md) (Technisches Transfer-Format)
Änderungen am Regelwerk müssen hier zentral eingepflegt werden, damit sie
@@ -0,0 +1,96 @@
# 🧐 Qualifikationen: Richter & Parcoursbauer (Funktionäre)
Diese Dokumentation beschreibt die Qualifikationsstufen und technischen Anforderungen für Funktionäre (Richter,
Parcoursbauer, Stewards) basierend auf der ÖTO 2026 und dem ZNS-Pflichtenheft v2.4.
---
## 1. Fachliche Qualifikationsstufen
Die Befugnisse der Funktionäre richten sich nach der offiziellen Richterliste des OEPS (§ 48 A-Teil).
### 1.1 Richter (Sparte Dressur & Springen)
Richter werden in unterschiedliche Klassen eingeteilt, die festlegen, bis zu welcher Kategorie und Klasse sie richten
dürfen.
| Kürzel | Bezeichnung | Befugnis (Beispiel) |
|:--------|:--------------|:--------------------------------------------|
| **D** | Dressur | Allgemeine Dressurbewerbe |
| **S** | Springen | Allgemeine Springbewerbe |
| **DPF** | Dressurpferde | Zusatzqualifikation für Jungpferdeprüfungen |
| **SPF** | Springpferde | Zusatzqualifikation für Jungpferdeprüfungen |
| **G** | Gelände | Vielseitigkeit (CCN) |
| **STW** | Steward | Aufsicht am Abreiteplatz |
### 1.2 Parcoursbauer (Sparte Springen)
Die Qualifikation der Parcoursbauer wird in Level (P) angegeben (§ 1965 B-Teil).
| Level | Bezeichnung | Einsatzbereich |
|:-------|:----------------|:----------------------------------------------|
| **P1** | Einsteiger | Verpflichtend für CSN-C-NEU Turniere |
| **P2** | Fortgeschritten | Turniere der Kategorie C und B |
| **P3** | National | Turniere der Kategorie B* und A |
| **P4** | Grand Prix | Turniere der Kategorie A* und Meisterschaften |
---
## 2. Einsatzvorgaben (Regelwerk)
### 2.1 Mindestbesetzung (§ 50 A-Teil)
* **Standard:** Mindestens zwei Richter pro Bewerb.
* **Ausnahme (CDN Kl. A / CSN bis 120 cm):** Ein Richter zulässig (bei Kat. B/C).
* **CSN-C-NEU:**
* Mindestens zwei Richter.
* Mindestens ein Parcoursbauer Level **P1**.
* **Pferdeprüfungen:** Mindestens ein Richter der Gruppe muss die Zusatzqualifikation **SPF** (Springen) oder **DPF** (
Dressur) besitzen.
### 2.2 Zeitlimits (§ 50 Abs. 7 A-Teil)
* Maximal **10 Stunden** Einsatz pro Tag.
* Nach 4 Stunden: Mindestens **45 Minuten Pause**.
* Bei beurteilendem Richtverfahren (Dressur): Maximal **7 Stunden** reine Richtzeit.
---
## 3. Technische Umsetzung (ZNS-Schnittstelle)
Die Daten werden über die Datei `RICHT01.dat` (Teil der `ZNS.zip`) importiert.
### 3.1 Dateistruktur (RICHT01.dat)
#### Richter (X-Satz)
| Feld | Stelle | Länge | Typ | Beschreibung |
|:--------------------|:-------|:------|:------|:---------------------------------------|
| **ID** | 1 | 1 | Alpha | Wert "X" |
| **SATZNUMMER** | 2 | 6 | Num | Eindeutige OEPS-ID (000000) |
| **NAME** | 8 | 75 | Alpha | Familienname, Vorname |
| **QUALIFIKATIONEN** | 83 | 30 | Alpha | Komma-getrennte Codes (z.B. "D,S,SPF") |
#### Parcoursbauer (Y-Satz)
| Feld | Stelle | Länge | Typ | Beschreibung |
|:--------------------|:-------|:------|:------|:-------------------------------------|
| **ID** | 1 | 1 | Alpha | Wert "Y" |
| **SATZNUMMER** | 2 | 6 | Num | Eindeutige OEPS-ID (000000) |
| **NAME** | 8 | 75 | Alpha | Familienname, Vorname |
| **QUALIFIKATIONEN** | 83 | 30 | Alpha | Komma-getrennte Codes (z.B. "P1,P2") |
---
## 4. Validierungs-Logik im System
Der `masterdata` Service muss beim Import und bei der Turnierplanung folgende Prüfungen ermöglichen:
1. **Existenzprüfung:** Ist die Satznummer in der aktuellen ZNS-Liste vorhanden?
2. **Qualifikations-Check:** Verfügt der Richter über die für den Bewerb erforderliche Kennung (z.B. SPF für
Springpferdeprüfungen)?
3. **Level-Check:** Erfüllt der Parcoursbauer das Mindestlevel (P1) für C-NEU Turniere?
---
> 📜 **Rulebook Expert Hinweis:** Die Qualifikations-Codes in `RICHT01.dat` sind der Primärschlüssel für die
> automatisierte Prüfung der Richtereinteilung in der Ausschreibung.
@@ -0,0 +1,117 @@
# 💰 Gebührenordnung (ÖTO 2026) Dressur & Springen
Dieses Dokument fasst die für die Sparten **Dressur (CDN)** und **Springen (CSN)** relevanten Gebühren,
Nenn-/Startgelder sowie Mindest-Geldpreise basierend auf der **ÖTO 2026 (Teil E)** zusammen.
---
## 1. Nenn- und Startgelder (§ 5 Gebührenordnung)
Die Gebühren setzen sich aus einem Nenngeld (pro Pferd/Turnier) und einem Startgeld (pro Bewerb) zusammen.
### 1.1 Nenngeld (Fixe Gebühr pro Turnier)
| Kategorie | Typ | Gebühr (EUR) |
|:------------------------|:----------|:----------------|
| **Bewerbe ohne Lizenz** | - | *Kein Nenngeld* |
| **Eintages-Turniere** | Alle | 16,00 |
| **Kat. C / C-NEU** | Mehrtägig | 25,00 30,00 |
| **Kat. B / B*** | Mehrtägig | 25,00 35,00 |
| **Kat. A / A*** | Mehrtägig | 25,00 50,00 |
| **Meisterschaften** | Mehrtägig | 25,00 35,00 |
### 1.2 Startgeld (Pro Bewerb)
| Bewerbstyp | Kategorie | Max. Startgeld (EUR) |
|:------------------------------------------|:-----------------|:-------------------------------------------|
| **Bewerbe ohne Geldpreis** | Alle | 20,00 |
| **Bewerbe für Reiter ohne Lizenz** | Alle | 20,00 |
| **Bewerbe mit Geldpreis** | Alle | max. 50% des letztausgezahlten Geldpreises |
| **C-NEU Turniere** | Dressur/Springen | max. 20,00 |
| **Dressur-Aufpreis (getrenntes Richten)** | 3 Richter | + max. 8,00 |
| **Dressur-Aufpreis (getrenntes Richten)** | > 3 Richter | + max. 12,00 |
| **Springen Warmup** | Vortag | max. 15,00 |
| **Pony/Führzügel/First Ridden** | - | max. 15,00 |
### 1.3 Zusatzabgaben pro Start
* **Tierwohleuro:** 1,00 EUR (nur bei Springen/Vielseitigkeit/Fahren/Distanz).
* **Sportförderbeitrag:** 1,00 EUR (NICHT bei C-NEU, Pony, Führzügel, First Ridden).
---
## 2. Mindest-Geldpreise & Startgelder (§ 7 Gebührenordnung)
Geldpreise sind in den Kategorien A und B verpflichtend (sofern ausgeschrieben). Bei Kat. C sind Mindestwerte
festgelegt.
### 2.1 Dressur (CDN) Mindest-Geldpreise (EUR)
*Werte für Platz 1 bis 6 und das restliche erste Viertel.*
| Kategorie | Klasse | 1. | 2. | 3. | 4. | 5. | 6. | ab 7. | Max. Startgeld |
|:-----------|:-------|:----|:----|:----|:----|:---|:---|:------|:---------------|
| **Kat. A** | L | 105 | 80 | 65 | 50 | 42 | 42 | 42 | 21 |
| **Kat. A** | LM | 150 | 115 | 90 | 70 | 50 | 42 | 42 | 21 |
| **Kat. A** | M | 220 | 175 | 140 | 105 | 70 | 50 | 42 | 21 |
| **Kat. A** | S | 250 | 210 | 140 | 105 | 80 | 60 | 42 | 21 |
| **Kat. B** | A | 70 | 55 | 40 | 36 | 36 | 36 | 36 | 21 |
| **Kat. B** | L | 85 | 65 | 55 | 42 | 42 | 42 | 42 | 21 |
| **Kat. B** | LM | 125 | 100 | 80 | 60 | 42 | 42 | 42 | 21 |
| **Kat. B** | M | 165 | 135 | 110 | 80 | 55 | 42 | 42 | - |
| **Kat. B** | S | 220 | 175 | 140 | 105 | 70 | 50 | 42 | - |
| **Kat. C** | A | 40 | 35 | 30 | 26 | 26 | 26 | 26 | 13 |
| **Kat. C** | L | 65 | 55 | 40 | 36 | 36 | 36 | 36 | 18 |
| **Kat. C** | LM | 85 | 70 | 55 | 42 | 42 | 42 | 42 | 21 |
### 2.2 Springen (CSN) Mindest-Geldpreise (EUR)
*Werte basierend auf der Hindernishöhe.*
| Kategorie | Höhe (cm) | 1. | 2. | 3. | 4. | 5. | 6. | ab 7. | Max. Startgeld |
|:-----------|:----------|:----|:----|:----|:----|:----|:----|:------|:---------------|
| **Kat. A** | 115/120 | 160 | 140 | 115 | 90 | 70 | 45 | 42 | 21 |
| **Kat. A** | 125/130 | 185 | 160 | 140 | 115 | 70 | 46 | 46 | 23 |
| **Kat. A** | 135 | 250 | 210 | 160 | 115 | 90 | 70 | 46 | 23 |
| **Kat. A** | 140 | 380 | 310 | 210 | 155 | 120 | 85 | 58 | 29 |
| **Kat. A** | 145 | 450 | 345 | 275 | 210 | 140 | 86 | 58 | 29 |
| **Kat. A** | 150/160 | 520 | 400 | 310 | 240 | 170 | 120 | 58 | 29 |
| **Kat. B** | 105/110 | 70 | 55 | 40 | 36 | 36 | 36 | 36 | 18 |
| **Kat. B** | 115/120 | 140 | 115 | 90 | 70 | 45 | 42 | 42 | 21 |
| **Kat. B** | 125/130 | 160 | 140 | 115 | 90 | 70 | 46 | 46 | 23 |
| **Kat. B** | 135 | 185 | 160 | 140 | 115 | 70 | 46 | 46 | 23 |
| **Kat. B** | 140 | 255 | 205 | 160 | 115 | 90 | 70 | 46 | 23 |
---
## 3. Aufwendungen für Funktionäre (§ 8 Gebührenordnung)
Vergütungen für Richter, Stewards und Parcoursbauer.
### 3.1 Tagessätze (Richtsätze)
* **Standard-Tagessatz:** 120,00 EUR (Steward, Richter, Parcoursbauer).
* **Sonderprüfungen (Abzeichen):** 100,00 EUR.
* **Halbtagessatz (bis 4 Std.):** 60,00 EUR.
* **Unkostenbeitrag Turnierbeauftragter:** 30,00 EUR / Tag.
* **Unkostenbeitrag Parcoursbauer (Kat. B/C):** 22,00 EUR / Tag.
* **Unkostenbeitrag Parcoursbauer (Kat. A+):** 30,00 EUR / Tag.
* **Turniertierarzt:** 350,00 EUR / Tag (exkl. MwSt.).
* **Assistent Parcoursbauer:** 50,00 EUR / Tag (inkl. Reisekosten).
### 3.2 Reise- und Aufenthaltskosten
* **PKW-Kilometergeld:** 0,50 EUR / km.
* **Bahnfahrt:** 1. Klasse Ticket.
* **Unterkunft:** Zimmer mit Dusche/WC inklusive Frühstück.
---
## 4. Sonstige Gebühren
* **Nachnenngebühr (an OEPS):** 25,00 EUR.
* **Tausch Nennung (Pferd/Reiter):** 15,00 EUR.
* **ZNS-Gebühr pro Pferd:** 5,00 EUR.
* **Boxengebühr (bei Boxenpflicht):** max. 130,00 EUR.
* **Endreinigung Box:** max. 30,00 EUR.
* **Reinigungsgebühr (Tagesgäste ohne Box):** max. 10,00 EUR / Pferd.
@@ -29,13 +29,13 @@ Die Klassen definieren die maximale Hindernishöhe (§ 200 B-Teil).
| Klasse | Bezeichnung | Höhe (cm) | Zulässige Turnier-Kategorien |
|:--------|:--------------------|:----------|:-----------------------------|
| **E0** | Einsteiger | 60 95 | C-NEU, C, B |
| **A** | Leicht | 105 110 | Alle (A erst ab Kat. B/A) |
| **L** | Mittelleicht | 115 120 | Alle |
| **LM** | Leicht-Mittelschwer | 125 130 | Alle |
| **M** | Mittelschwer | 135 | B, B*, A, A* |
| **S*** | Schwer | 140 145 | B*, A, A* |
| **S**** | Schwer (GP) | 150 160 | A* |
| **E0** | Einsteiger | 60 95 | C-NEU, C, B | Inkl. lizenzfrei (Reiterpass) |
| **A** | Leicht | 105 110 | Alle (A erst ab Kat. B/A) | - |
| **L** | Mittelleicht | 115 120 | Alle | - |
| **LM** | Leicht-Mittelschwer | 125 130 | Alle | - |
| **M** | Mittelschwer | 135 | B, B*, A, A* | - |
| **S*** | Schwer | 140 145 | B*, A, A* | - |
| **S**** | Schwer (GP) | 150 160 | A* | - |
### 2.2 Dressur (CDN) Aufgabenniveau
@@ -43,6 +43,7 @@ Dressurprüfungen werden nach offiziellen Aufgabenheften geritten (§ 100 B-Teil
| Klasse | Niveau | Besonderheiten |
|:-------|:--------------------|:-------------------------------------------------------|
| **LF** | Lizenzfrei | Reiterpass/Reiternadel-Aufgaben (C-NEU) |
| **A** | Leicht | Grundlagen, 20x40m oder 20x60m Viereck |
| **L** | Mittelleicht | Beginnende Versammlung |
| **LM** | Leicht-Mittelschwer | Wahlweise Trense oder Kandare |
@@ -59,8 +60,11 @@ Dressurprüfungen werden nach offiziellen Aufgabenheften geritten (§ 100 B-Teil
* **Lizenzprüfung:** Getrennt nach R2/RD2 und R3/RD3.
* **Pferdeprüfungen:** Zwingend nach **Alter der Pferde** (z.B. 4-jährige vs. 5-6-jährige).
* **CSN-C-NEU:**
* Bis 95 cm: Abt. 1 (ohne Lizenz) / Abt. 2 (mit Lizenz).
* Bis 95 cm: Abt. 1 (ohne Lizenz) / Abt. 2 (R1) / Abt. 3 (R2 und höher).
* Ab 100 cm: Abt. 1 (R1) / Abt. 2 (R2 und höher).
* **CDN-C-NEU:**
* Reiterpass/Reiternadel-Aufgaben: Keine Lizenzinhaber startberechtigt.
* Inkl. First Ridden und Führzügelbewerbe.
### 3.2 Kapazitive Teilung (MUSS-Grenzen)
@@ -0,0 +1,94 @@
# 🐴 Pferdeprüfungen (Jungpferde) Dressur & Springen
Diese Dokumentation beschreibt die spezifischen Anforderungen und Richtverfahren für Pferdeprüfungen (Dressurpferde,
Springpferde) gemäß ÖTO 2026. Diese Prüfungen dienen der Beurteilung von jungen Pferden und weisen eine höhere
Komplexität in der Bewertung auf als Standardprüfungen.
## 1. Übersicht & Altersklassen (§ 100 & § 200 B-Teil)
Stichtag für das Alter des Pferdes ist der **1. Januar** des Geburtsjahres (Pferde altern immer zum Jahreswechsel).
| Sparte | Klasse | Pferdealter | Besonderheiten |
|:-------------|:------------|:------------|:-------------------------------|
| **Dressur** | **A** | 4 6 Jahre | Pflicht-Teilung: 4j. vs. 5-6j. |
| **Dressur** | **L** | 5 6 Jahre | Keine Teilung vorgeschrieben |
| **Dressur** | **M** | 6 7 Jahre | Keine Teilung vorgeschrieben |
| **Dressur** | **S** | 7 8 Jahre | Spezielles Richtverfahren |
| **Springen** | **95-110** | 4 6 Jahre | - |
| **Springen** | **115-130** | 5 7 Jahre | - |
| **Springen** | **135** | 6 8 Jahre | - |
---
## 2. Dressurpferdeprüfungen (§ 103, § 104 B-Teil)
### 2.1 Bewertungskriterien
Im Gegensatz zu Standard-Dressurprüfungen wird nicht jede Lektion einzeln benotet, sondern es erfolgt eine qualitative
Bewertung in folgenden Blöcken:
1. **Schritt**
2. **Trab**
3. **Galopp**
4. **Durchlässigkeit / Rittigkeit**
5. **Gesamteindruck / Perspektive**
### 2.2 Richtverfahren
* **Klassen A bis M:** In der Regel **Richtverfahren A** (Gemeinsames Richten). Es wird eine schriftlich begründete
Wertnote (0-10, eine Dezimale) vergeben.
* **Klasse S:** Kombiniertes Verfahren:
* 1 Richter bei C für die **technische Bewertung** (Sitz, Einwirkung, Korrektheit).
* 2 Richter bei B oder E (gemeinsam) für das **Dressurpferdeprotokoll** (Qualität der Grundgangarten).
### 2.3 Abzüge (Verreiten)
* Erstes Mal: **- 0,1 Punkte** von der Gesamtnote.
* Zweites Mal: **- 0,2 Punkte** von der Gesamtnote.
* Drittes Mal: **Ausschluss**.
---
## 3. Springpferdeprüfungen (§ 203, § 204 B-Teil)
### 3.1 Bewertungskriterien
Es wird eine Wertnote zwischen 0 und 10 (Zehntelnoten zulässig) vergeben. Beurteilt werden:
* **Rittigkeit**
* **Springmanier**
* **Einhaltung des Tempos**
### 3.2 Abzüge (Fehler im Parcours)
Vom Grundurteil (z.B. 8,5) werden folgende Fehler abgezogen:
* **Hindernisfehler:** - 0,5 Punkte.
* **Erster Ungehorsam:** - 0,5 Punkte.
* **Zweiter Ungehorsam:** - 1,0 Punkte.
* **Dritter Ungehorsam:** Ausschluss.
* **Zeitüberschreitung:** - 0,1 Punkte pro angefangene Sekunde.
* **Sturz (Reiter/Pferd):** Ausschluss.
**Besonderheit:** Ergibt die Endnote nach Abzügen **4,9 oder weniger**, wird das Ergebnis als **"ohne Bewertung"** in
die Liste aufgenommen (reihungstechnisch zwischen platzierten Reitern und Ausgeschiedenen).
---
## 4. Reitpferdeprüfungen (§ 1102 B-Teil)
Spezielle Form für 3- und 4-jährige Pferde zur Beurteilung der Grundgangarten und des Gebäudes.
* Finden oft in Gruppen (3-4 Pferde) statt.
* Bewertung analog zu Dressurpferdeprüfungen (Schritt, Trab, Galopp, Ausbildung, Gebäude).
---
## 5. System-Anforderungen (Backend/UI)
* **Noteneingabe:** Das System muss die Eingabe von Einzelnoten für die qualitativen Merkmale (Grundgangarten etc.)
unterstützen und daraus die Endnote berechnen.
* **Abzugs-Logik:** Automatische Subtraktion von Fehlern bei Springpferdeprüfungen.
* **Ergebnisliste:** Korrekte Handhabung von "ohne Bewertung" (< 5,0) in der Reihung.
* **Pferdealter-Validierung:** Prüfung beim Nennvorgang, ob das Pferd für die ausgeschriebene Pferdeprüfung
startberechtigt ist (Geburtsjahr-Check).
@@ -0,0 +1,92 @@
# 🐴 Pferdeprüfungen & Stilspringen: Bewertungssystem (ÖTO 2026)
Dieses Dokument beschreibt das spezifische Bewertungssystem für **Pferdeprüfungen** (Jungpferde) und *
*Stilspringprüfungen**, da diese über die einfache Ergebniserfassung hinausgehen und automatisierte Berechnungslogik im
System erfordern.
---
## 1. Dressurpferdeprüfungen (§ 103 & § 104 B-Teil)
Dressurpferdeprüfungen dienen der Beurteilung der Ausbildung und Qualität junger Pferde. Anstelle von Einzelnoten pro
Lektion werden qualitative Merkmale bewertet.
### 1.1 Bewertungsskala (0 10)
Es werden Noten in Zehntelschritten (z.B. 7,4) für folgende fünf Kriterien vergeben:
1. **Schritt:** Takt, Fleiß und Raumgriff.
2. **Trab:** Schwung, Elastizität und Ausdruck.
3. **Galopp:** Durchsprung, Bergauftendenz und Balance.
4. **Durchlässigkeit:** Rittigkeit, Gehorsam und Akzeptanz der Hilfen.
5. **Gesamteindruck:** Perspektive des Pferdes als Dressurpferd.
### 1.2 Ergebniserfassung & Berechnung
* **Gemeinsames Richten (RV A):** Die Richtergruppe vergibt eine gemeinsame Note pro Kriterium. Die Endnote ist das
arithmetische Mittel dieser fünf Noten.
* **Abzüge für Verreiten:**
*
1. Mal: - 0,1 Punkte vom Gesamtergebnis.
*
2. Mal: - 0,2 Punkte vom Gesamtergebnis.
*
3. Mal: Ausschluss.
---
## 2. Springpferdeprüfungen (§ 203 & § 204 B-Teil)
Hier steht die Springmanier und Rittigkeit im Vordergrund. Das Ergebnis basiert auf einer Grundnote, von der Fehler
abgezogen werden.
### 2.1 Grundnote (0 10)
Die Richter vergeben eine Wertnote für:
* Springmanier (Beintechnik, Bascule).
* Rittigkeit und Einhalten des korrekten Tempos.
### 2.2 Abzugslogik (Punkteabzug von der Grundnote)
| Fehlerart | Abzug (Punkte) |
|:-----------------------------------|:--------------------------------------------|
| **Hindernisfehler (Abwurf)** | - 0,5 |
| **Erster Ungehorsam (Verweigern)** | - 0,5 |
| **Zweiter Ungehorsam** | - 1,0 |
| **Dritter Ungehorsam** | Ausschluss |
| **Zeitfehler** | - 0,1 pro angef. Sekunde Zeitüberschreitung |
| **Sturz (Reiter/Pferd)** | Ausschluss |
### 2.3 Besonderheit: „Ohne Bewertung“ (§ 204 Abs. 4.2)
* Beträgt die **Endnote 4,9 oder weniger** (nach Abzügen), wird das Pferd als **„ohne Bewertung“** (o.B.) geführt.
* **Reihung:** Diese Teilnehmer werden in der Ergebnisliste hinter den platzierten/bewerteten Reitern, aber vor den
Ausgeschiedenen gereiht.
---
## 3. Stilspringprüfungen (§ 204 Abs. 4)
Stilspringprüfungen bewerten primär den Reiter (Sitz, Einwirkung, Wegführung).
### 3.1 Kriterien
* Sitz und Einwirkung des Reiters.
* Wahl des korrekten Tempos und harmonische Bewältigung der Aufgabe.
### 3.2 Abzüge & Idealzeit
* Die **Abzugslogik** ist identisch zu den Springpferdeprüfungen (siehe 2.2).
* **Idealzeit (§ 204 Abs. 4.3):** Bei Punktegleichheit entscheidet die geringere Zeitdifferenz zur Idealzeit.
* **Berechnung Idealzeit:** Erlaubte Zeit (EZ) minus 10%.
---
## 4. System-Anforderungen (Meldestelle)
1. **Eingabemaske:** Das UI muss für diese Prüfungsarten dedizierte Felder für die Kriterien (Dressur) bzw. die
Grundnote und die Fehler (Springen) bieten.
2. **Echtzeit-Berechnung:** Die Endnote muss während der Eingabe automatisch berechnet werden.
3. **Validierung:** Warnung, wenn eine Note > 10 eingegeben wird.
4. **Ergebnisliste:** Korrekte Kennzeichnung von „o.B.“ Ergebnissen und deren spezifische Reihung gemäß ÖTO.
@@ -0,0 +1,79 @@
# 🏇 Reiter-Prüfungen (Dressur & Stilspringen)
In diesem Dokument werden die Stammdaten und Regelwerke für Prüfungen aufbereitet, bei denen der Fokus primär auf der
Einwirkung und dem Sitz des Reiters liegt. Dies ist besonders relevant für Nachwuchsbewerbe und C-NEU Turniere.
## 1. Dressurreiterprüfungen (§ 103 Abs. 5 ÖTO)
Im Gegensatz zur Standard-Dressurprüfung, bei der die Durchlässigkeit und Gangqualität des Pferdes im Vordergrund
stehen, wird hier der Reiter bewertet.
### 1.1 Beurteilungskriterien
Die Bewertung erfolgt nach **Richtverfahren A (Gemeinsames Richten)** mit einer Wertnote von 0 bis 10 (eine Dezimale
zulässig).
* **Sitz:** Korrektheit, Geschmeidigkeit, Balance.
* **Einwirkung:** Effektivität der Hilfengebung, Harmonie mit dem Pferd.
* **Hufschlaglinien:** Exakte Ausführung der Wendungen und Linien.
* **Übergänge:** Fließende und korrekte Übergänge zwischen den Gangarten.
* **Tempo:** Einhalten gleichmäßiger und unterscheidbarer Tempi.
### 1.2 Besonderheiten für C-NEU
* Oft als **lizenzfreie Bewerbe (LF)** ausgeschrieben.
* Viereck-Maße: Meist 20x40m.
* Ausrüstung: Trense verpflichtend (Kandare in Reiterprüfungen nicht üblich).
---
## 2. Stilspringprüfungen (§ 204 Abs. 2 ÖTO)
Stilspringprüfungen dienen der Überprüfung der reiterlichen Ausbildung im Parcours.
### 2.1 Bewertungslogik
Es wird mit einer **Grundnote (0-10)** gestartet, von der Fehler (Abwürfe/Ungehorsam) und Stil-Mängel abgezogen werden.
| Vorfall | Abzug |
|:-------------------------------|:--------------------------------------------------------------|
| **Hindernisfehler (Abwurf)** | - 0,5 Punkte |
| **1. Ungehorsam (Verweigern)** | - 0,5 Punkte |
| **2. Ungehorsam** | - 1,0 Punkte |
| **3. Ungehorsam** | **Ausschluss** |
| **Sturz (Reiter/Pferd)** | **Ausschluss** |
| **Zeitfehler** | - 0,1 Punkte pro angefangene Sekunde (bei Zeitüberschreitung) |
### 2.2 Reihung bei Punktgleichheit
Bei gleicher Endnote im Stilspringen entscheidet laut ÖTO:
1. Die bessere **Stilnote** (bevor Abzüge für Hindernisfehler erfolgten).
2. Bei weiterhin gleicher Note: Ex aequo Platzierung (oder Stechen, falls ausgeschrieben).
---
## 3. System-Anforderungen für die Meldestelle
### 3.1 Ergebniserfassung (UI)
* **Dressurreiter:** Einfaches Eingabefeld für die Gesamtnote (z.B. 7,2).
* **Stilspringen:** Maske mit Grundnote und Auswahlfeldern für Fehler (Abwürfe, Verweigerungen), um die Endnote
automatisch zu berechnen.
### 3.2 Validierung
* Prüfung der **Lizenzklasse**: Stilspringprüfungen sind oft auf Reiter mit niedrigeren Lizenzen (R1) oder ohne Lizenz
beschränkt.
* **Altersklassen**: Kombination mit Jugend/Junioren-Bewerben prüfen.
---
## 4. ZNS-Mapping
Reiterprüfungen werden in den ZNS-Dateien (`*.dat`) meist über spezifische Prüfungsart-Codes identifiziert:
* `DR` -> Dressurreiterprüfung
* `ST` -> Stilspringprüfung
Diese Codes müssen im `zns-parser` korrekt auf die oben beschriebene Logik gemappt werden.
+140
View File
@@ -0,0 +1,140 @@
# Strategische Roadmap: Masterdata (Stammdaten) 2026 H1H2
🏗️ [Lead Architect]
## Leitbild und Scope
- Ziel: ÖTO-konforme, offline-fähige Stammdaten-Plattform für Dressur & Springen als SelfContained System mit eigener
DB, klaren APIs und einem wiederverwendbaren Frontend-Feature (Compose MPP).
- Ergebnis: Lesekanal (REST-API), Schreibkanal (ZNS-Ingestion), datengesteuerte Regel-Engine (Versionierung von
ÖTO-Regeln), vollständige Observability und Betrieb.
- Nicht-Ziele (Phase 1): FEI-Integration, weitere Sparten (VS, Western), komplexe Serien-/Cup-Reglements.
---
## Phasenüberblick und Meilensteine
### 1) Foundation & Governance (WK 12)
- Architektur-Entscheide (ADRs) finalisieren: Database-per-Service, Rule-Engine als Datenmodell, Importer als Worker im
Masterdata-SCS.
- Versionierungs-Strategie: `valid_from/valid_to` auf Regel-Datensätzen; „Regel-Set 2026“ als Seed.
- Security/Cross-Cutting: API-Schlüssel/Service-Tokens, CORS, Ratelimits, Idempotency-Policies dokumentieren und
aktivieren.
- Deliverables:
- [x] ADR-Set im Repo (Rules, DB, Import, API) → ADR-0017, ADR-0018, ADR-0019
- Operative Runbooks (Backup/Restore, Re-Import, Rollback)
### 2) Datenmodell & Persistenz (WK 24)
- Tabellenkatalog vervollständigen und migrieren (Exposed + Flyway/Liquibase): Reiter, Pferde, Vereine, Funktionäre,
Altersklassen, Lizenzen, Turnierklassen, Gebührenordnung, Richtverfahren, Regelkonfiguration.
- Indizes/Keys: Eindeutige Schlüssel gemäß ZNS (Satz-/Lizenznummern), Suchindizes für Name/Teilstrings.
- Deliverables:
- Migrationsskripte v1.0
- Repository-Impls mit Upsert-Semantik
- Test-Datasets (Mini-ZNS, ÖTO-Seeds)
### 3) Rule-Engine (WK 46)
- Domänenlogik kapseln: Altersklassenrechner, Lizenz-zu-Klasse-Matrix, Abteilungsregeln,
Pferde-/Reiterprüfungs-Scoring (Stilspringen/Dressurpferde), Gebühren-Lookups.
- Datengesteuerte Konfiguration: Tabellen „RegulationConfig“, „LicenseMatrix“, „ClassDefinitions“ mit Versionen.
- Deliverables:
- UseCases im `masterdata-common` (pure Kotlin) + Unit-Tests
- Admin-Seed für „ÖTO 2026“
### 4) ZNS-Ingestion als Worker (WK 57)
- Import-Pipeline (ASCII CP850) als Masterdata-Submodul/Worker: Validierung, Deduplikation (Idempotenz),
Fehlerreporting.
- Re-Import & Delta-Regeln; Konfliktstrategien (last-write-wins vs. checksumbased skip).
- Deliverables:
- Batch-Job + CLI/HTTP Trigger
- Import-Report (persistiert + JSON-Export)
### 5) API-Fassade (WK 68)
- Read-APIs (v1):
- GET /reiter?search=…
- GET /horses?search=…
- GET /vereine?bundesland=…
- GET /altersklassen, /turnierklassen, /lizenzmatrix, /richtverfahren, /gebuehrenordnung
- Admin/Tech-APIs: GET /rulesets, GET /health, GET /metrics
- DTOs mit Kotlinx Serialization; Paginierung & ETags.
- Deliverables: OpenAPI 3 Spec, Contract-Tests
### 6) Frontend-Feature „masterdata“ (WK 79)
- KMP-Feature-Modul: Such-/Detail-Views für Reiter, Pferde, Vereine; Readonly Rule-Explorer.
- State-Management, OfflineCache (Local DB) für Desktop; Fehler-/Konfliktanzeigen beim Import.
- Deliverables: Integrations-Demo in Desktop-Shell, UI-Snippets für Web-Shell
### 7) Observability & Operations (WK 59, parallel)
- Logging-Konzepte (strukturierte Logs), Metriken (Importdauer, Records/s, API Latenzen), Tracing (optional).
- Dashboards/Alerts: Import-Fehlerquote, API 5xx, DBWachstum, Regel-Set-Mismatch.
- Backups/Restore-Runbooks, DR-Test.
### 8) Quality Gate & GoLive (WK 910)
- Test-Strategie:
- Unit: Rule-Engine, UseCases
- Integration: Repos + API + Importer (Mini-ZNS)
- EndtoEnd: Desktop-Feature → API → DB
- Security Review, Performance Smoke (100k Reiter, 50k Pferde, 2k Vereine), Data Quality Checks.
- GoLive Checklist und Staged Rollout.
---
## Verantwortlichkeiten (Agents)
- 🏗️ Lead Architect: ADRs, Architektur-Governance, Phasenabnahme
- 👷 Backend Developer: DB/Repositories, UseCases, API, Importer
- 🎨 Frontend Expert: KMP-Feature, Offline-Cache, API-Integration
- 🐧 DevOps Engineer: CI/CD, Deploy, Observability, Backups
- 🧐 QA Specialist: Test-Strategie, Abdeckung, E2E
- 📜 Rulebook Expert: Daten-Seeds, Regel-Validierung, Review der Matrix
- 🧹 Curator: Docs-as-Code, Changelogs, Runbooks, Session Logs
---
## Architekturprinzipien (Wartbarkeit)
- Hexagonale Architektur strikt einhalten; UseCases sind framework-frei und testbar.
- Regeln im Datenmodell versionieren; Code nutzt nur „aktives Regel-Set“ je Turnier/Datum.
- Importer ist ein Worker des Masterdata-SCS (Schreibkanal), API ist der Lesekanal.
- Idempotenz konsequent: Upserts, ETags, Import-Footprint (checksum, source_id, imported_at).
---
## Abhängigkeiten & Risiken
- Abhängigkeiten: Postgres-Verfügbarkeit, ZNS-Dateiqualität, Identity (Token) für gesicherte Admin-Routen, Desktop-App
Shell.
- Risiken & Gegenmaßnahmen:
- Regeländerungen kurz vor Saisonstart → Versionierte Rulesets + Blue/Green Umschaltung per Config.
- Datenqualität ZNS (Inkonsistenzen) → strikte Validierung + Fehlerreport + manuelle Korrekturrouten (später).
- Performance bei Erstimport → Batchgrößen, Indizes, COPY/Batch-Insert, Profiling.
- ScopeCreep (weitere Sparten) → Phasen-Governance, ADRs, FeatureFlags.
---
## Erfolgskriterien (Messbar)
- T0 Import: Komplettes ZNS-Paket < 10 Minuten, Fehlerrate < 0,5% pro Datei, 100% idempotent.
- API: P95 Latenz < 150 ms bei 500 RPS Burst (ReadOnly Endpunkte), Fehlerquote < 0,1%.
- Rule-Engine: 100% Übereinstimmung mit dokumentierten Beispielen (Golden Files) und ÖTO-Referenzen.
- Observability: 4 zentrale Dashboards + 6 Alarm-Regeln aktiv; Backup/Restore in < 30 Minuten validiert.
---
## Nächste konkrete Schritte (2Wochen SprintPlan)
1. [x] ADRs für ImporterEinbettung, RuleVersionierung, API-Schichten abschließen (🏗️)
2. Exposed-Tabellen vervollständigen und in `SchemaUtils.create`/Migrationen registrieren (👷)
3. UseCases: Altersklasse, LizenzMatrix, AbteilungsRegeln inkl. UnitTests (👷🧐)
4. ZNSImporter an Repositories anbinden, Idempotenz-Checks ergänzen, MiniZNS Testlauf (👷🧐)
5. API v1 Endpunkte + OpenAPI, ContractTests (👷🧐)
6. Observability-Grundlagen (Metriken + Dashboards) (🐧)
7. Curator: Docs aktualisieren, Runbooks und Changelogs pflegen (🧹)
@@ -0,0 +1,82 @@
# 📜 Turnier-Sparten, Klassen & Startberechtigungen
Diese Dokumentation bietet eine detaillierte Übersicht über die Klassen der Hauptsparten **Dressur (CDN)** und *
*Springen (CSN)** sowie die jeweiligen Startberechtigungen basierend auf der ÖTO 2026.
---
## 1. Sparte Springen (CSN)
### 1.1 Klasseneinteilung (Großpferde)
Die Klassen richten sich primär nach der maximalen Hindernishöhe (§ 200 B-Teil).
| Klasse | Bezeichnung | Höhe (cm) | Startberechtigung (Lizenz) |
|:--------|:--------------------|:----------|:----------------------------|
| **E0** | Einsteiger | 60 95 | LZF (Startkarte/Reiterpass) |
| **A** | Leicht | 105 110 | R1 oder höher |
| **L** | Mittelleicht | 115 120 | R1 oder höher |
| **LM** | Leicht-Mittelschwer | 125 130 | R2 oder höher |
| **M** | Mittelschwer | 135 | R3 oder höher |
| **S*** | Schwer | 140 145 | R3 oder höher |
| **S**** | Schwer (GP) | 150 160 | R4 |
### 1.2 Besonderheiten CSN-C NEU
* **Höhen:** 60 cm bis 115 cm.
* **Registrierung:** Pferde bis 90 cm müssen nicht beim OEPS registriert sein.
* **Ergebniserfassung:** Erst ab 95 cm (für Lizenzerhalt) bzw. ab 105 cm (für Höherreihung).
* **Startlimit:** Ein Pferd darf maximal 3-mal pro Tag starten.
### 1.3 Abteilungsbildung (Pflicht)
* **Bis 95 cm:**
1. Abt.: Ohne Lizenz (LZF)
2. Abt.: R1-Reiter
3. Abt.: R2-Reiter und höher
* **Ab 100 cm:**
1. Abt.: R1-Reiter
2. Abt.: R2-Reiter und höher
---
## 2. Sparte Dressur (CDN)
### 2.1 Klasseneinteilung & Aufgabenniveau
Die Dressur wird nach offiziellen Aufgabenheften geritten (§ 100 B-Teil).
| Klasse | Niveau | Erforderliche Lizenz | Besonderheiten |
|:-------|:--------------------|:---------------------|:-------------------------------------------|
| **LF** | Lizenzfrei | LZF (Reiterpass) | First Ridden, Führzügel, Aufgaben R1/Nadel |
| **A** | Leicht | R1 / RD1 oder höher | Grundausbildung |
| **L** | Mittelleicht | R1 / RD1 oder höher | Beginnende Versammlung |
| **LM** | Leicht-Mittelschwer | R2 / RD2 oder höher | Wahlweise Trense/Kandare |
| **M** | Mittelschwer | R2 / RD2 oder höher | Kandarenpflicht |
| **S** | Schwer | R3 / RD3 oder höher | St. Georg bis Grand Prix |
### 2.2 Besonderheiten CDN-C NEU
* **Ausschreibbare Bewerbe:** Kl. A & L, lizenzfreie Aufgaben, Reiterpass/Reiternadel.
* **Einschränkung:** In Reiterpass/Reiternadel-Aufgaben sind Lizenzinhaber **nicht** startberechtigt.
* **Ergebniserfassung:** Ergebnisse in Kl. A und L werden für Lizenzen gewertet. Reiterpass-Aufgaben werden nicht
erfasst.
---
## 3. Zusammenfassende Startberechtigungs-Matrix
| Lizenzstufe | Springen (max. Klasse) | Dressur (max. Klasse) |
|:-------------|:-----------------------|:----------------------|
| **LZF** (RP) | E0 (95 cm) | LF / lizenzfrei |
| **R1** | L (120 cm) | L |
| **RD1** | E0 (95 cm) | L |
| **R2** | LM (130 cm) | M |
| **RD2** | E0 (95 cm) | M |
| **R3** | S* (145 cm) | S |
| **RD3** | E0 (95 cm) | S |
| **R4** | S**** (160 cm) | S |
---
> 📜 **Rulebook Expert Hinweis:** Diese Matrix dient der automatischen Validierung von Nennungen. Bei Rasse-Spezifischen
> Bewerben (Haflinger/Noriker) können Sonderregelungen gemäß `REITER_LIZENZEN.md` greifen.
@@ -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)
}
}
@@ -37,7 +37,12 @@ class MasterdataDatabaseConfiguration {
ReiterTable,
HorseTable,
VereinTable,
FunktionaerTable
FunktionaerTable,
TurnierklasseTable,
LicenseTable,
RichtverfahrenTable,
GebuehrTable,
RegulationConfigTable
)
log.info("Masterdata database schema initialized successfully")
}
@@ -77,7 +82,12 @@ class MasterdataTestDatabaseConfiguration {
ReiterTable,
HorseTable,
VereinTable,
FunktionaerTable
FunktionaerTable,
TurnierklasseTable,
LicenseTable,
RichtverfahrenTable,
GebuehrTable,
RegulationConfigTable
)
log.info("Test masterdata database schema initialized successfully")
}
@@ -0,0 +1,148 @@
-- V005: Create Turnierklasse, License, Richtverfahren, Gebuehr, RegulationConfig Tables
-- Basierend auf ÖTO 2026 und ADR-0018
CREATE TABLE IF NOT EXISTS turnierklasse
(
turnierklasse_id
UUID
PRIMARY
KEY,
sparte
VARCHAR
(
20
) NOT NULL,
code VARCHAR
(
10
) NOT NULL,
bezeichnung VARCHAR
(
100
) NOT NULL,
max_hoehe INTEGER,
aufgaben_niveau VARCHAR
(
100
),
valid_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
valid_to TIMESTAMP WITH TIME ZONE,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_turnierklasse_sparte_code ON turnierklasse (sparte, code);
CREATE TABLE IF NOT EXISTS license_matrix
(
license_id
UUID
PRIMARY
KEY,
sparte
VARCHAR
(
20
) NOT NULL,
lizenz_klasse VARCHAR
(
20
) NOT NULL,
max_turnierklasse_code VARCHAR
(
10
) NOT NULL,
valid_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
valid_to TIMESTAMP WITH TIME ZONE,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_license_sparte_klasse ON license_matrix (sparte, lizenz_klasse);
CREATE TABLE IF NOT EXISTS richtverfahren
(
richtverfahren_id
UUID
PRIMARY
KEY,
sparte
VARCHAR
(
20
) NOT NULL,
code VARCHAR
(
10
) NOT NULL,
bezeichnung VARCHAR
(
200
) NOT NULL,
beschreibung TEXT,
valid_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
valid_to TIMESTAMP WITH TIME ZONE,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_richtverfahren_sparte_code ON richtverfahren (sparte, code);
CREATE TABLE IF NOT EXISTS gebuehr
(
gebuehr_id
UUID
PRIMARY
KEY,
bezeichnung
VARCHAR
(
200
) NOT NULL,
typ VARCHAR
(
50
) NOT NULL,
betrag DECIMAL
(
10,
2
) NOT NULL,
waehrung VARCHAR
(
3
) NOT NULL DEFAULT 'EUR',
valid_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
valid_to TIMESTAMP WITH TIME ZONE,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS regulation_config
(
config_id
UUID
PRIMARY
KEY,
config_key
VARCHAR
(
100
) NOT NULL,
config_value TEXT NOT NULL,
beschreibung VARCHAR
(
255
),
valid_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
valid_to TIMESTAMP WITH TIME ZONE,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_regulation_config_key ON regulation_config (config_key);
@@ -0,0 +1,248 @@
-- V006: Missing Core Masterdata Tables (Reiter, Horse, Verein, Funktionaer)
-- Diese Tabellen wurden in V1 (Initial) teilweise unter anderen Namen angelegt (dom_verein, dom_person).
-- Um konsistent mit den Exposed-Tabellen (ReiterTable, HorseTable, etc.) zu sein, legen wir sie hier final an.
CREATE TABLE IF NOT EXISTS reiter
(
reiter_id
UUID
PRIMARY
KEY,
person_id
UUID,
satznummer
VARCHAR
(
10
) UNIQUE NOT NULL,
lizenz_nummer VARCHAR
(
20
),
lizenz_klasse VARCHAR
(
20
) NOT NULL,
startkart_aktiv BOOLEAN NOT NULL DEFAULT false,
startkart_saison INTEGER,
fei_id VARCHAR
(
20
),
nation VARCHAR
(
3
),
nachname VARCHAR
(
100
) NOT NULL,
vorname VARCHAR
(
100
) NOT NULL,
geburtsdatum DATE,
vereins_nummer VARCHAR
(
10
),
vereins_name VARCHAR
(
200
),
ist_gastreiter BOOLEAN NOT NULL DEFAULT false,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
daten_quelle VARCHAR
(
50
) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_reiter_satznummer ON reiter (satznummer);
CREATE INDEX idx_reiter_name ON reiter (nachname, vorname);
CREATE TABLE IF NOT EXISTS horse
(
horse_id
UUID
PRIMARY
KEY,
pferde_name
VARCHAR
(
200
) NOT NULL,
geschlecht VARCHAR
(
20
) NOT NULL,
geburtsdatum DATE,
rasse VARCHAR
(
100
),
farbe VARCHAR
(
100
),
besitzer_id UUID,
verantwortliche_person_id UUID,
zuechter_name VARCHAR
(
200
),
zuchtbuch_nummer VARCHAR
(
50
),
lebensnummer VARCHAR
(
50
),
chip_nummer VARCHAR
(
50
),
pass_nummer VARCHAR
(
50
),
oeps_nummer VARCHAR
(
50
),
fei_nummer VARCHAR
(
50
),
vater_name VARCHAR
(
200
),
mutter_name VARCHAR
(
200
),
mutter_vater_name VARCHAR
(
200
),
stockmass INTEGER,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
bemerkungen TEXT,
daten_quelle VARCHAR
(
50
) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_horse_lebensnummer ON horse (lebensnummer);
CREATE INDEX idx_horse_name ON horse (pferde_name);
CREATE TABLE IF NOT EXISTS verein
(
verein_id
UUID
PRIMARY
KEY,
vereins_nummer
VARCHAR
(
10
) UNIQUE NOT NULL,
name VARCHAR
(
200
) NOT NULL,
kurzname VARCHAR
(
100
),
bundesland VARCHAR
(
100
),
ort VARCHAR
(
100
),
plz VARCHAR
(
10
),
strasse VARCHAR
(
200
),
email VARCHAR
(
200
),
telefon VARCHAR
(
50
),
website VARCHAR
(
255
),
oeps_region_nummer VARCHAR
(
10
),
ist_veranstalter BOOLEAN NOT NULL DEFAULT false,
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
bemerkungen TEXT,
daten_quelle VARCHAR
(
50
) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS funktionaer
(
funktionaer_id
UUID
PRIMARY
KEY,
richter_nummer
VARCHAR
(
10
) UNIQUE,
vorname VARCHAR
(
100
) NOT NULL,
nachname VARCHAR
(
100
) NOT NULL,
geburtsdatum DATE,
email VARCHAR
(
200
),
telefon VARCHAR
(
50
),
vereins_nummer VARCHAR
(
10
),
ist_aktiv BOOLEAN NOT NULL DEFAULT true,
bemerkungen TEXT,
daten_quelle VARCHAR
(
50
) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);