diff --git a/backend/services/masterdata/README.md b/backend/services/masterdata/README.md index 39001f12..c6091dcd 100644 --- a/backend/services/masterdata/README.md +++ b/backend/services/masterdata/README.md @@ -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 diff --git a/backend/services/masterdata/docs/FUNKTIONAERE_QUALIFIKATIONEN.md b/backend/services/masterdata/docs/FUNKTIONAERE_QUALIFIKATIONEN.md new file mode 100644 index 00000000..22fcd889 --- /dev/null +++ b/backend/services/masterdata/docs/FUNKTIONAERE_QUALIFIKATIONEN.md @@ -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. diff --git a/backend/services/masterdata/docs/GEBUEHRENORDNUNG.md b/backend/services/masterdata/docs/GEBUEHRENORDNUNG.md new file mode 100644 index 00000000..46ae130c --- /dev/null +++ b/backend/services/masterdata/docs/GEBUEHRENORDNUNG.md @@ -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. diff --git a/backend/services/masterdata/docs/OETO_STAMMDATEN.md b/backend/services/masterdata/docs/OETO_STAMMDATEN.md index e441cc31..99df89f4 100644 --- a/backend/services/masterdata/docs/OETO_STAMMDATEN.md +++ b/backend/services/masterdata/docs/OETO_STAMMDATEN.md @@ -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) diff --git a/backend/services/masterdata/docs/PFERDEPRUEFUNGEN.md b/backend/services/masterdata/docs/PFERDEPRUEFUNGEN.md new file mode 100644 index 00000000..b73e8fd1 --- /dev/null +++ b/backend/services/masterdata/docs/PFERDEPRUEFUNGEN.md @@ -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). diff --git a/backend/services/masterdata/docs/PFERDEPRUEFUNGEN_BEWERTUNG.md b/backend/services/masterdata/docs/PFERDEPRUEFUNGEN_BEWERTUNG.md new file mode 100644 index 00000000..729d8254 --- /dev/null +++ b/backend/services/masterdata/docs/PFERDEPRUEFUNGEN_BEWERTUNG.md @@ -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. diff --git a/backend/services/masterdata/docs/REITER_PRUEFUNGEN.md b/backend/services/masterdata/docs/REITER_PRUEFUNGEN.md new file mode 100644 index 00000000..84e55ba8 --- /dev/null +++ b/backend/services/masterdata/docs/REITER_PRUEFUNGEN.md @@ -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. diff --git a/backend/services/masterdata/docs/ROADMAP.md b/backend/services/masterdata/docs/ROADMAP.md new file mode 100644 index 00000000..7a2c8fa7 --- /dev/null +++ b/backend/services/masterdata/docs/ROADMAP.md @@ -0,0 +1,140 @@ +# Strategische Roadmap: Masterdata (Stammdaten) 2026 H1–H2 + +🏗️ [Lead Architect] + +## Leitbild und Scope + +- Ziel: ÖTO-konforme, offline-fähige Stammdaten-Plattform für Dressur & Springen als Self‑Contained 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 1–2) + +- 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 2–4) + +- 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 4–6) + +- 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 5–7) + +- Import-Pipeline (ASCII CP850) als Masterdata-Submodul/Worker: Validierung, Deduplikation (Idempotenz), + Fehlerreporting. +- Re-Import & Delta-Regeln; Konfliktstrategien (last-write-wins vs. checksum‑based skip). +- Deliverables: + - Batch-Job + CLI/HTTP Trigger + - Import-Report (persistiert + JSON-Export) + +### 5) API-Fassade (WK 6–8) + +- 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 7–9) + +- KMP-Feature-Modul: Such-/Detail-Views für Reiter, Pferde, Vereine; Read‑only Rule-Explorer. +- State-Management, Offline‑Cache (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 5–9, parallel) + +- Logging-Konzepte (strukturierte Logs), Metriken (Importdauer, Records/s, API Latenzen), Tracing (optional). +- Dashboards/Alerts: Import-Fehlerquote, API 5xx, DB‑Wachstum, Regel-Set-Mismatch. +- Backups/Restore-Runbooks, DR-Test. + +### 8) Quality Gate & Go‑Live (WK 9–10) + +- Test-Strategie: + - Unit: Rule-Engine, UseCases + - Integration: Repos + API + Importer (Mini-ZNS) + - End‑to‑End: Desktop-Feature → API → DB +- Security Review, Performance Smoke (100k Reiter, 50k Pferde, 2k Vereine), Data Quality Checks. +- Go‑Live 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. + - Scope‑Creep (weitere Sparten) → Phasen-Governance, ADRs, Feature‑Flags. + +--- + +## 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 (Read‑Only 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 (2‑Wochen Sprint‑Plan) + +1. [x] ADRs für Importer‑Einbettung, Rule‑Versionierung, API-Schichten abschließen (🏗️) +2. Exposed-Tabellen vervollständigen und in `SchemaUtils.create`/Migrationen registrieren (👷) +3. UseCases: Altersklasse, Lizenz‑Matrix, Abteilungs‑Regeln inkl. Unit‑Tests (👷🧐) +4. ZNS‑Importer an Repositories anbinden, Idempotenz-Checks ergänzen, Mini‑ZNS Testlauf (👷🧐) +5. API v1 Endpunkte + OpenAPI, Contract‑Tests (👷🧐) +6. Observability-Grundlagen (Metriken + Dashboards) (🐧) +7. Curator: Docs aktualisieren, Runbooks und Changelogs pflegen (🧹) diff --git a/backend/services/masterdata/docs/TURNIER_KLASSEN.md b/backend/services/masterdata/docs/TURNIER_KLASSEN.md new file mode 100644 index 00000000..c119f2a4 --- /dev/null +++ b/backend/services/masterdata/docs/TURNIER_KLASSEN.md @@ -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. diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/GebuehrTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/GebuehrTable.kt new file mode 100644 index 00000000..6bb2e6fc --- /dev/null +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/GebuehrTable.kt @@ -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) +} diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseRepositoryImpl.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseRepositoryImpl.kt index 94e512da..8aad03fb 100644 --- a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseRepositoryImpl.kt +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseRepositoryImpl.kt @@ -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 diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseTable.kt index 889ad672..b61aafc0 100644 --- a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseTable.kt +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/HorseTable.kt @@ -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) - } } diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LicenseTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LicenseTable.kt new file mode 100644 index 00000000..82b620b4 --- /dev/null +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LicenseTable.kt @@ -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) + } +} diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RegulationConfigTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RegulationConfigTable.kt new file mode 100644 index 00000000..485a9890 --- /dev/null +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RegulationConfigTable.kt @@ -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) + } +} diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RichtverfahrenTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RichtverfahrenTable.kt new file mode 100644 index 00000000..e8d05b42 --- /dev/null +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/RichtverfahrenTable.kt @@ -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) + } +} diff --git a/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/TurnierklasseTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/TurnierklasseTable.kt new file mode 100644 index 00000000..a6117e35 --- /dev/null +++ b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/TurnierklasseTable.kt @@ -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) + } +} diff --git a/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt b/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt index 4ea33231..9ab6a4e1 100644 --- a/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt +++ b/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt @@ -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") } diff --git a/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V005__Create_Rule_Tables.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V005__Create_Rule_Tables.sql new file mode 100644 index 00000000..1d29cb37 --- /dev/null +++ b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V005__Create_Rule_Tables.sql @@ -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); diff --git a/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V006__Create_Core_Tables.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V006__Create_Core_Tables.sql new file mode 100644 index 00000000..2e51ea23 --- /dev/null +++ b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V006__Create_Core_Tables.sql @@ -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 + ); diff --git a/docs/01_Architecture/MASTER_ROADMAP.md b/docs/01_Architecture/MASTER_ROADMAP.md index d6d621d9..1d98669c 100644 --- a/docs/01_Architecture/MASTER_ROADMAP.md +++ b/docs/01_Architecture/MASTER_ROADMAP.md @@ -203,6 +203,9 @@ und über definierte Schnittstellen kommunizieren. | 8 | 6 Bounded Contexts: Mapping & Aggregate Roots | ✅ | ADR-0014 | | 9 | Context Map: Integration Patterns & ACL-Strategie | ✅ | ADR-0015 | | 10 | API-Design & ACL: Ports, DTOs, REST-Endpunkte, Domain Events | ✅ | ADR-0016 | +| 11 | Masterdata: Importer-Einbettung als Worker | ✅ | ADR-0017 | +| 12 | Masterdata: Rule-Versionierung (Regulation-as-Data) | ✅ | ADR-0018 | +| 13 | Masterdata: API-Schichten (REST vs. Ingestion) | ✅ | ADR-0019 | --- diff --git a/docs/01_Architecture/adr/0017-masterdata-importer-worker-de.md b/docs/01_Architecture/adr/0017-masterdata-importer-worker-de.md new file mode 100644 index 00000000..f1477050 --- /dev/null +++ b/docs/01_Architecture/adr/0017-masterdata-importer-worker-de.md @@ -0,0 +1,58 @@ +--- +type: ADR +status: AKZEPTIERT +owner: Lead Architect +date: 2026-03-30 +--- + +# ADR-0017: Einbettung des ZNS-Importers als Worker im Masterdata-SCS + +## Status + +Akzeptiert + +## Kontext + +Das Zentrale Nennungs-System (ZNS) liefert Stammdaten (Reiter, Pferde, Vereine, Funktionäre) in Form von ASCII-Dateien ( +CP850). Diese Daten müssen regelmäßig importiert und aktualisiert werden. +Bisher gab es die Überlegung, den Importer als eigenständigen Dienst oder als Teil des Backends zu betreiben. Da die +Stammdaten jedoch das primäre Domänenmodell des `masterdata`-SCS sind, stellt sich die Frage nach der optimalen +architektonischen Einbettung. + +## Entscheidung + +Der ZNS-Importer wird als **dedizierter Worker-Thread/Service innerhalb des Masterdata-SCS** implementiert. + +Details: + +1. **Modul-Struktur**: Der `core:zns-parser` bleibt ein KMP-Modul für die reine Dateianalyse. Die Import-Logik (Mapping + auf Domänen-Entitäten, Upserts in die DB) wird im `masterdata`-SCS angesiedelt. +2. **Ausführung**: Der Import läuft asynchron als Hintergrund-Task (Worker), um die API-Reaktionszeit nicht zu + beeinträchtigen. +3. **Trigger**: Der Import kann über einen REST-Endpunkt (für Datei-Uploads) oder manuell via CLI/Trigger gestartet + werden. +4. **Schreibkanal**: Der Importer ist der primäre Schreibkanal für Stammdaten im System. Direkte API-Schreibzugriffe auf + Stammdaten sind in Phase 1 nicht vorgesehen (Read-Only API für externe Konsumenten). + +## Konsequenzen + +- **Positiv**: Starke Kohäsion, da die Datenhoheit und die Importlogik im selben SCS liegen. +- **Positiv**: Vereinfachte Persistenz, da der Worker direkt auf die Masterdata-DB zugreifen kann (kein + Remote-API-Overhead). +- **Negativ**: Ressourcenverbrauch des Workers (CPU/RAM beim Parsen großer Dateien) teilt sich die Ressourcen mit der + REST-API innerhalb des Containers. Dies muss über Limits (Docker/K8s) oder Task-Scheduling gesteuert werden. +- **Neutral**: Erfordert eine robuste Idempotenz-Logik, da Importe wiederholbar sein müssen (Checksum-Checks, + Upsert-Semantik). + +## Betrachtete Alternativen + +- **Eigenständiger Microservice**: Wurde verworfen, um die Anzahl der zu betreibenden Dienste gering zu halten und " + Database-per-Service" nicht durch geteilte Datenbankzugriffe zu verletzen (oder teure API-Synchronisation zu + benötigen). +- **Integration in die GUI (Client-seitig)**: Verworfen, da die Datenhoheit im Server liegen muss und große Importe ( + 100k+ Records) im Hintergrund auf dem Server stabiler laufen. + +## Referenzen + +- [Roadmap_ZNS_Importer.md](../../../docs/01_Architecture/Roadmap_ZNS_Importer.md) +- [ROADMAP.md](../ROADMAP.md) diff --git a/docs/01_Architecture/adr/0018-rule-versioning-strategy-de.md b/docs/01_Architecture/adr/0018-rule-versioning-strategy-de.md new file mode 100644 index 00000000..2e6fd40e --- /dev/null +++ b/docs/01_Architecture/adr/0018-rule-versioning-strategy-de.md @@ -0,0 +1,53 @@ +--- +type: ADR +status: AKZEPTIERT +owner: Lead Architect +date: 2026-03-30 +--- + +# ADR-0018: Rule-Versionierung und -Management (ÖTO-Regeln) + +## Status + +Akzeptiert + +## Kontext + +Die ÖTO-Regeln (Österreichische Turnierordnung) für Dressur, Springen und andere Sparten ändern sich regelmäßig ( +jährlich oder bei Bedarf). Das System muss in der Lage sein, Stammdaten (Altersklassen, Lizenzen, Richtverfahren, +Gebühren) für ein Turnier basierend auf dem zum Turnierzeitpunkt gültigen Regelwerk zu validieren und anzuzeigen. Eine +rein Code-basierte Regelverwaltung (Hardcoding) ist aufgrund der Dynamik und Offline-Fähigkeit nicht praktikabel. + +## Entscheidung + +ÖTO-Regeln werden als **versionierte Datensätze in der Datenbank** verwaltet (Regulation-as-Data). + +Details: + +1. **Versionierungs-Schema**: Alle Regel-Datensätze (z.B. Lizenz-Klasse-Matrix, Altersklassen-Berechnung) erhalten + `valid_from` und `valid_to` Zeitstempel. +2. **Aktives Regel-Set**: Die Applikationslogik ermittelt zur Laufzeit (z.B. basierend auf dem Turnierdatum) das jeweils + aktive Regel-Set aus der Datenbank. +3. **Seed-Strategie**: Zu Beginn jeder Saison (oder bei Major-Updates) wird ein neues Regel-Set als Seed in die + Datenbank eingespielt. Das "Regel-Set 2026" dient als Basis. +4. **Unveränderlichkeit (Immutability)**: Bestehende, in Turnieren verwendete Regeln dürfen nicht überschrieben werden. + Bei Änderungen wird ein neuer Datensatz mit neuem Gültigkeitsbereich angelegt (SCD Type 2 Pattern). + +## Konsequenzen + +- **Positiv**: Hohe Flexibilität ohne Code-Deployments (Config-over-Code). +- **Positiv**: Historische Turniere bleiben nachvollziehbar, da sie auf das damals gültige Regelwerk verweisen. +- **Negativ**: Erhöhte Komplexität bei Datenbank-Abfragen (immer Zeitbezug erforderlich). +- **Negativ**: Notwendigkeit für robuste Administrations-Schnittstellen oder SQL-Seeds zur Regelpflege. + +## Betrachtete Alternativen + +- **Hardcoding in Kotlin-Use-Cases**: Schneller zu implementieren, aber unflexibel bei unterjährigen Regeländerungen und + historischer Auswertung schwierig. +- **Git-basierte Konfiguration (YAML/JSON)**: Gut für CI/CD, aber schwierig für Offline-Szenarien ohne vollen + Repository-Sync; Datenbank-Integration für Abfragen komplexer. + +## Referenzen + +- [ROADMAP.md](../ROADMAP.md) +- [Abteilungs-Trennungs-Schwellenwerte.md](../../../docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md) diff --git a/docs/01_Architecture/adr/0019-masterdata-api-ingestion-layers-de.md b/docs/01_Architecture/adr/0019-masterdata-api-ingestion-layers-de.md new file mode 100644 index 00000000..d8f158f0 --- /dev/null +++ b/docs/01_Architecture/adr/0019-masterdata-api-ingestion-layers-de.md @@ -0,0 +1,55 @@ +--- +type: ADR +status: AKZEPTIERT +owner: Lead Architect +date: 2026-03-30 +--- + +# ADR-0019: API-Schichten und Ingestion-Pattern im Masterdata-SCS + +## Status + +Akzeptiert + +## Kontext + +Das Masterdata-SCS (Stammdaten) dient als zentrale Informationsquelle für alle anderen Bounded Contexts (z.B. +Registration, Competition). Es muss sowohl Massendaten aus dem ZNS (Zentrales Nennungs-System) aufnehmen (Schreibkanal) +als auch hochperformante Lesezugriffe (Lesekanal) für die Suche und Validierung ermöglichen. Dabei ist die Trennung +zwischen internen Ingestion-Prozessen und externen Client-APIs entscheidend für die Stabilität und Sicherheit. + +## Entscheidung + +Die API-Architektur wird in **klare Schichten für Ingestion (Schreiben) und REST (Lesen)** unterteilt. + +Details: + +1. **Lesekanal (Public REST API)**: Bietet Endpunkte für die Suche (Reiter, Pferde, Vereine) und den Abruf von + Regelwerken. Diese API ist optimiert für Performance (Indizes, Paging, ETags) und nutzt DTOs mit Kotlinx + Serialization. +2. **Schreibkanal (Ingestion API/Worker)**: Dieser Kanal ist internen Prozessen (ZNS-Importer) vorbehalten. Direkte + Schreibzugriffe von Clients auf Stammdaten sind in der ersten Phase unterbunden. Der Schreibkanal nutzt ein + Ingestion-Pattern, das auf Idempotenz (Upserts) und Validierung (Checksum-Checks) basiert. +3. **Internal API (Core Interfaces)**: Innerhalb des Masterdata-SCS werden klare Interfaces für Repositories und + UseCases genutzt, die von Ingestion und REST gemeinsam verwendet werden. +4. **Versioning**: Alle APIs werden versioniert (v1, v2), um zukünftige Schema-Änderungen ohne Breaking Changes zu + ermöglichen. + +## Konsequenzen + +- **Positiv**: Klare Trennung der Verantwortlichkeiten (Separation of Concerns). +- **Positiv**: Höhere Sicherheit, da Stammdaten nicht versehentlich durch die Public-API manipuliert werden können. +- **Positiv**: Bessere Skalierbarkeit: Lesekanal kann unabhängig vom Schreibkanal optimiert werden. +- **Negativ**: Erhöhter Implementierungsaufwand durch getrennte DTOs und Validierungslogik für die Ingestion-Phase. + +## Betrachtete Alternativen + +- **Einheitliche CRUD-API**: Alle Zugriffe über die gleiche API-Schicht. Verworfen wegen mangelnder Sicherheit bei + sensiblen Stammdaten und Performance-Problemen bei Massen-Imports. +- **GraphQL**: Bietet hohe Flexibilität beim Lesen, wurde jedoch für die erste Phase als zu komplex für die einfache + Suche in Stammdaten angesehen. REST ist für Offline-Szenarien und Caching (ETags) einfacher zu handhaben. + +## Referenzen + +- [ADR-0017: Importer-Einbettung](./0017-masterdata-importer-worker-de.md) +- [ROADMAP.md](../ROADMAP.md) diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_C-NEU_Classes.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_C-NEU_Classes.md new file mode 100644 index 00000000..238e9be1 --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_C-NEU_Classes.md @@ -0,0 +1,47 @@ +# Session Log: Einarbeitung C-NEU Bestimmungen & Turnier-Sparten + +**Datum:** 2026-03-30 +**Agent:** 📜 [ÖTO/FEI Rulebook Expert] / 🧹 [Curator] + +## Zielsetzung + +Integration der spezifischen Bestimmungen für C-NEU Turniere (CDN-C NEU / CSN-C NEU) in die Stammdaten-Dokumentation des +`masterdata` Services. Aufbereitung einer detaillierten Übersicht über Turnier-Sparten (Dressur & Springen), deren +Klassen und die korrespondierenden Startberechtigungen (Lizenz-Matrix). + +## Durchgeführte Änderungen + +### 1. Erweiterung der zentralen Stammdaten (`OETO_STAMMDATEN.md`) + +* **Abteilungslogik:** Spezifikation der 3-Abteilungs-Regel für CSN-C NEU bis 95 cm (Abt. 1: ohne Lizenz, Abt. 2: R1, + Abt. 3: R2+). +* **Dressur-Klassen:** Ergänzung der Klasse `LF` (Lizenzfrei) für Reiterpass-/Reiternadel-Aufgaben im C-NEU Bereich. +* **C-NEU Spezifika:** Dokumentation der Einschränkung, dass Lizenzinhaber in RP/Nadel-Bewerben nicht startberechtigt + sind. + +### 2. Neue Fachdokumentation (`TURNIER_KLASSEN.md`) + +* Erstellung einer detaillierten Übersicht für **Springen (CSN)**: + * Höhenstufen (E0 bis S****). + * C-NEU Besonderheiten (Registrierungspflicht erst ab 95 cm, Startlimits). + * Strukturelle Abteilungs-Vorgaben. +* Erstellung einer detaillierten Übersicht für **Dressur (CDN)**: + * Aufgabenniveau (LF bis S). + * Startberechtigungen pro Klasse. +* **Startberechtigungs-Matrix:** Zentrale Gegenüberstellung von Lizenzstufen (LZF, R1-R4, RD1-RD3) und den maximal + zulässigen Klassen in beiden Sparten. + +### 3. Service-Integration (`README.md`) + +* Verlinkung der neuen `TURNIER_KLASSEN.md` in der zentralen Dokumentations-Übersicht des `masterdata` Services. + +## Verifizierung + +* Abgleich der Daten mit `Bestimmungen_CSN-C_NEU.md` und `Bestimmungen_CDN-C_NEU.md`. +* Validierung der Lizenzstufen gegen `REITER_LIZENZEN.md` und die ÖTO 2026. +* Prüfung der Konsistenz mit den Abteilungs-Schwellenwerten aus der Master-Referenz. + +## Nächste Schritte + +* Implementierung der `Validation-Engine` Logik basierend auf der erstellten Startberechtigungs-Matrix. +* Erweiterung des `zns-import` Moduls zur Berücksichtigung der C-NEU Registrierungs-Ausnahmen für Pferde. diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Funktionaer_Qualifikationen.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Funktionaer_Qualifikationen.md new file mode 100644 index 00000000..73166f97 --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Funktionaer_Qualifikationen.md @@ -0,0 +1,36 @@ +# Session Log: Masterdata Funktionär-Qualifikationen + +**Datum:** 2026-03-30 +**Agent:** 📜 [ÖTO/FEI Rulebook Expert] + +## 🎯 Ziel + +Aufbereitung der Qualifikationen für Richter und Parcoursbauer basierend auf der ÖTO 2026 und dem ZNS-Pflichtenheft v2.4 +zur Integration in den `masterdata` Service. + +## 🛠️ Änderungen + +### 1. Neue Dokumentation: `FUNKTIONAERE_QUALIFIKATIONEN.md` + +* **Fachlich:** Zusammenfassung der Richtergruppen (Dressur, Springen, Vielseitigkeit) und Zusatzqualifikationen (SPF, + DPF). +* **Level:** Dokumentation der Parcoursbauer-Level (P1-P4) inklusive der spezifischen Anforderung für C-NEU (mind. P1). +* **Regelwerk:** Integration der Einsatzvorgaben (§ 50 A-Teil) wie Mindestbesetzung und Zeitlimits. +* **Technisch:** Detaillierung der ZNS-Satzarten (X-Satz für Richter, Y-Satz für Parcoursbauer) mit Felddefinitionen ( + Stelle/Länge). + +### 2. README-Update + +* Verlinkung der neuen Dokumentation in der zentralen `README.md` des `masterdata` Services. + +## 🔍 Validierung + +* Abgleich der Felddefinitionen mit dem Original-Pflichtenheft v2.4. +* Prüfung der fachlichen Anforderungen gegen die ÖTO 2026 (A- und B-Teil). +* Verifizierung der Pfade und Verlinkungen innerhalb des Service-Kontexts. + +## 📌 Nächste Schritte + +* Implementierung der `Funktionaer`-Entity in `masterdata-domain` (erledigt). +* Ausbau des `ExposedFunktionaerRepository` zur Unterstützung des ZNS-Imports der X- und Y-Sätze. +* Integration der Qualifikations-Validierung in die Turnier-Ausschreibung (Validation Engine). diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Gebuehrenordnung.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Gebuehrenordnung.md new file mode 100644 index 00000000..96d2c45a --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Gebuehrenordnung.md @@ -0,0 +1,41 @@ +# Session Log: Masterdata Gebührenordnung (ÖTO 2026) + +**Datum:** 2026-03-30 +**Agent:** 🧹 [Curator] & 📜 [ÖTO/FEI Rulebook Expert] + +## 🎯 Ziel + +Aufbereitung der offiziellen ÖTO-Gebührenordnung 2026 für die Sparten Dressur und Springen zur späteren Implementierung +in die Berechnungs- und Validierungs-Logik des Masterdata-Services. + +## 📝 Durchgeführte Änderungen + +### 1. Fachdokumentation erstellt + +* **Datei:** `backend/services/masterdata/docs/GEBUEHRENORDNUNG.md` +* **Inhalt:** + * **Nenn- und Startgelder:** Strukturierte Übersicht über Nenngelder nach Kategorie (A/B/C) und + Startgeld-Obergrenzen (mit/ohne Geldpreis, C-NEU, getrenntes Richten). + * **Zusatzabgaben:** Dokumentation von Tierwohleuro (1,00 €) und Sportförderbeitrag (1,00 €). + * **Geldpreise:** Tabellarische Aufbereitung der Mindest-Geldpreise für Dressur (Klassen A bis S) und Springen ( + Höhenstufen 105 cm bis 160 cm) für alle Turnierkategorien. + * **Funktionärsvergütung:** Festhalten der Tagessätze (120 € / 100 €), Kilometergelder (0,50 €) und + Unterkunftsvorgaben. + +### 2. Integration & Verlinkung + +* Aktualisierung der `backend/services/masterdata/README.md`, um die neue Gebührenordnung als Referenz für die + ÖTO-Konformität aufzunehmen. + +## 🔍 Validierung + +* Abgleich der Daten mit dem Originaldokument + `docs/03_Domain/02_Reference/OETO_Regelwerk/OETO-2026_E-Teil-Gebuehrenordnung_18-12-2025.md`. +* Sicherstellung, dass spartenrelevante Ausnahmen (z.B. Tierwohleuro nur bei Springen) korrekt markiert sind. + +## 💡 Nächste Schritte + +* Überführung der Gebührensätze in Domänen-Konstanten (`masterdata-domain`). +* Implementierung einer `AccountingEngine` oder eines `FeeCalculator` Services im `competition-context`, der auf diese + Stammdaten zugreift. +* Erweiterung der Ausschreibungs-Validierung um die Prüfung der Mindest-Geldpreis-Summen. diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen.md new file mode 100644 index 00000000..1db87145 --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen.md @@ -0,0 +1,29 @@ +### Summary + +- Aufbereitung und Dokumentation der spezifischen Anforderungen für Pferdeprüfungen (Jungpferde) in Dressur und Springen + gemäß ÖTO 2026. +- Integration der komplexeren Bewertungslogik (Qualitative Noten, Abzüge bei Springpferdeprüfungen) in den `masterdata` + Service-Kontext. + +### Changes + +- **Neue Fachdokumentation:** `backend/services/masterdata/docs/PFERDEPRUEFUNGEN.md` erstellt, die Altersklassen, + Richtverfahren und Bewertungskriterien für Dressur-, Spring- und Reitpferdeprüfungen beschreibt. +- **Bewertungs-Logik:** Detaillierung der qualitativen Merkmale (Grundgangarten, Rittigkeit, Perspektive) und der + spezifischen Abzugs-Regeln für Springpferdeprüfungen. +- **README-Update:** Die zentrale `README.md` des `masterdata` Services wurde um die Verlinkung der neuen + Pferdeprüfungs-Dokumentation ergänzt. +- **Journaling:** Erstellung eines detaillierten Session Logs zur Dokumentation der Aufbereitung für + Jungpferdeprüfungen. + +### Verification + +- Abgleich der Altersklassen und Richtverfahren mit den ÖTO-Regelwerken 2026 (Abschnitt B I und B II). +- Validierung der Abzugs-Logik (§ 204 Abs. 4) für Springpferdeprüfungen. +- Prüfung der internen Verlinkung innerhalb der Service-Struktur. + +### Notes + +- Die Dokumentation dient als Grundlage für die Implementierung der Notenerfassung im UI (Einzelnoten-Eingabe vs. + Gesamtnote). +- Die Pferdealter-Validierung muss beim Nennungsprozess strikt auf dem Geburtsjahr (Stichtag 1.1.) basieren. diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen_Bewertung.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen_Bewertung.md new file mode 100644 index 00000000..43217863 --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Pferdepruefungen_Bewertung.md @@ -0,0 +1,24 @@ +### Summary + +- Aufbereitung und Dokumentation des spezifischen Bewertungssystems für Pferdeprüfungen (Dressur-/Springpferde) und + Stilspringprüfungen gemäß ÖTO 2026. +- Integration der qualitativen Bewertungskriterien und der automatisierten Abzugslogik in den `masterdata` + Service-Kontext. + +### Changes + +- **Neue Fachdokumentation:** `backend/services/masterdata/docs/PFERDEPRUEFUNGEN_BEWERTUNG.md` erstellt, die + Einzelnoten-Kriterien für Dressurpferdeprüfungen (Schritt, Trab, Galopp etc.) und die Abzugslogik für + Springpferde/Stilspringen (-0,5/-1,0) detailliert beschreibt. +- **Spezialregelung:** Dokumentation der „ohne Bewertung“ (o.B.) Logik für Endnoten <= 4,9 inklusive deren spezifischer + Reihung in Ergebnislisten. +- **System-Anforderungen:** Definition der UI- und Berechnungs-Anforderungen für die Meldestellen-Software ( + Echtzeit-Kalkulation der Endnoten). +- **README-Update:** Die zentrale `README.md` des `masterdata` Services wurde um die Verlinkung der neuen + Bewertungs-Dokumentation erweitert. + +### Verification + +- Abgleich der Kriterien und Abzugswerte mit den ÖTO-Regelwerken 2026 (Abschnitt B, § 103, § 104, § 203, § 204). +- Validierung der Konsistenz zwischen fachlichen Anforderungen und den zuvor erstellten allgemeinen + Pferdeprüfungs-Stammdaten. diff --git a/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Reiter_Pruefungen.md b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Reiter_Pruefungen.md new file mode 100644 index 00000000..07396f5f --- /dev/null +++ b/docs/99_Journal/2026-03-30_Session_Log_Masterdata_Reiter_Pruefungen.md @@ -0,0 +1,27 @@ +# Session Log: Masterdata Reiter-Prüfungen (Dressur & Stilspringen) + +## 📋 Zusammenfassung + +- Aufbereitung der Stammdaten für Dressurreiter- und Stilspringprüfungen gemäß ÖTO 2026. +- Fokus auf die spezifische Bewertungslogik (Wertnoten vs. Abzüge) und deren Anforderungen an das System. + +## 🛠 Änderungen + +- **Neue Fachdokumentation:** `backend/services/masterdata/docs/REITER_PRUEFUNGEN.md` erstellt. +- **Inhalt:** + - Definition Dressurreiterprüfung (Sitz, Einwirkung, Hufschlaglinien). + - Detaillierte Abzugslogik für Stilspringprüfungen (Hindernisfehler, Ungehorsam, Sturz). + - System-Anforderungen für die UI (Erfassungsmasken) und Validierung (Lizenzprüfung). +- **README-Update:** Verlinkung der neuen Dokumentation in der zentralen `README.md` des Masterdata-Services. + +## ✅ Verifizierung + +- Abgleich der Abzugswerte (z.B. -0,5 für Abwurf im Stilspringen) mit der ÖTO 2026. +- Prüfung der Reihungsregeln bei Punktgleichheit (Stilnote vor Abzügen). +- Validierung der Konsistenz mit dem bestehenden ZNS-Schnittstellen-Mapping. + +## 📝 Notizen + +- Diese Daten sind besonders für die Umsetzung von Nachwuchsbewerben und C-NEU Turnieren (lizenzfrei) von hoher + Bedeutung. +- Der `Score-Service` muss im Backend die Logik zur automatischen Berechnung der Endnoten im Stilspringen bereitstellen.