Document and implement CSN-C-NEU mandatory division rules: Add TURNIER_KLASSEN.md detailing forced divisions by license categories; establish uniform labels and keys (e.g., LZF_ONLY and R1_PLUS); draft optional youth division rules. Extend validation in Validierungsregeln.md. Implement FEI-ID resolver and mapping endpoint in Masterdata service.
This commit is contained in:
parent
bbe5b1a357
commit
4ae701d969
|
|
@ -0,0 +1,29 @@
|
||||||
|
package at.mocode.masterdata.domain.service
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auflösung von FEI-IDs: akzeptiert numerische IDs (Pass‑Through) und Legacy‑Referenzcodes
|
||||||
|
* und liefert – wenn bekannt – die zugehörige numerische FEI‑ID zurück.
|
||||||
|
*/
|
||||||
|
interface FeiIdResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löst eine eingegebene FEI‑Kennung auf.
|
||||||
|
*
|
||||||
|
* @param input Benutzer-/Importeingabe (numerisch 7–8 Stellen oder Legacy‑Code 3Z+2B+2Z)
|
||||||
|
* @return [FeiIdResolution] mit normalisierter numerischer ID, oder null wenn unbekannt/ungültig
|
||||||
|
*/
|
||||||
|
fun resolve(input: String): FeiIdResolution?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ergebnis der FEI‑ID Auflösung.
|
||||||
|
*
|
||||||
|
* @property normalizedNumericId Numerische FEI‑ID (7–8 Ziffern) als String
|
||||||
|
* @property sourceFormat "NUMERIC" | "LEGACY_CODE"
|
||||||
|
* @property wasMapped true, wenn aus Legacy nach numerisch gemappt wurde
|
||||||
|
*/
|
||||||
|
data class FeiIdResolution(
|
||||||
|
val normalizedNumericId: String,
|
||||||
|
val sourceFormat: String,
|
||||||
|
val wasMapped: Boolean
|
||||||
|
)
|
||||||
|
|
@ -31,6 +31,7 @@ dependencies {
|
||||||
implementation(libs.spring.boot.starter.web)
|
implementation(libs.spring.boot.starter.web)
|
||||||
implementation(libs.spring.boot.starter.validation)
|
implementation(libs.spring.boot.starter.validation)
|
||||||
implementation(libs.spring.boot.starter.actuator)
|
implementation(libs.spring.boot.starter.actuator)
|
||||||
|
implementation(libs.jackson.module.kotlin)
|
||||||
//implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
//implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||||
|
|
||||||
// Ktor Server (für SCS: eigener kleiner HTTP-Server pro Kontext)
|
// Ktor Server (für SCS: eigener kleiner HTTP-Server pro Kontext)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package at.mocode.masterdata.service.fei
|
||||||
|
|
||||||
|
import at.mocode.masterdata.domain.service.FeiIdResolution
|
||||||
|
import at.mocode.masterdata.domain.service.FeiIdResolver
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/fei")
|
||||||
|
class FeiIdController(
|
||||||
|
private val resolver: FeiIdResolver
|
||||||
|
) {
|
||||||
|
|
||||||
|
data class ResolveResponse(
|
||||||
|
val input: String,
|
||||||
|
val normalizedNumericId: String?,
|
||||||
|
val sourceFormat: String?,
|
||||||
|
val wasMapped: Boolean,
|
||||||
|
val found: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@GetMapping("/resolve/{id}")
|
||||||
|
fun resolve(@PathVariable("id") id: String): ResponseEntity<ResolveResponse> {
|
||||||
|
val res: FeiIdResolution? = resolver.resolve(id)
|
||||||
|
return if (res != null) {
|
||||||
|
ResponseEntity.ok(
|
||||||
|
ResolveResponse(
|
||||||
|
input = id,
|
||||||
|
normalizedNumericId = res.normalizedNumericId,
|
||||||
|
sourceFormat = res.sourceFormat,
|
||||||
|
wasMapped = res.wasMapped,
|
||||||
|
found = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ResponseEntity.status(404).body(
|
||||||
|
ResolveResponse(
|
||||||
|
input = id,
|
||||||
|
normalizedNumericId = null,
|
||||||
|
sourceFormat = null,
|
||||||
|
wasMapped = false,
|
||||||
|
found = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package at.mocode.masterdata.service.fei
|
||||||
|
|
||||||
|
import at.mocode.masterdata.domain.service.FeiIdResolution
|
||||||
|
import at.mocode.masterdata.domain.service.FeiIdResolver
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import org.springframework.core.io.ClassPathResource
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einfache In‑Memory Implementierung des [FeiIdResolver],
|
||||||
|
* lädt ein JSON‑Mapping aus Ressourcen: `data/fei-id-mapping.json`.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
class FeiIdResolverImpl : FeiIdResolver {
|
||||||
|
|
||||||
|
private val legacyToNumeric: Map<String, String> by lazy {
|
||||||
|
val res = ClassPathResource("data/fei-id-mapping.json")
|
||||||
|
if (!res.exists()) return@lazy emptyMap<String, String>()
|
||||||
|
val mapper = jacksonObjectMapper()
|
||||||
|
res.inputStream.use { input ->
|
||||||
|
mapper.readValue<Map<String, String>>(input)
|
||||||
|
.mapKeys { it.key.trim().uppercase() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val numericRegex = Regex("^[0-9]{7,8}$")
|
||||||
|
private val legacyRegex = Regex("^[0-9]{3}[A-Z]{2}[0-9]{2}$")
|
||||||
|
|
||||||
|
override fun resolve(input: String): FeiIdResolution? {
|
||||||
|
val s = input.trim().uppercase()
|
||||||
|
// Numerisch: Pass‑Through
|
||||||
|
if (numericRegex.matches(s)) {
|
||||||
|
return FeiIdResolution(normalizedNumericId = s, sourceFormat = "NUMERIC", wasMapped = false)
|
||||||
|
}
|
||||||
|
// Legacy: lookup
|
||||||
|
if (legacyRegex.matches(s)) {
|
||||||
|
val mapped = legacyToNumeric[s] ?: return null
|
||||||
|
return FeiIdResolution(normalizedNumericId = mapped, sourceFormat = "LEGACY_CODE", wasMapped = true)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"104FE22": "10011469",
|
||||||
|
"103RW04": "10019075",
|
||||||
|
"102UB51": "10028445",
|
||||||
|
"104UD89": "10011111"
|
||||||
|
}
|
||||||
181
docs/03_Domain/02_Reference/TURNIER_KLASSEN.md
Normal file
181
docs/03_Domain/02_Reference/TURNIER_KLASSEN.md
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
---
|
||||||
|
type: RULE_SPEC
|
||||||
|
status: DRAFT
|
||||||
|
owner: Rulebook Expert
|
||||||
|
last_update: 2026-04-02
|
||||||
|
---
|
||||||
|
|
||||||
|
# Turnier-Klassen und Abteilungs-Zwangsteilung (ÖTO)
|
||||||
|
|
||||||
|
Ziel: Einheitliche, maschinenlesbare Spezifikation der Klassensystematik und der verpflichtenden Abteilungs-Teilungsregeln ("Zwangsteilung") gemäß ÖTO. Diese Regeln steuern Backend-Validierungen, Frontend-UX (Hinweise/Warnungen) und Exportlogik.
|
||||||
|
|
||||||
|
Quellen/Verweise:
|
||||||
|
- Roadmap: `docs/04_Agents/Roadmaps/Rulebook_Roadmap.md` (A-2)
|
||||||
|
- Domänen‑Modell: `docs/03_Domain/01_Core_Model/Domain_Model_Veranstaltung_Turnier_Bewerb_Abteilung.md`
|
||||||
|
- Validierungsregeln (Lizenz/Alter): `docs/03_Domain/02_Reference/Validierungsregeln.md`
|
||||||
|
- ÖTO Referenzstellen (Paragraphen‑Pins zur Nachverfolgung):
|
||||||
|
- Springen: ÖTO 2026, Kapitel „Springen“, § 231 Abs. 1–3 (CSN‑C‑NEU Teilungsregeln) [PIN: OETO-SPR-231]
|
||||||
|
- Dressur: ÖTO 2026, Kapitel „Dressur“, § 103 Abs. 2–5 (Teilnahme/Leistungsstufen) [PIN: OETO-DRS-103]
|
||||||
|
- Vielseitigkeit: ÖTO 2026, Kapitel „Vielseitigkeit“, §§ 3xx (Teilnahme/Abteilungen) [PIN: OETO-VS-3XX]
|
||||||
|
|
||||||
|
Hinweis Rechtslage: Die obigen „Paragraphen‑Pins“ verankern die Stellen im ÖTO. Exakte Absatz-/Ziffernangaben werden nach juristischer Finalisierung ergänzt. Inhaltliche Logik entspricht dem Stand der Praxis (CSN‑C‑NEU) und wird bei Abweichungen angepasst.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Begriffe (Auszug)
|
||||||
|
- Bewerb: Sportliche Ausschreibungseinheit innerhalb eines Turniers (z. B. Springen 95 cm, Stilspringen). Enthält 1..N Abteilungen.
|
||||||
|
- Abteilung: Startgruppe innerhalb eines Bewerbs. Kann organisatorische oder regelbedingte Gründe haben (Zwangsteilung, Lizenz, Jugend usw.).
|
||||||
|
- Zwangsteilung: Verpflichtende Abteilungsbildung anhand lizenz-/leistungsbezogener Kriterien gemäß ÖTO.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. CSN (Springen national) — Zwangsteilung C‑NEU
|
||||||
|
|
||||||
|
Gültig für Bewerbe der Kategorie „CSN‑C‑NEU“.
|
||||||
|
|
||||||
|
### 2.1 Regelübersicht (Zwangsteilung)
|
||||||
|
- Rechtsgrundlage: ÖTO § 231 (vgl. [PIN: OETO-SPR-231])
|
||||||
|
- Bewerbe mit Höhe ≤ 95 cm:
|
||||||
|
- Abteilung A: Label: „ohne Lizenz“ — Key: `LZF_ONLY` — Allowed: `LZF`
|
||||||
|
- Abteilung B: Label: „mit Lizenz“ — Key: `R1_PLUS` — Allowed: `R1|R2|R3|R4`
|
||||||
|
|
||||||
|
- Bewerbe mit Höhe ≥ 100 cm:
|
||||||
|
- Abteilung A: Label: „R1“ — Key: `R1_ONLY` — Allowed: `R1`
|
||||||
|
- Abteilung B: Label: „R2 und höher“ — Key: `R2_PLUS` — Allowed: `R2|R3|R4`
|
||||||
|
|
||||||
|
Erläuterungen:
|
||||||
|
- Die Abteilungsbezeichnungen dienen dem Frontend (Label) und der Preisgeld-/Siegerehrungslogik. Technisch werden die Abteilungen per Attribut „Lizenz‑Gruppe“ markiert.
|
||||||
|
- Veranstalter dürfen enger teilen (z. B. zusätzliche Jugendabteilungen), nicht jedoch lockern (Pflicht‑Zweiteilung muss bestehen bleiben).
|
||||||
|
|
||||||
|
### 2.2 Maschinenlesbare Spezifikation
|
||||||
|
|
||||||
|
Tabelle: CSN‑C‑NEU Zwangsteilung nach Höhe
|
||||||
|
|
||||||
|
| Höhe (cm) | Abteilung 1 (Label · Key) | Abteilung 2 (Label · Key) | Bemerkung |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ≤ 95 | „ohne Lizenz“ · `LZF_ONLY` | „mit Lizenz“ · `R1_PLUS` | `R1_PLUS` umfasst `R1|R2|R3|R4` |
|
||||||
|
| ≥ 100 | „R1“ · `R1_ONLY` | „R2 und höher“ · `R2_PLUS` | `R2_PLUS` umfasst `R2|R3|R4` |
|
||||||
|
|
||||||
|
Pseudocode (Ableitung der Pflicht‑Abteilungen):
|
||||||
|
```kotlin
|
||||||
|
data class ForcedDivision(val label: String, val allowedLicenses: Set<String>)
|
||||||
|
|
||||||
|
fun forcedDivisionsCsnCNeu(heightCm: Int): List<ForcedDivision> =
|
||||||
|
if (heightCm <= 95) listOf(
|
||||||
|
ForcedDivision(label = DivisionLabels.OHNE_LIZENZ, allowedLicenses = setOf("LZF")),
|
||||||
|
ForcedDivision(label = DivisionLabels.MIT_LIZENZ, allowedLicenses = setOf("R1","R2","R3","R4"))
|
||||||
|
) else listOf(
|
||||||
|
ForcedDivision(label = DivisionLabels.R1, allowedLicenses = setOf("R1")),
|
||||||
|
ForcedDivision(label = DivisionLabels.R2_UND_HOEHER, allowedLicenses = setOf("R2","R3","R4"))
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Validierung (vereinfachte Regel):
|
||||||
|
- Wenn Bewerbskategorie = `CSN-C-NEU`, dann müssen genau zwei Abteilungen gemäß obiger Ableitung vorhanden sein. Jede Nennung muss in einer Abteilung landen, deren `allowedLicenses` die Lizenz des Reiters enthält.
|
||||||
|
|
||||||
|
Fehlermeldungen (UX):
|
||||||
|
- „Für CSN‑C‑NEU Bewerbe ist eine Zwangsteilung nach Lizenz vorgeschrieben (ÖTO § 231). Bitte beide Abteilungen anlegen.“
|
||||||
|
- „Die Abteilung ‚R2 und höher‘ darf nur Lizenzen R2/R3/R4 enthalten.“
|
||||||
|
- Hinweistext (Quelle): „Rechtsgrundlage: ÖTO § 231 (CSN‑C‑NEU).“
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. CDN (Dressur national) — Prüfung weiterer Zwangsteilungen
|
||||||
|
|
||||||
|
Status: geprüft. Nach aktuellem Stand bestehen in den Einsteiger‑/Niedrig‑Klassen keine zwingenden Lizenz‑Zwangsteilungen analog zu CSN‑C‑NEU. Übliche Praxis ist die optionale Teilung nach Leistungsklassen/Jahrgängen (z. B. Jugendliche), jedoch keine verpflichtende Zweiteilung „ohne/mit Lizenz“.
|
||||||
|
|
||||||
|
- Ergebnis: Keine allgemeine, disziplinweite Zwangsteilung identifiziert. Veranstalter können freiwillig teilen (z. B. RD1 vs. RD2+), sofern ÖTO konform. Bezug: ÖTO § 103 (vgl. [PIN: OETO-DRS-103]).
|
||||||
|
|
||||||
|
Folgeaktion: Bei Veröffentlichung der finalen Dressur‑Abschnitte erneut prüfen. Bis dahin: Keine systemweite Pflichtregel hinterlegen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. CCN (Vielseitigkeit national) — Prüfung weiterer Zwangsteilungen
|
||||||
|
|
||||||
|
Status: vorläufig geprüft. In den nationalen Vielseitigkeitsklassen (CCN) ist keine generische Zwangsteilung nach Lizenzgruppen („ohne/mit“ bzw. `R1` vs. `R2+`) als Pflicht verankert. Teilungen erfolgen eher nach Leistungsniveau, Altersklassen oder organisatorischen Gründen.
|
||||||
|
|
||||||
|
- Ergebnis: Keine disziplinweiten Pflicht‑Teilungsregeln identifiziert. Konkrete Ausnahmen sind turnierspezifisch. Bezug: ÖTO Kapitel „Vielseitigkeit“, §§ 3xx (vgl. [PIN: OETO-VS-3XX]); exakte Absätze folgen nach Finalisierung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Implementierungshinweise (Backend/Frontend)
|
||||||
|
|
||||||
|
- Backend:
|
||||||
|
- Regel „CSN‑C‑NEU → Pflicht‑Abteilungen“ als Regulation‑as‑Data hinterlegen (z. B. `reg_forced_divisions` mit Feldern: `category`, `height_threshold`, `division_key`, `allowed_licenses`).
|
||||||
|
- Serverseitige Validierung beim Anlegen/Bearbeiten eines CSN‑C‑NEU Bewerbs: genau zwei Abteilungen erzwingen, Labels/Allowed‑Sets prüfen.
|
||||||
|
- Nennvalidierung: Lizenz des Reiters ∈ `allowedLicenses` der Zielabteilung.
|
||||||
|
|
||||||
|
- Frontend:
|
||||||
|
- Wizard/Editor legt bei CSN‑C‑NEU automatisch beide Abteilungen an (konfigurierbare Labels).
|
||||||
|
- Live‑Hinweis, wenn eine Abteilung fehlt oder falsche Lizenzen zugeordnet sind.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Einheitliche Label‑Konventionen für Abteilungen
|
||||||
|
|
||||||
|
Ziel: Einheitliche, i18n‑fähige Benennung in UI, Exporten und Validierung. Deutsche Standard‑Labels und technische Keys:
|
||||||
|
|
||||||
|
- DivisionLabels (Deutsch):
|
||||||
|
- OHNE_LIZENZ → „ohne Lizenz“ (Key: `LZF_ONLY`)
|
||||||
|
- MIT_LIZENZ → „mit Lizenz“ (Key: `R1_PLUS`)
|
||||||
|
- R1 → „R1“ (Key: `R1_ONLY`)
|
||||||
|
- R2_UND_HOEHER → „R2 und höher“ (Key: `R2_PLUS`)
|
||||||
|
|
||||||
|
Richtlinien:
|
||||||
|
- Labels in UI exakt wie oben; keine Varianten („R2+“ nur in Klammern/Hinweisen, offizielles Label: „R2 und höher“).
|
||||||
|
- Keys sind stabil und werden in Datenpersistenz/Exports verwendet. Übersetzungen erfolgen per i18n.
|
||||||
|
|
||||||
|
Pseudocode (Konstanten):
|
||||||
|
```kotlin
|
||||||
|
object DivisionLabels {
|
||||||
|
const val OHNE_LIZENZ = "ohne Lizenz" // key: LZF_ONLY
|
||||||
|
const val MIT_LIZENZ = "mit Lizenz" // key: R1_PLUS
|
||||||
|
const val R1 = "R1" // key: R1_ONLY
|
||||||
|
const val R2_UND_HOEHER = "R2 und höher" // key: R2_PLUS
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Erweiterungen: Jugend‑/Jahrgangsteilungen (optional)
|
||||||
|
|
||||||
|
Status: Optionales Regel‑Set, kein ÖTO‑Pflichtumfang wie bei CSN‑C‑NEU. Veranstalter können zusätzlich nach Jahrgängen/Jugendklassen teilen, sofern ÖTO‑konform (vgl. Dressur § 103 und disziplin‑spezifische Jugendbestimmungen).
|
||||||
|
|
||||||
|
Modellierung als optionale Regeln:
|
||||||
|
|
||||||
|
- Datenmodell (Beispiel als Regulation‑as‑Data):
|
||||||
|
- Tabelle `reg_optional_divisions`:
|
||||||
|
- `category` (z. B. `CSN`, `CDN`)
|
||||||
|
- `discipline` (SPRINGEN, DRESSUR, VIELSEITIGKEIT)
|
||||||
|
- `division_key` (z. B. `U16`, `U18`, `U25`, `AMATEURE`)
|
||||||
|
- `label` (z. B. „Jugend U16“, „Jugend U18“)
|
||||||
|
- `age_range` (z. B. `14-16` Jahre, berechnet gem. Stichtag 1.1.; vgl. Validierungsregeln § „Altersklassen Pferd/Reiter“)
|
||||||
|
- `license_filter` (optional, Menge erlaubter Lizenzen)
|
||||||
|
- `notes` (Freitext/Paragraphen‑Bezug)
|
||||||
|
|
||||||
|
Beispiel (Pseudocode):
|
||||||
|
```kotlin
|
||||||
|
data class OptionalDivisionRule(
|
||||||
|
val category: String, // CSN, CDN
|
||||||
|
val discipline: String, // SPRINGEN, DRESSUR
|
||||||
|
val divisionKey: String, // U16, U18
|
||||||
|
val label: String, // "Jugend U16"
|
||||||
|
val ageFrom: Int, val ageTo: Int?, // inklusiv, To=null = open ended
|
||||||
|
val allowedLicenses: Set<String>? = null // null = alle
|
||||||
|
)
|
||||||
|
|
||||||
|
fun applies(rule: OptionalDivisionRule, athleteAge: Int, license: String): Boolean =
|
||||||
|
(athleteAge >= rule.ageFrom) && (rule.ageTo?.let { athleteAge <= it } ?: true) &&
|
||||||
|
(rule.allowedLicenses?.contains(license) ?: true)
|
||||||
|
```
|
||||||
|
|
||||||
|
UX‑Hinweistexte:
|
||||||
|
- „Optionale Jugendabteilung aktiv: Nur Athlet:innen des Jahrgangsbereichs {label} werden hier gewertet.“
|
||||||
|
- „Diese Abteilung ist optional; Pflicht‑Zwangsteilung (falls vorhanden) bleibt unberührt.“
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Offene Punkte / ToDos
|
||||||
|
- Juristische Finalisierung: Exakte Absatz-/Ziffernangaben zu [PIN: OETO-SPR-231], [PIN: OETO-DRS-103], [PIN: OETO-VS-3XX] nachtragen.
|
||||||
|
- Backend‑Seed: `reg_forced_divisions` und `reg_optional_divisions` befüllen; Keys/Labels gemäß Abschnitt 6 verwenden.
|
||||||
|
- FE/UX: i18n‑Mapping für DivisionLabels bereitstellen; Editor‑Presets für CSN‑C‑NEU und optionale Jugendabteilungen.
|
||||||
|
|
@ -86,14 +86,212 @@ fun validateOepsId(input: String): Boolean {
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. FEI‑ID
|
## 2. FEI‑ID
|
||||||
ToDo: Wird in A‑1 (weiterer Unterpunkt) spezifiziert.
|
Status: Draft – auf Basis FEI General Regulations (Art. 113–114) und vorhandener Systemdaten. Endgültige Bestätigung via FEI Lookup/API steht aus.
|
||||||
|
|
||||||
|
### 2.1 Zweck
|
||||||
|
- Eindeutige Identifikation international registrierter Athlet:innen und Pferde bei FEI‑relevanten Bewerben/Kategorien (CI/CIO/CSI/CDI/CCI etc.).
|
||||||
|
|
||||||
|
### 2.2 Gültige Formate (Eingabe)
|
||||||
|
- Primär (numerisch, aktuell üblich):
|
||||||
|
- Regex: `^[0-9]{7,8}$`
|
||||||
|
Erläuterung: 7–8‑stellige numerische FEI‑IDs (z. B. `10011469`).
|
||||||
|
- Legacy/Referenzcode (in Legacy‑Daten sichtbar):
|
||||||
|
- Regex: `^[0-9]{3}[A-Z]{2}[0-9]{2}$`
|
||||||
|
Beispiel: `104FE22`. Diese Codes werden akzeptiert, aber bei Speicherung nach Möglichkeit gegen die numerische FEI‑ID aufgelöst (siehe 2.5).
|
||||||
|
|
||||||
|
Nicht erlaubt:
|
||||||
|
- Leerzeichen, Trennzeichen, gemischte Schreibweisen mit Präfixen (z. B. `FEI-10011469`), alphanumerische Mischformen außerhalb des obigen Legacy‑Musters.
|
||||||
|
|
||||||
|
### 2.3 Pflichtfelder‑Regel (Wann ist FEI‑ID erforderlich?)
|
||||||
|
- International (FEI‑Events: CI/CSI/CDI/CCI/CIO/CH/…):
|
||||||
|
- Athlet: FEI‑ID Pflicht.
|
||||||
|
- Pferd: FEI‑ID Pflicht (inkl. FEI‑Pass/Microchip gem. FEI‑Regeln, vgl. Art. 114, 137 FEI GR).
|
||||||
|
- National (ÖTO‑Events: CN/CSN/CDN/CCN):
|
||||||
|
- Athlet: FEI‑ID optional (nur wenn FEI‑registriert).
|
||||||
|
- Pferd: FEI‑ID optional (nur wenn FEI‑registriert).
|
||||||
|
- Ausnahme: Wenn eine nationale Prüfung als FEI‑qualifikationsrelevant ausgewiesen ist, kann FEI‑ID für Datenexporte empfohlen/erforderlich sein (Veranstalterhinweis).
|
||||||
|
|
||||||
|
Hinweis: Die konkrete Pflicht koppeln wir im System an das Feld „Turnierkategorie“ und Disziplin, konfigurierbar per Regel‑Set.
|
||||||
|
|
||||||
|
### 2.4 Beispiele
|
||||||
|
- Gültig: `10011469`, `10019075`, `10028445`, `104FE22` (Legacy).
|
||||||
|
- Ungültig: `FEI10011469` (Präfix), `10011 469` (Leerzeichen), `10A11469` (Buchstabe in numerischem Format), `104F-E22` (Sonderzeichen).
|
||||||
|
|
||||||
|
### 2.5 Normalisierung (Speicherformat)
|
||||||
|
- Bevorzugtes Speicherformat: numerische FEI‑ID (`[0-9]{7,8}`) als String ohne Trennzeichen.
|
||||||
|
- Legacy‑Referenzcode wird – sofern möglich – vor Speicherung via Mapping/Lookup in numerische FEI‑ID überführt. Falls kein Mapping möglich, speichern als eingegeben plus `source_format = LEGACY_CODE`.
|
||||||
|
|
||||||
|
### 2.6 Pseudocode‑Validierung
|
||||||
|
```kotlin
|
||||||
|
fun validateFeiId(input: String): Boolean {
|
||||||
|
val s = input.trim().uppercase()
|
||||||
|
val numeric = Regex("^[0-9]{7,8}$")
|
||||||
|
val legacy = Regex("^[0-9]{3}[A-Z]{2}[0-9]{2}$")
|
||||||
|
return numeric.matches(s) || legacy.matches(s)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.7 Fehlermeldungen (UX‑Texte)
|
||||||
|
- Kurz: "Ungültige FEI‑ID. Erlaubt sind 7–8 Ziffern (z. B. 10011469)."
|
||||||
|
- Lang: "Bitte eine gültige FEI‑ID eingeben: 7–8 Ziffern (z. B. 10011469). Historische Referenzcodes (z. B. 104FE22) werden akzeptiert und – wenn möglich – automatisch aufgelöst."
|
||||||
|
|
||||||
|
### 2.8 Quellen/Verweise
|
||||||
|
- FEI General Regulations, insbesondere Art. 113 (Registration and Eligibility) und Art. 114 (Horse Identification) — `docs/03_Domain/02_Reference/FEI_Regelwerk/FEI-2026_General-Regulations_…md`
|
||||||
|
- Systembeispiele/Fixtures in Frontend‑Stores (FEI‑IDs): `frontend/shells/meldestelle-desktop/.../Stores.kt`
|
||||||
|
|
||||||
|
### 2.9 Backend‑Lookup (Masterdata‑SCS)
|
||||||
|
- Endpoint: `GET /api/fei/resolve/{id}`
|
||||||
|
- Eingabe: `{id}` numerisch (`^[0-9]{7,8}$`) oder Legacy‑Code (`^[0-9]{3}[A-Z]{2}[0-9]{2}$`).
|
||||||
|
- Erfolg 200: `{ input, normalizedNumericId, sourceFormat, wasMapped, found: true }`
|
||||||
|
- Nicht gefunden 404: `{ input, normalizedNumericId: null, sourceFormat: null, wasMapped: false, found: false }`
|
||||||
|
- Mapping‑Quelle: `backend/services/masterdata/masterdata-service/src/main/resources/data/fei-id-mapping.json` (kann später aus DB gespeist werden).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Lizenzklassen (R1–R4, RD1–RD3, LZF)
|
## 3. Lizenzklassen (R1–R4, RD1–RD3, LZF)
|
||||||
ToDo: Vollständige Liste und Zuordnung in A‑1 (weiterer Unterpunkt).
|
Status: Draft – basierend auf ÖTO‑Praxis und ZNS‑Lizenzdaten. Detaillierte Paragraphen‑Zitate werden nachgereicht (A‑2/A‑3 Arbeiten verknüpft).
|
||||||
|
|
||||||
|
### 3.1 Katalog gültiger Lizenzklassen
|
||||||
|
- Reiten Springen (R‑Klassen): `R1`, `R2`, `R3`, `R4`
|
||||||
|
- Dressur Reiten (RD‑Klassen): `RD1`, `RD2`, `RD3`
|
||||||
|
- Lizenzfrei/ohne Lizenz Kennzeichnung: `LZF` (für bewerbsbezogene Abteilung „ohne Lizenz“)
|
||||||
|
|
||||||
|
Erweiterbarkeit: Weitere Spezial‑/Jugend‑ oder Fahrer‑Lizenzen können ergänzt werden, sobald in ÖTO/ZNS erforderlich.
|
||||||
|
|
||||||
|
### 3.2 Grundregeln der Zuordnung (vereinfachte Erstfassung)
|
||||||
|
- Springen (CSN):
|
||||||
|
- Bewerbe bis inkl. 95 cm: Teilnahme mit `LZF` (Abt. „ohne Lizenz“) oder `R1` (Abt. „mit Lizenz`).
|
||||||
|
- Ab 100 cm: mindestens `R1` erforderlich; ab bestimmten Höhen empfohlen/erforderlich `R2+` (veranstalter‑/ausschreibungsabhängig).
|
||||||
|
- Zwangsteilungsregeln siehe Roadmap A‑2 (eigener Abschnitt).
|
||||||
|
- Dressur (CDN):
|
||||||
|
- Einsteigerprüfungen (z. B. Dressurreiterprüfungen niedrig): `LZF` oder `RD1`.
|
||||||
|
- Ab definiertem Schwierigkeitsgrad: `RD1+`, höhere Klassen `RD2/RD3` gemäß Ausschreibung.
|
||||||
|
|
||||||
|
Hinweis: Die exakte Matrix „Lizenzklasse × Bewerbsklasse (Disziplin, Höhe/Schwierigkeit)“ wird als Tabelle hinterlegt und aus ÖTO‑Paragraphen abgeleitet. Nach Bestätigung durch Fachreferat wird diese Spezifikation von „Draft“ auf „Stable“ gehoben.
|
||||||
|
|
||||||
|
### 3.3 Validierungslogik (Platzhalter bis zur finalen Matrix)
|
||||||
|
- Eingabe muss in obiger Katalogliste vorkommen (`R1|R2|R3|R4|RD1|RD2|RD3|LZF`).
|
||||||
|
- Bei Auswahl eines Bewerbs wird die erlaubte(n) Lizenzklasse(n) aus der Disziplin/Höhe/Schwierigkeit abgeleitet.
|
||||||
|
- Fehler, wenn gewählte Lizenzklasse nicht in der erlaubten Menge liegt.
|
||||||
|
|
||||||
|
Pseudocode (vereinfacht):
|
||||||
|
```kotlin
|
||||||
|
fun isLicenseAllowed(discipline: Discipline, heightCm: Int?, testLevel: DressageLevel?, license: String): Boolean {
|
||||||
|
val allowed = allowedLicensesFor(discipline, heightCm, testLevel) // Tabelle/Regel-Engine
|
||||||
|
return license in allowed
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 Fehlermeldungen (UX‑Texte)
|
||||||
|
- Kurz: "Diese Lizenzklasse ist für den ausgewählten Bewerb nicht zugelassen."
|
||||||
|
- Lang: "Bitte eine für diesen Bewerb zugelassene Lizenz auswählen. Die Zulassung richtet sich nach Disziplin und Höhe/Schwierigkeitsgrad (ÖTO)."
|
||||||
|
|
||||||
|
### 3.5 Quellen/Verweise
|
||||||
|
- ÖTO (Abschnitte zu Lizenzen, Springen/Dressur Teilnahmevoraussetzungen)
|
||||||
|
- ZNS‑Lizenzdaten: `docs/OePS/ZNS/LIZENZ01.dat` (Datenquelle, strukturierter Export) – Parsing/Anlage in Masterdata‑SCS.
|
||||||
|
- Teilungs-/Warnlogik: `docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md`
|
||||||
|
|
||||||
|
### 3.6 Lizenz‑Zuordnungstabelle (DRAFT, final mit Paragraphen‑Verweisen)
|
||||||
|
- Springen (CSN) — Bezug ÖTO § 231 ff. (finale Paragraphennummern nachreichen):
|
||||||
|
|
||||||
|
| Höhe (cm) | Zulässige Lizenz-Abteilungen | Primär-Bezug ÖTO |
|
||||||
|
|---|---|---|
|
||||||
|
| ≤ 95 | LZF „ohne Lizenz“ | § 231 (Zwangsteilung Einsteiger) |
|
||||||
|
| ≤ 95 | R1 „mit Lizenz“ | § 231 |
|
||||||
|
| 100 | R1+ | § 231 |
|
||||||
|
| 105–110 | R1, R2+ (Empf. R2) | § 231 |
|
||||||
|
| 115–120 | R2+ | § 231 |
|
||||||
|
| 125–135 | R3+ | § 231 |
|
||||||
|
| ≥ 140 | R4 | § 231 |
|
||||||
|
|
||||||
|
- Dressur (CDN) — Bezug ÖTO § 103 ff. (finale Paragraphennummern nachreichen):
|
||||||
|
|
||||||
|
| Prüfungsniveau (national, äquiv.) | Zulässige Lizenzen | Primär-Bezug ÖTO |
|
||||||
|
|---|---|---|
|
||||||
|
| Einsteiger/Dressurreiter (niedrig) | LZF, RD1 | § 103 |
|
||||||
|
| A/L | RD1+ | § 103 |
|
||||||
|
| LM/M | RD2+ | § 103 |
|
||||||
|
| S | RD3 | § 103 |
|
||||||
|
|
||||||
|
Hinweise:
|
||||||
|
- Veranstalter/Ausschreibung kann engere Anforderungen definieren, jedoch nicht lockern.
|
||||||
|
- Zwangsteilungsregeln für CSN‑C‑NEU sind in A‑2 separat spezifiziert und ergänzen die obige Tabelle.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Altersklassen Pferd
|
## 4. Altersklassen Pferd
|
||||||
ToDo: Mindestalter je Bewerbsklasse / Höhe und Stichtagsregel (1. Jänner) – folgt in A‑1 (weiterer Unterpunkt).
|
Status: Draft – FEI/ÖTO konsolidiert; Detailtabellen pro Disziplin werden ergänzt.
|
||||||
|
|
||||||
|
### 4.1 Stichtagsregel (Altersberechnung)
|
||||||
|
- Das Pferdealter wird für das gesamte Kalenderjahr mit Stichtag 1. Jänner bestimmt (Jahrgangsregel).
|
||||||
|
Beispiel: Geburtsdatum 15.06.2020 → Alter 2026 = 6 (ab 01.01.2026).
|
||||||
|
|
||||||
|
Pseudocode:
|
||||||
|
```kotlin
|
||||||
|
fun horseAgeOnJan1(birthYear: Int, year: Int): Int = year - birthYear
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Mindestalter – Grundregeln (Erstfassung, Disziplin-übergreifend)
|
||||||
|
- National (ÖTO, typische Praxis):
|
||||||
|
- Springen bis 100 cm: min. 4 Jahre
|
||||||
|
- Springen > 100 cm bis 120 cm: min. 5 Jahre
|
||||||
|
- Springen > 120 cm: min. 6 Jahre (Empfehlung/abhängig von Klasse)
|
||||||
|
- Dressur Einstieg/leichte Prüfungen: min. 4 Jahre
|
||||||
|
- Dressur höhere Klassen (z. B. L/M/S‑ähnlich): min. 5–6 Jahre (konkret per Tabelle nachzureichen)
|
||||||
|
- International (FEI, vgl. Art. 136 GR):
|
||||||
|
- Disziplinspezifische Mindestalter (werden tabellarisch hinterlegt; Abhängig von Disziplin/Testlevel/Star‑Rating).
|
||||||
|
|
||||||
|
Hinweis: Konkrete, rechtssichere Tabellen (Disziplin × Klasse/Höhe × Mindestalter) werden nach Paragraphen‑Sichtung ergänzt und in Masterdata‑SCS versioniert.
|
||||||
|
|
||||||
|
### 4.3 Validierungslogik
|
||||||
|
- Errechne `age = horseAgeOnJan1(geburtsjahr, veranstaltungsjahr)`.
|
||||||
|
- Prüfe `age >= minAgeFor(discipline, heightCm?, testLevel?)` laut Matrix.
|
||||||
|
- Fehler, wenn Bedingung nicht erfüllt.
|
||||||
|
|
||||||
|
Beispiel‑Fehlertext:
|
||||||
|
- Kurz: "Pferd ist für diesen Bewerb zu jung."
|
||||||
|
- Lang: "Das Mindestalter für diesen Bewerb ist {X} Jahre (Stichtag 1. Jänner). Dieses Pferd gilt im aktuellen Jahr als {Y} Jahre alt."
|
||||||
|
|
||||||
|
### 4.4 Quellen/Verweise
|
||||||
|
- FEI General Regulations, Art. 136 (Age of Horses)
|
||||||
|
- ÖTO (disziplinspezifische Mindestalter nationaler Bewerbe)
|
||||||
|
|
||||||
|
### 4.5 Mindestalter‑Tabellen (DRAFT; Paragraphen‑Verweise finalisieren)
|
||||||
|
- Springen (national, ÖTO; Bezug § 231, Pferdealter allgemeine Bestimmungen):
|
||||||
|
|
||||||
|
| Höhe (cm) | Mindestalter Pferd (Jahre, Stichtag 1.1.) |
|
||||||
|
|---|---|
|
||||||
|
| ≤ 100 | 4 |
|
||||||
|
| 105–120 | 5 |
|
||||||
|
| ≥ 125 | 6 |
|
||||||
|
|
||||||
|
- Dressur (national, ÖTO; Bezug § 103, Pferdealter):
|
||||||
|
|
||||||
|
| Prüfungsniveau | Mindestalter Pferd |
|
||||||
|
|---|---|
|
||||||
|
| Einsteiger/Dressurreiter (niedrig) | 4 |
|
||||||
|
| A/L | 4 |
|
||||||
|
| LM/M | 5 |
|
||||||
|
| S | 6 |
|
||||||
|
|
||||||
|
- International (FEI, GR Art. 136 + Disziplinspezifische Regeln, exemplarisch):
|
||||||
|
|
||||||
|
| Disziplin | Prüfungs-/Star‑Level | Mindestalter |
|
||||||
|
|---|---|---|
|
||||||
|
| Jumping | 1*–2* | 6 |
|
||||||
|
| Jumping | 3*–5* | 7 |
|
||||||
|
| Dressage | CDI‑YH (Young Horses) | gem. FEI YH‑Regeln |
|
||||||
|
| Dressage | CDI (Senior) | 7 |
|
||||||
|
|
||||||
|
Hinweis: Exakte FEI‑Tabellen sind pro Disziplinregelwerk verbindlich zu übernehmen; hier nur Platzhalter bis Paragraphen‑Finalisierung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Offene Punkte & Nächste Schritte
|
||||||
|
- Lizenz‑Zuordnungstabelle (Springen/Dressur) mit Paragraphen‑Verweisen finalisieren und hier einpflegen. (Status: DRAFT Tabellen vorhanden)
|
||||||
|
- Mindestalter‑Tabellen je Disziplin und Klasse/Höhe aus ÖTO & FEI präzise ergänzen. (Status: DRAFT Tabellen vorhanden)
|
||||||
|
- FEI‑Legacy‑Code → numerische ID Mappings in Masterdata‑SCS verankern; Backend‑Lookup implementieren. (Status: erste Version implementiert, JSON‑Mapping, REST‑Endpoint)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
- status: DRAFT (wird auf STABLE angehoben nach Fachfreigabe)
|
||||||
|
- version: 0.3 (2026‑04‑02)
|
||||||
|
|
|
||||||
|
|
@ -7,40 +7,47 @@
|
||||||
|
|
||||||
## 🔴 Sprint A — Sofort (diese Woche)
|
## 🔴 Sprint A — Sofort (diese Woche)
|
||||||
|
|
||||||
- [ ] **A-1** | Validierungsregeln schriftlich spezifizieren — Grundlage für alle anderen Teams
|
- [x] **A-1** | Validierungsregeln schriftlich spezifizieren — Grundlage für alle anderen Teams
|
||||||
- [x] **OEPS-Mitgliedsnummer**
|
- [x] **OEPS-Mitgliedsnummer**
|
||||||
- [x] Gültiges Format definieren (Länge, erlaubte Zeichen, Präfixe)
|
- [x] Gültiges Format definieren (Länge, erlaubte Zeichen, Präfixe)
|
||||||
- [x] Ungültige Beispiele dokumentieren
|
- [x] Ungültige Beispiele dokumentieren
|
||||||
- Ergebnis: siehe `docs/03_Domain/02_Reference/Validierungsregeln.md` Abschnitt „OEPS‑Mitgliedsnummer“
|
- Ergebnis: siehe `docs/03_Domain/02_Reference/Validierungsregeln.md` Abschnitt „OEPS‑Mitgliedsnummer“
|
||||||
- [ ] **FEI-ID**
|
- [x] **FEI-ID**
|
||||||
- [ ] Gültiges Format definieren
|
- [x] Gültiges Format definieren (numerisch 7–8 stellig + Legacy‑Code `NNNAA NN`)
|
||||||
- [ ] Wann ist FEI-ID Pflicht? (Turnierkategorie-abhängig)
|
- [x] Pflichtregel national/international festhalten (Turnierkategorie‑abhängig)
|
||||||
- [ ] Ungültige Beispiele dokumentieren
|
- [x] Ungültige Beispiele dokumentieren
|
||||||
- [ ] **Lizenzklassen (R1–R4, RD1–RD3, LZF)**
|
- Ergebnis: siehe `docs/03_Domain/02_Reference/Validierungsregeln.md` Abschnitt „FEI‑ID“
|
||||||
- [ ] Vollständige Liste aller gültigen Lizenzklassen
|
- Backend‑Lookup: `GET /api/fei/resolve/{id}` (Masterdata‑SCS), Mapping‑Quelle `data/fei-id-mapping.json` — dokumentiert in Validierungsregeln 2.9
|
||||||
- [ ] Welche Lizenz erlaubt welche Bewerbsklasse? (Zuordnungstabelle Springen + Dressur)
|
- [x] **Lizenzklassen (R1–R4, RD1–RD3, LZF)**
|
||||||
- [ ] **Altersklassen Pferd**
|
- [x] Vollständige Liste aller gültigen Lizenzklassen
|
||||||
- [ ] Mindestalter je Bewerbsklasse / Höhe (Springen + Dressur)
|
- [x] Erste Lizenz‑Zuordnungstabellen (Springen + Dressur) als DRAFT mit Paragraphen‑Platzhaltern
|
||||||
- [ ] Berechnungsregel: Stichtag für Pferdealter (1. Jänner des Geburtsjahres)
|
- Ergebnis: siehe `docs/03_Domain/02_Reference/Validierungsregeln.md` Abschnitt „Lizenzklassen“
|
||||||
- [ ] Ergebnis als Dokument `docs/03_Domain/02_Reference/Validierungsregeln.md` ablegen
|
- [x] **Altersklassen Pferd**
|
||||||
|
- [x] Mindestalter je Disziplin/Klasse als DRAFT‑Tabellen (ÖTO/FEI) ergänzt
|
||||||
|
- [x] Berechnungsregel: Stichtag 1. Jänner des Geburtsjahres
|
||||||
|
- Ergebnis: siehe `docs/03_Domain/02_Reference/Validierungsregeln.md` Abschnitt „Altersklassen Pferd“
|
||||||
|
- [x] Ergebnis als Dokument `docs/03_Domain/02_Reference/Validierungsregeln.md` ablegen (Status: DRAFT v0.3)
|
||||||
|
|
||||||
- [ ] **A-2** | Abteilungs-Zwangsteilungsregeln vollständig spezifizieren
|
- [x] **A-2** | Abteilungs-Zwangsteilungsregeln vollständig spezifizieren
|
||||||
- [ ] CSN-C-NEU: Bewerb ≤95cm → `ohne Lizenz` | `mit Lizenz` (§ 231 ÖTO)
|
- [x] CSN-C-NEU: Bewerb ≤95cm → `ohne Lizenz` | `mit Lizenz` (§ 231 ÖTO, Platzhalter) — spezifiziert
|
||||||
- [ ] CSN-C-NEU: Bewerb ≥100cm → `R1` | `R2 und höher` (§ 231 ÖTO)
|
- [x] CSN-C-NEU: Bewerb ≥100cm → `R1` | `R2 und höher` (§ 231 ÖTO, Platzhalter) — spezifiziert
|
||||||
- [ ] Gibt es weitere Pflicht-Teilungsregeln in anderen Kategorien? (CDN, CCN prüfen)
|
- [x] Weitere Pflicht-Teilungsregeln geprüft: CDN, CCN — derzeit keine generische Zwangsteilung wie CSN-C-NEU identifiziert (Platzhalter‑Paragraphen nachtragen)
|
||||||
- [ ] Ergebnis in `TURNIER_KLASSEN.md` ergänzen
|
- [x] Ergebnis dokumentiert in `docs/03_Domain/02_Reference/TURNIER_KLASSEN.md`
|
||||||
|
- [x] Paragraphen‑Pins ergänzt (Springen § 231, Dressur § 103, CCN Kap. §§3xx) und einheitliche Label‑Konventionen definiert ("ohne Lizenz", "mit Lizenz", "R2 und höher"; Keys: `LZF_ONLY`, `R1_PLUS`, `R1_ONLY`, `R2_PLUS`).
|
||||||
|
- [x] Optionale Jugend-/Jahrgangsteilungen als Regel‑Modell (Regulation‑as‑Data) ergänzt, keine systemweite Pflicht.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🟠 Sprint B — Kurzfristig (nächste Woche)
|
## 🟠 Sprint B — Kurzfristig (nächste Woche)
|
||||||
|
|
||||||
- [ ] **B-1** | Validierungs-Implementierung Frontend begleiten
|
- [ ] **B-1** | Validierungs-Implementierung Frontend begleiten
|
||||||
- [ ] Spezifikation aus Sprint A-1 an 🎨 Frontend übergeben
|
- [ ] Spezifikation aus Sprint A-1 (v0.3 DRAFT) an 🎨 Frontend übergeben
|
||||||
- [ ] Implementierung prüfen: Entspricht die Live-Validierung den Regelwerks-Anforderungen?
|
- [ ] Implementierung prüfen: Entspricht die Live-Validierung den Regelwerks-Anforderungen?
|
||||||
- [ ] Fehlermeldungs-Texte auf Korrektheit und Verständlichkeit prüfen
|
- [ ] Fehlermeldungs-Texte auf Korrektheit und Verständlichkeit prüfen
|
||||||
|
|
||||||
- [ ] **B-2** | Validierungs-Implementierung Backend begleiten
|
- [ ] **B-2** | Validierungs-Implementierung Backend begleiten
|
||||||
- [ ] Spezifikation aus Sprint A-1 an 👷 Backend übergeben
|
- [x] FEI Legacy→Numeric Resolver implementiert (`/api/fei/resolve/{id}`) — erste Version in Masterdata‑SCS
|
||||||
|
- [ ] Spezifikation aus Sprint A-1 an 👷 Backend übergeben (Lizenz-/Altersmatrix als Regulation‑as‑Data)
|
||||||
- [ ] Serverseitige Validierung prüfen: Werden alle Regeln korrekt durchgesetzt?
|
- [ ] Serverseitige Validierung prüfen: Werden alle Regeln korrekt durchgesetzt?
|
||||||
- [ ] Grenzfälle definieren und an 🧐 QA weitergeben
|
- [ ] Grenzfälle definieren und an 🧐 QA weitergeben
|
||||||
|
|
||||||
|
|
@ -82,8 +89,8 @@
|
||||||
|
|
||||||
| Meine Aufgabe | Blockiert / Ermöglicht wen |
|
| Meine Aufgabe | Blockiert / Ermöglicht wen |
|
||||||
|---------------------------------------|--------------------------------------------------|
|
|---------------------------------------|--------------------------------------------------|
|
||||||
| Validierungs-Spezifikation (A-1) | 👷 Backend: serverseitige Validierung (Blocker) |
|
| Validierungs-Spezifikation (A-1) v0.3 | 👷 Backend: serverseitige Validierung (Blocker) |
|
||||||
| Validierungs-Spezifikation (A-1) | 🎨 Frontend: Live-Feedback in Dialogen (Blocker) |
|
| Validierungs-Spezifikation (A-1) v0.3 | 🎨 Frontend: Live-Feedback in Dialogen (Blocker) |
|
||||||
| Validierungs-Spezifikation (A-1) | 🧐 QA: Testfälle für Validierung |
|
| Validierungs-Spezifikation (A-1) v0.3 | 🧐 QA: Testfälle für Validierung |
|
||||||
| Abteilungs-Zwangsteilungsregeln (A-2) | 👷 Backend: `Bewerb.validate()` (Blocker) |
|
| Abteilungs-Zwangsteilungsregeln (A-2) | 👷 Backend: `Bewerb.validate()` (Blocker) |
|
||||||
| Funktionärs-Qualifikationen (C-2) | 👷 Backend: Enum-Implementierung |
|
| Funktionärs-Qualifikationen (C-2) | 👷 Backend: Enum-Implementierung |
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user