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

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

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-30 14:29:55 +02:00
parent 6375ec23c3
commit e8757c5c32
29 changed files with 1663 additions and 18 deletions
@@ -0,0 +1,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)
@@ -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)
@@ -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)