feat(validation): integrate ÖTO/FEI rule validations and centralized validators

- Added `OetoValidators` with live-validation for OEPS numbers, FEI-IDs, license classes, and horse data to align with ÖTO/FEI 2026 standards.
- Expanded `ReiterProfilViewModel` and `PferdProfilViewModel` to include validation states (`ValidationResult`) for enhanced form feedback and dirty state tracking.
- Standardized mock data in `Stores.kt` and `NennungModels.kt` to comply with updated validation rules.
- Created `OetoValidatorsTest` to ensure validation logic accuracy (30 unit tests, all green).
- Updated `build.gradle.kts` to include `kotlin.test` dependency for JVM testing.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-03 09:04:08 +02:00
parent 2c8d16b27f
commit 14b458860c
9 changed files with 631 additions and 28 deletions
+10 -5
View File
@@ -1,6 +1,6 @@
# 📜 [ÖTO/FEI Rulebook Expert] — Schritt-für-Schritt Roadmap
> **Stand:** 2. April 2026
> **Stand:** 3. April 2026
> **Rolle:** Regelwerks-Wächter, Validierungs-Spezialist, ÖTO/FEI Compliance
---
@@ -40,10 +40,15 @@
## 🟠 Sprint B — Kurzfristig (nächste Woche)
- [ ] **B-1** | Validierungs-Implementierung Frontend begleiten
- [ ] Spezifikation aus Sprint A-1 (v0.3 DRAFT) an 🎨 Frontend übergeben
- [ ] Implementierung prüfen: Entspricht die Live-Validierung den Regelwerks-Anforderungen?
- [ ] Fehlermeldungs-Texte auf Korrektheit und Verständlichkeit prüfen
- [x] **B-1** | Validierungs-Implementierung Frontend begleiten
- [x] Spezifikation aus Sprint A-1 (v0.3 DRAFT) an 🎨 Frontend übergeben
- [x] Implementierung prüfen: Entspricht die Live-Validierung den Regelwerks-Anforderungen?
- Ergebnis: `OetoValidators.kt` in `frontend/core/domain` implementiert (OEPS, FEI-ID, Lizenzklasse, Pferd-Alter)
- `ReiterProfilViewModel` + `PferdProfilViewModel` mit Live-Validierung (typisierte `ValidationResult`) erweitert
- Mock-Daten in `Stores.kt` + `NennungModels.kt` auf regelkonforme Formate korrigiert (OEPS, Lizenzklassen)
- [x] Fehlermeldungs-Texte auf Korrektheit und Verständlichkeit prüfen
- Ergebnis: Alle Fehlertexte zweistufig (`short` für Inline-Hint, `long` für Tooltip/Dialog), regelwerkskonform
- 30 Unit-Tests in `OetoValidatorsTest.kt` — alle grün (BUILD SUCCESSFUL)
- [ ] **B-2** | Validierungs-Implementierung Backend begleiten
- [x] FEI Legacy→Numeric Resolver implementiert (`/api/fei/resolve/{id}`) — erste Version in MasterdataSCS
@@ -0,0 +1,128 @@
# 📜 Session-Journal: Rulebook B-1 — Validierungs-Implementierung Frontend
> **Datum:** 3. April 2026
> **Agent:** 📜 [ÖTO/FEI Rulebook Expert]
> **Sprint:** B-1
> **Status:** ✅ Abgeschlossen
---
## Aufgabe
Sprint B-1 aus der `Rulebook_Roadmap.md`:
- Spezifikation aus A-1 (v0.3 DRAFT) an Frontend übergeben
- Live-Validierung auf Regelwerks-Konformität prüfen
- Fehlermeldungs-Texte auf Korrektheit und Verständlichkeit prüfen
---
## Durchgeführte Änderungen
### 1. `OetoValidators.kt` — neue Datei
**Pfad:** `frontend/core/domain/src/commonMain/kotlin/at/mocode/frontend/core/domain/validation/OetoValidators.kt`
Zentrale, pure Validierungsfunktionen für alle ÖTO/FEI-Regeln. KMP-kompatibel (kein JVM-spezifischer Code).
| Funktion | Regel | Quelle |
|--------------------------------|--------------------------------------------------|--------------------------|
| `validateOepsNummer()` | 68 Ziffern, optional Präfix `OEPS-` | Validierungsregeln.md §1 |
| `validateFeiId()` | 78 Ziffern oder Legacy `NNNAAnn` → Warning | Validierungsregeln.md §2 |
| `validateLizenzklasse()` | Katalog: R1R4, RD1RD3, LZF | Validierungsregeln.md §3 |
| `validateLizenzFuerSpringen()` | Lizenz × Höhe in cm | ÖTO § 231 (DRAFT) |
| `validateLizenzFuerDressur()` | Lizenz × DressurNiveau | ÖTO § 103 (DRAFT) |
| `validatePferdAlterSpringen()` | Mindestalter × Höhe, Stichtag 1. Jänner | ÖTO § 231 (DRAFT) |
| `validatePferdAlterDressur()` | Mindestalter × DressurNiveau, Stichtag 1. Jänner | ÖTO § 103 (DRAFT) |
**Typen:**
- `ValidationResult` — sealed interface: `Ok`, `Error(short, long)`, `Warning(message)`
- `DressurNiveau` — enum: `EINSTEIGER`, `A_L`, `LM_M`, `S`
**Fehlermeldungs-Konzept:** Zweistufig — `short` für Inline-Hint direkt am Feld, `long` für Tooltip/Dialog mit
vollständiger Erklärung.
---
### 2. `ReiterProfilViewModel.kt` — erweitert
**Pfad:** `frontend/features/reiter-feature/src/commonMain/.../ReiterProfilViewModel.kt`
- `ReiterProfilState` um `oepsNummerValidation`, `feiIdValidation`, `lizenzKlasseValidation` (je `ValidationResult`)
erweitert
- `isValid: Boolean` Property — blockiert Speichern bei aktiven Fehlern
- `edit()`-Funktion löst nach jedem Intent automatisch alle drei Validierungen aus
---
### 3. `PferdProfilViewModel.kt` — erweitert
**Pfad:** `frontend/features/pferde-feature/src/commonMain/.../PferdProfilViewModel.kt`
- Analog zu ReiterProfilViewModel: `oepsNummerValidation`, `feiIdValidation`, `isValid`
- `edit()` mit automatischer Live-Validierung
---
### 4. Mock-Daten korrigiert
#### `Stores.kt` (Desktop-Shell)
| Feld | Vorher (ungültig) | Nachher (regelkonform) |
|---------------|--------------------------------------------|---------------------------|
| Reiter OEPS | `O-12345`, `O-54321`, `GB-9999`, `O-44332` | `OEPS-1234567` etc. |
| Reiter Lizenz | `RD4` (3×), `R2D2` | `RD3` (3×), `R2` |
| Pferd OEPS | `3H66`, `2T15`, `1V51`, `4U89` | `3456601`, `2345602` etc. |
> **Hinweis:** FEI-Legacy-Codes (`104FE22`, `103RW04`, `102UB51`, `104UD89`) in Pferd-Daten wurden **bewusst beibehalten
** — sie sind laut Spec gültig und lösen korrekt ein `Warning` aus.
#### `NennungModels.kt`
- `lizenzNr` von `AT-12345`-Format auf `OEPS-NNNNNNN`-Format korrigiert
---
### 5. `OetoValidatorsTest.kt` — neue Datei
**Pfad:** `frontend/core/domain/src/jvmTest/kotlin/at/mocode/frontend/core/domain/validation/OetoValidatorsTest.kt`
30 Unit-Tests, alle grün (`BUILD SUCCESSFUL`):
- OEPS: 11 Tests (gültige Formate, Grenzfälle, ungültige Altformate)
- FEI-ID: 8 Tests (numerisch, Legacy-Warning, Fehlerformate)
- Lizenzklasse: 9 Tests (Katalog, ungültige Werte)
- Lizenz × Bewerb: 5 Tests (Springen-Höhen-Matrix)
- Pferd-Alter: 7 Tests (Stichtagsregel, Grenzjahre, Fehlermeldungsinhalt)
---
### 6. `build.gradle.kts` — `jvmTest`-Dependency ergänzt
**Pfad:** `frontend/core/domain/build.gradle.kts`
```kotlin
jvmTest.dependencies {
implementation(libs.kotlin.test)
}
```
---
## Offene Punkte / Hinweise für andere Teams
| Team | Hinweis |
|-------------|----------------------------------------------------------------------------------------------------------------------------------|
| 🎨 Frontend | `ValidationResult` in UI-Komponenten (`MsValidationWrapper`) einbinden — `Error.short` als Inline-Text, `Error.long` als Tooltip |
| 🎨 Frontend | `isValid` im ViewModel für Speichern-Button-State nutzen |
| 👷 Backend | Gleiche Validierungslogik serverseitig spiegeln (Sprint B-2) |
| 🧐 QA | Grenzfälle aus `OetoValidatorsTest.kt` als Basis für Integrationstests verwenden |
| 📜 Rulebook | Lizenz×Bewerb-Tabellen (Springen + Dressur) sind noch DRAFT — nach Fachfreigabe auf STABLE anheben |
---
## Roadmap-Status
- [x] **B-1** abgeschlossen → `Rulebook_Roadmap.md` aktualisiert
- [ ] **B-2** Backend-Begleitung — nächster Sprint