diff --git a/docs/03_Domain/00_Glossary.md b/docs/03_Domain/00_Glossary.md index bc223343..4f853d28 100644 --- a/docs/03_Domain/00_Glossary.md +++ b/docs/03_Domain/00_Glossary.md @@ -1,8 +1,40 @@ - # Glossar der Domäne "Meldestelle" +# Glossar der Domäne "Meldestelle" - Dieses Dokument definiert die Ubiquitous Language des Projekts. +Dieses Dokument definiert die **Ubiquitous Language** (allgegenwärtige Sprache) des Projekts. Alle Begriffe sind so zu verwenden, wie sie hier definiert sind – sowohl im Code als auch in der Kommunikation. - * **Event:** Der organisatorische Rahmen für eine Veranstaltung. - * **Turnier:** Die administrative, regelbasierte Einheit innerhalb eines Events. - * ... - +## A - E + +* **Abteilung:** Eine Unterteilung eines -> *Bewerbs*. Oft werden Bewerbe mit vielen Startern in mehrere Abteilungen geteilt (z.B. nach Lizenzklasse oder Rasse), die getrennt gewertet werden. +* **Akteur:** Oberbegriff für alle Personen (Reiter, Richter, Besitzer) und Organisationen (Vereine), die im System interagieren. +* **Ausschreibung:** Das offizielle Dokument, das alle Bedingungen eines -> *Turniers* festlegt. +* **Bewerb:** Die einzelne sportliche Prüfung (z.B. "Springprüfung Kl. L"). Kleinste Einheit für Nennungen und Ergebnisse. +* **Event:** Der organisatorische Rahmen (z.B. "Pferdefest 2026"), der ein oder mehrere -> *Turniere* beinhalten kann. + +## F - J + +* **FEI-ID:** Eindeutige Identifikationsnummer der Internationalen Reiterlichen Vereinigung (FEI) für Reiter und Pferde. +* **Gastreiter:** Ein Reiter mit ausländischer Staatsbürgerschaft, der nicht für einen österreichischen Verein startet. +* **Kopfnummer:** + * *National (OEPS):* Die permanente, 4-stellige Registrierungsnummer eines Pferdes beim OEPS (z.B. "A123"). Wird oft am Zaumzeug getragen. + * *International/Turnier:* Eine temporäre Startnummer für das spezifische Turnier. + +## K - O + +* **Lebensnummer:** Eine 9-stellige Nummer (bzw. 15-stellig international), die ein Pferd bei der Geburt vom Zuchtverband erhält. Dient der eindeutigen Identifizierung, ist aber im OEPS-Kontext bei ausländischen Pferden oft generiert und daher nicht zur Suche geeignet. +* **Lizenz:** Die Qualifikationsstufe eines Reiters (z.B. "R1", "RD3"). Bestimmt, in welchen Klassen er startberechtigt ist. +* **Nennung:** Die verbindliche Anmeldung eines Paares (Reiter & Pferd) zu einem -> *Bewerb*. +* **OEPS:** Österreichischer Pferdesportverband. + +## P - T + +* **Satznummer:** + * *Pferd:* 10-stellige, rein numerische ID (z.B. `0000123456`), die ein Pferd in der OEPS-Datenbank eindeutig identifiziert. **Primärer Schlüssel für den Datenaustausch.** + * *Reiter:* 6-stellige, rein numerische ID für Personen. +* **Sperrliste:** Eine vom Verband geführte Liste von Personen oder Pferden, die aktuell nicht startberechtigt sind (meist wegen offener Zahlungen). +* **Startkarte:** Der Nachweis, dass die Jahresgebühr für die Lizenz bezahlt wurde. Ohne aktive Startkarte ist (national) kein Start möglich. +* **Turnier:** Die administrative Einheit (z.B. "CSN-A"), die einem spezifischen Regelwerk (ÖTO oder FEI) unterliegt. + +## U - Z + +* **Wertungsserie:** Ein übergeordneter Wettbewerb (Cup, Meisterschaft), der Ergebnisse aus mehreren Bewerben/Turnieren aggregiert. +* **ZNS:** Zentrales Nennsystem (bzw. die zugehörigen Datensätze wie `zns.zip`), über das Stammdaten und Nennungen ausgetauscht werden. diff --git a/docs/03_Domain/01_Core_Model/Entities/Database_Schema.sql b/docs/03_Domain/01_Core_Model/Entities/Database_Schema.sql new file mode 100644 index 00000000..a3e2e4a0 --- /dev/null +++ b/docs/03_Domain/01_Core_Model/Entities/Database_Schema.sql @@ -0,0 +1,241 @@ +-- Database Schema Draft for Meldestelle (Offline-First) +-- Dialect: SQLite (compatible with SQLDelight) +-- Status: Draft / Proposal +-- Based on: OEPS Legacy Spec V2.4 & Domain Analysis + +-- ================================================================== +-- 1. CORE INFRASTRUCTURE (Sync & Audit) +-- ================================================================== +-- Every table should ideally have these fields, but for brevity +-- they are implied or added where critical. +-- id: TEXT NOT NULL PRIMARY KEY (UUID) +-- created_at: INTEGER NOT NULL (Epoch Millis) +-- updated_at: INTEGER NOT NULL (Epoch Millis) +-- version: INTEGER NOT NULL (Optimistic Locking / Sync Counter) +-- is_deleted: INTEGER NOT NULL DEFAULT 0 (Soft Delete) + +-- ================================================================== +-- 2. MASTER DATA (Stammdaten) +-- ================================================================== + +-- Akteure: Personen und Organisationen +-- Covers: Reiter, Richter, Besitzer, Vereine +CREATE TABLE actor ( + id TEXT NOT NULL PRIMARY KEY, + type TEXT NOT NULL, -- 'PERSON', 'ORGANIZATION' + + -- Display Data + first_name TEXT, -- NULL for Organizations + last_name TEXT NOT NULL, -- Name or Org-Name + + -- OEPS Specifics (Legacy Spec) + oeps_id TEXT, -- 'Satznummer' (6 digits for Person, 4 for Club) + oeps_category TEXT, -- 'Verein', 'Reiter', 'Richter' + + -- Licenses & Status + license_code TEXT, -- e.g. 'R1', 'RD3' + has_start_card INTEGER NOT NULL DEFAULT 0, -- Boolean: Paid annual fee? + is_locked INTEGER NOT NULL DEFAULT 0, -- Boolean: Sperrliste? + + -- Contact & Meta + nationality TEXT NOT NULL DEFAULT 'AUT', -- ISO 3-Letter + contact_json TEXT, -- Address, Phone, Email + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL, + version INTEGER NOT NULL DEFAULT 1 +); + +CREATE INDEX idx_actor_oeps_id ON actor(oeps_id); +CREATE INDEX idx_actor_name ON actor(last_name, first_name); + + +-- Pferde +CREATE TABLE horse ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + + -- Identification + oeps_id TEXT, -- 'Satznummer' (10 digits) - CRITICAL for Export + head_number_permanent TEXT, -- 'Kopfnummer' (e.g. A123) + life_number TEXT, -- 'Lebensnummer' (Zucht) + fei_id TEXT, + + -- Details + birth_year INTEGER, + gender TEXT, -- 'M', 'W', 'G' (Gelding/Wallach) + color TEXT, + sire_name TEXT, -- Vater (Denormalized for search) + dam_name TEXT, -- Mutter + + -- Owner Link + owner_id TEXT, -- FK to actor.id + + -- Status + is_locked INTEGER NOT NULL DEFAULT 0, -- Sperrliste + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL, + version INTEGER NOT NULL DEFAULT 1 +); + +CREATE INDEX idx_horse_oeps_id ON horse(oeps_id); +CREATE INDEX idx_horse_head_num ON horse(head_number_permanent); +CREATE INDEX idx_horse_name ON horse(name); + +-- ================================================================== +-- 3. EVENT STRUCTURE +-- ================================================================== + +CREATE TABLE event ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + start_date INTEGER NOT NULL, -- Epoch Day + end_date INTEGER NOT NULL, + location TEXT, + organizer_id TEXT NOT NULL, -- FK to actor.id + + status TEXT NOT NULL DEFAULT 'PLANNING' -- PLANNING, ACTIVE, ARCHIVED +); + +CREATE TABLE tournament ( + id TEXT NOT NULL PRIMARY KEY, + event_id TEXT NOT NULL REFERENCES event(id), + + -- OEPS Spec + oeps_number TEXT NOT NULL, -- 5 digits (e.g. 21001) + category TEXT, -- e.g. 'CSN-A' + ruleset TEXT NOT NULL DEFAULT 'OETO', -- 'OETO', 'FEI' + + -- Sync Meta + updated_at INTEGER NOT NULL +); + +-- Bewerbe (Competitions) +-- Note: If a competition is split into 2 departments (Abteilungen), +-- we create 2 rows here to match the OEPS 'B-Satz' logic. +CREATE TABLE competition ( + id TEXT NOT NULL PRIMARY KEY, + tournament_id TEXT NOT NULL REFERENCES tournament(id), + + -- Identification + code_internal TEXT NOT NULL, -- '01', '02' (2 digits) + code_official TEXT, -- '001' (3 digits, optional) + division_id INTEGER NOT NULL DEFAULT 0, -- 'Abteilung' (0=None, 1=1st, 2=2nd) + + -- Description + title TEXT NOT NULL, + category TEXT, -- e.g. 'LM', 'S*' + discipline TEXT NOT NULL, -- 'D', 'S', 'C' (Dressage, Jumping, Combined) + + -- Rules & Scoring + scoring_method TEXT NOT NULL, -- 'A0', 'C', 'DRESSAGE_PERCENT' + start_fee INTEGER NOT NULL DEFAULT 0, -- In Cents + + -- State + status TEXT NOT NULL DEFAULT 'OPEN', -- OPEN, CLOSED_FOR_ENTRIES, RUNNING, FINISHED, SIGNED_OFF + + -- Sync Meta + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_comp_tournament ON competition(tournament_id); + +-- ================================================================== +-- 4. SPORT & PROCESS +-- ================================================================== + +-- Nennungen (Entries) +-- Represents the intent to start. +CREATE TABLE entry ( + id TEXT NOT NULL PRIMARY KEY, + competition_id TEXT NOT NULL REFERENCES competition(id), + + -- The Pair + horse_id TEXT NOT NULL REFERENCES horse(id), + rider_id TEXT NOT NULL REFERENCES actor(id), + + -- Financials + responsible_person_id TEXT REFERENCES actor(id), -- Who pays? + fee_agreed INTEGER NOT NULL, -- In Cents (Snapshot of price at entry time) + payment_status TEXT NOT NULL DEFAULT 'PENDING', -- PENDING, PAID, WAIVED + + -- Validation Override (The "Human Factor") + validation_status TEXT NOT NULL DEFAULT 'OK', -- OK, WARNING, BLOCKED + override_comment TEXT, -- Why was this allowed despite warning? + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_entry_comp ON entry(competition_id); +CREATE INDEX idx_entry_rider ON entry(rider_id); + +-- Startliste (Start Order) +-- Subset of entries that actually start. +CREATE TABLE start_list_entry ( + id TEXT NOT NULL PRIMARY KEY, + entry_id TEXT NOT NULL REFERENCES entry(id), + + -- Ordering + start_order INTEGER, -- 1, 2, 3... + start_time_planned INTEGER, -- Epoch Millis (optional) + + -- Tournament Specifics + head_number_event TEXT, -- Startnummer am Turnier (kann von A123 abweichen) + + -- Status + status TEXT NOT NULL DEFAULT 'READY', -- READY, STARTED, DNS (Did Not Start) + + UNIQUE(entry_id) +); + +-- Ergebnisse (Results) +CREATE TABLE result ( + id TEXT NOT NULL PRIMARY KEY, + start_list_entry_id TEXT NOT NULL REFERENCES start_list_entry(id), + + -- The Outcome + rank INTEGER, -- 1, 2, 3... (NULL if eliminated) + + -- Scoring Details (Polymorphic based on Competition Type) + points_jump_faults DECIMAL(5,2), -- Springfehler + time_taken_ms INTEGER, -- Zeit in Millisekunden + score_dressage_percent DECIMAL(5,3), -- 72.500 + score_dressage_total DECIMAL(6,2), -- Summe Punkte + + -- Status Flags + classification TEXT NOT NULL DEFAULT 'OK', -- OK, EL (Elim), RET (Retired), DIS (Disq) + + -- Detailed Marks (JSON) + -- e.g. { "judge_C": 7.5, "judge_H": 7.2, "obstacles": [...] } + details_json TEXT, + + -- Money + prize_money INTEGER DEFAULT 0, -- In Cents + + -- Audit + updated_by_user_id TEXT, + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_result_starter ON result(start_list_entry_id); + +-- ================================================================== +-- 5. AUDIT LOG (NFR-07) +-- ================================================================== + +CREATE TABLE audit_log ( + id TEXT NOT NULL PRIMARY KEY, + entity_type TEXT NOT NULL, -- 'RESULT', 'ENTRY' + entity_id TEXT NOT NULL, + action TEXT NOT NULL, -- 'CREATE', 'UPDATE', 'DELETE' + + user_id TEXT, + timestamp INTEGER NOT NULL, + + changes_json TEXT -- { "score_old": 7.0, "score_new": 7.5 } +); diff --git a/docs/03_Domain/01_Core_Model/Entities/Overview.md b/docs/03_Domain/01_Core_Model/Entities/Overview.md index 82fc80da..52232f1b 100644 --- a/docs/03_Domain/01_Core_Model/Entities/Overview.md +++ b/docs/03_Domain/01_Core_Model/Entities/Overview.md @@ -1,6 +1,8 @@ # 01 - Core Domain Entities -Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) des "Meldestelle"-Projekts. Diese Entitäten bilden das Fundament des Datenmodells und der gesamten Anwendungslogik. Sie sind das Ergebnis der Analyse der OEPS/ÖTO- und FEI-Regelwerke sowie der grundlegenden Anforderungen an das System. +Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) des "Meldestelle"-Projekts. Diese Entitäten bilden das Fundament des Datenmodells und der gesamten Anwendungslogik. + +> **Hinweis:** Dieses Modell wurde basierend auf der Analyse des OEPS-Pflichtenhefts 2021 V2.4 verfeinert. ## Die 6 Kern-Entitäten @@ -20,7 +22,7 @@ Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) **Beispiele:** "Apropos Pferd 2026", "Vereinsturnier Reitclub XY". **Attribute:** -* `Event-ID` (PK): Eindeutiger technischer Schlüssel. +* `Event-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Name`: Offizieller Name des Events. * `Veranstaltungsort`: Adresse und Name der Anlage. * `Datum_Von`: Startdatum des Events. @@ -37,8 +39,9 @@ Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) **Beispiele:** "CSN-A im Rahmen der Apropos Pferd", "CSI2* im Rahmen der Apropos Pferd". **Attribute:** -* `Turnier-ID` (PK): Eindeutiger technischer Schlüssel. +* `Turnier-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Event_ID` (FK): Verweis auf das übergeordnete `Event`. +* `Turniernummer_OEPS`: 5-stellige Nummer (z.B. `21001`) für den Datenaustausch. * `Regelwerk`: Entscheidende Weiche für die Anwendungslogik (Enum: `OETO`, `FEI`). * `Kategorie`: Offizielle Turnierkategorie (z.B. "CSN-A", "CSI2*", "CDI-W"). * `Disziplinen`: Liste der angebotenen Sportarten (z.B. `Springen`, `Dressur`). @@ -55,11 +58,13 @@ Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) **Beispiele:** "Standardspringprüfung Kl. L", "Dressurprüfung Kl. M - Aufgabe M5". **Attribute:** -* `Bewerb-ID` (PK): Eindeutiger technischer Schlüssel. +* `Bewerb-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Turnier_ID` (FK): Verweis auf das zugehörige `Turnier`. -* `Nummer`: Die offizielle Nummer des Bewerbs laut Ausschreibung (z.B. "05"). +* `Nummer_Intern`: 2-stellige Nummer (z.B. `05`). +* `Nummer_Offiziell`: 3-stellige Nummer (z.B. `005`) für Turniere > 99 Bewerbe. +* `Abteilung`: Kennzeichen für Unterteilungen (z.B. `1`, `2`). Default `0`. * `Titel`: Der offizielle Titel des Bewerbs. -* `Startgeld`: Das für diesen Bewerb zu entrichtende Startgeld. +* `Startgeld`: Das für diesen Bewerb zu entrichtende Startgeld (in EUR). * `Startberechtigung_Text`: Textuelle Beschreibung der Teilnahmevoraussetzungen. * `Besondere_Bestimmungen`: Spezielle Regeln nur für diesen Bewerb. @@ -72,7 +77,7 @@ Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) **Beispiele:** "Casino Grand Prix 2026", "OÖ Landesmeisterschaft Dressur Allgemeine Klasse". **Attribute:** -* `Serie-ID` (PK): Eindeutiger technischer Schlüssel. +* `Serie-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Name`: Offizieller Name der Serie. * `Saison`: Das Jahr, in dem die Serie stattfindet. * `Reglement_Text`: Die spezifischen Regeln für die Wertung (Punktesystem, etc.). @@ -83,37 +88,43 @@ Dieses Dokument definiert die zentralen fachlichen Entitäten (Kern-Entitäten) ### 5. Entität: `Akteur` -**Zweck:** Zentrale, widerspruchsfreie Verwaltung aller beteiligten Personen und Organisationen, unabhängig von ihrer Rolle. +**Zweck:** Zentrale, widerspruchsfreie Verwaltung aller beteiligten Personen und Organisationen. **Beispiele:** Ein Reiter, ein Pferdebesitzer, ein Züchter, ein Richter, ein Reitverein. **Attribute:** -* `Akteur-ID` (PK): Eindeutiger technischer Schlüssel. +* `Akteur-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Typ`: `PERSON` oder `ORGANISATION`. * `Name`: Vollständiger Name der Person oder Organisation. * `Kontakt`: Adress- und Kontaktdaten. -* `Rollen`: Eine Liste der Rollen, die dieser Akteur einnimmt (z.B. `REITER`, `PFERDEBESITZER`, `ZÜCHTER`, `FUNKTIONÄR`, `VERANSTALTER`). -* `Identifikatoren`: Ein flexibler Speicher (z.B. JSON oder eigene Tabelle) für alle offiziellen Nummern: - * `OEPS-Lizenznummer` - * `FEI-ID` - * `Mitgliedsnummer_Zuchtverband` +* `Rollen`: Liste der Rollen (z.B. `REITER`, `RICHTER`). +* **OEPS-Daten (für Personen):** + * `Satznummer`: 6-stellig, numerisch (Primärschlüssel OEPS). + * `Lizenz`: Aktueller Lizenzcode (z.B. "R1"). + * `Startkarte`: Boolean/Status (Jahresgebühr bezahlt?). + * `Verein_ID`: Verweis auf den Stammverein. +* **Identifikatoren (Sonstige):** + * `FEI-ID` + * `Mitgliedsnummer_Zuchtverband` --- ### 6. Entität: `Pferd` -**Zweck:** Zentrale Verwaltung aller Pferde, egal ob im Sport oder in der Zucht, mit all ihren unterschiedlichen Identitäten. +**Zweck:** Zentrale Verwaltung aller Pferde, egal ob im Sport oder in der Zucht. -**Beispiele:** Ein international erfolgreiches Sportpferd, eine Zuchtstute, ein junges Pferd in Ausbildung. +**Beispiele:** Ein international erfolgreiches Sportpferd, eine Zuchtstute. **Attribute:** -* `Pferd-ID` (PK): Eindeutiger technischer Schlüssel. +* `Pferd-ID` (PK): Eindeutiger technischer Schlüssel (UUID). * `Name`: Offizieller Name des Pferdes. * `Abstammung_Vater_ID` (FK): Verweis auf ein anderes `Pferd` (Vater). * `Abstammung_Mutter_ID` (FK): Verweis auf ein anderes `Pferd` (Mutter). * `Besitzer_ID` (FK): Verweis auf den `Akteur`, dem das Pferd gehört. -* `Identifikatoren`: Ein flexibler Speicher für alle offiziellen Nummern: - * `Lebensnummer` (aus der Zucht) - * `OEPS-Registrierungsnummer` - * `FEI-ID` - * `Chip-Nummer` +* **OEPS-Daten:** + * `Satznummer`: 10-stellig, numerisch (Primärschlüssel OEPS). + * `Kopfnummer`: 4-stellig, alphanumerisch (Permanente ID). + * `Lebensnummer`: 9-stellig (Zuchtnummer). +* **FEI-Daten:** + * `FEI-ID`: Eindeutige FEI-Nummer. + * `FEI-Pass`: Passnummer (kann abweichen). diff --git a/docs/03_Domain/03_Analysis/Database_Schema_Draft.sql b/docs/03_Domain/03_Analysis/Database_Schema_Draft.sql new file mode 100644 index 00000000..a3e2e4a0 --- /dev/null +++ b/docs/03_Domain/03_Analysis/Database_Schema_Draft.sql @@ -0,0 +1,241 @@ +-- Database Schema Draft for Meldestelle (Offline-First) +-- Dialect: SQLite (compatible with SQLDelight) +-- Status: Draft / Proposal +-- Based on: OEPS Legacy Spec V2.4 & Domain Analysis + +-- ================================================================== +-- 1. CORE INFRASTRUCTURE (Sync & Audit) +-- ================================================================== +-- Every table should ideally have these fields, but for brevity +-- they are implied or added where critical. +-- id: TEXT NOT NULL PRIMARY KEY (UUID) +-- created_at: INTEGER NOT NULL (Epoch Millis) +-- updated_at: INTEGER NOT NULL (Epoch Millis) +-- version: INTEGER NOT NULL (Optimistic Locking / Sync Counter) +-- is_deleted: INTEGER NOT NULL DEFAULT 0 (Soft Delete) + +-- ================================================================== +-- 2. MASTER DATA (Stammdaten) +-- ================================================================== + +-- Akteure: Personen und Organisationen +-- Covers: Reiter, Richter, Besitzer, Vereine +CREATE TABLE actor ( + id TEXT NOT NULL PRIMARY KEY, + type TEXT NOT NULL, -- 'PERSON', 'ORGANIZATION' + + -- Display Data + first_name TEXT, -- NULL for Organizations + last_name TEXT NOT NULL, -- Name or Org-Name + + -- OEPS Specifics (Legacy Spec) + oeps_id TEXT, -- 'Satznummer' (6 digits for Person, 4 for Club) + oeps_category TEXT, -- 'Verein', 'Reiter', 'Richter' + + -- Licenses & Status + license_code TEXT, -- e.g. 'R1', 'RD3' + has_start_card INTEGER NOT NULL DEFAULT 0, -- Boolean: Paid annual fee? + is_locked INTEGER NOT NULL DEFAULT 0, -- Boolean: Sperrliste? + + -- Contact & Meta + nationality TEXT NOT NULL DEFAULT 'AUT', -- ISO 3-Letter + contact_json TEXT, -- Address, Phone, Email + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL, + version INTEGER NOT NULL DEFAULT 1 +); + +CREATE INDEX idx_actor_oeps_id ON actor(oeps_id); +CREATE INDEX idx_actor_name ON actor(last_name, first_name); + + +-- Pferde +CREATE TABLE horse ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + + -- Identification + oeps_id TEXT, -- 'Satznummer' (10 digits) - CRITICAL for Export + head_number_permanent TEXT, -- 'Kopfnummer' (e.g. A123) + life_number TEXT, -- 'Lebensnummer' (Zucht) + fei_id TEXT, + + -- Details + birth_year INTEGER, + gender TEXT, -- 'M', 'W', 'G' (Gelding/Wallach) + color TEXT, + sire_name TEXT, -- Vater (Denormalized for search) + dam_name TEXT, -- Mutter + + -- Owner Link + owner_id TEXT, -- FK to actor.id + + -- Status + is_locked INTEGER NOT NULL DEFAULT 0, -- Sperrliste + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL, + version INTEGER NOT NULL DEFAULT 1 +); + +CREATE INDEX idx_horse_oeps_id ON horse(oeps_id); +CREATE INDEX idx_horse_head_num ON horse(head_number_permanent); +CREATE INDEX idx_horse_name ON horse(name); + +-- ================================================================== +-- 3. EVENT STRUCTURE +-- ================================================================== + +CREATE TABLE event ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + start_date INTEGER NOT NULL, -- Epoch Day + end_date INTEGER NOT NULL, + location TEXT, + organizer_id TEXT NOT NULL, -- FK to actor.id + + status TEXT NOT NULL DEFAULT 'PLANNING' -- PLANNING, ACTIVE, ARCHIVED +); + +CREATE TABLE tournament ( + id TEXT NOT NULL PRIMARY KEY, + event_id TEXT NOT NULL REFERENCES event(id), + + -- OEPS Spec + oeps_number TEXT NOT NULL, -- 5 digits (e.g. 21001) + category TEXT, -- e.g. 'CSN-A' + ruleset TEXT NOT NULL DEFAULT 'OETO', -- 'OETO', 'FEI' + + -- Sync Meta + updated_at INTEGER NOT NULL +); + +-- Bewerbe (Competitions) +-- Note: If a competition is split into 2 departments (Abteilungen), +-- we create 2 rows here to match the OEPS 'B-Satz' logic. +CREATE TABLE competition ( + id TEXT NOT NULL PRIMARY KEY, + tournament_id TEXT NOT NULL REFERENCES tournament(id), + + -- Identification + code_internal TEXT NOT NULL, -- '01', '02' (2 digits) + code_official TEXT, -- '001' (3 digits, optional) + division_id INTEGER NOT NULL DEFAULT 0, -- 'Abteilung' (0=None, 1=1st, 2=2nd) + + -- Description + title TEXT NOT NULL, + category TEXT, -- e.g. 'LM', 'S*' + discipline TEXT NOT NULL, -- 'D', 'S', 'C' (Dressage, Jumping, Combined) + + -- Rules & Scoring + scoring_method TEXT NOT NULL, -- 'A0', 'C', 'DRESSAGE_PERCENT' + start_fee INTEGER NOT NULL DEFAULT 0, -- In Cents + + -- State + status TEXT NOT NULL DEFAULT 'OPEN', -- OPEN, CLOSED_FOR_ENTRIES, RUNNING, FINISHED, SIGNED_OFF + + -- Sync Meta + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_comp_tournament ON competition(tournament_id); + +-- ================================================================== +-- 4. SPORT & PROCESS +-- ================================================================== + +-- Nennungen (Entries) +-- Represents the intent to start. +CREATE TABLE entry ( + id TEXT NOT NULL PRIMARY KEY, + competition_id TEXT NOT NULL REFERENCES competition(id), + + -- The Pair + horse_id TEXT NOT NULL REFERENCES horse(id), + rider_id TEXT NOT NULL REFERENCES actor(id), + + -- Financials + responsible_person_id TEXT REFERENCES actor(id), -- Who pays? + fee_agreed INTEGER NOT NULL, -- In Cents (Snapshot of price at entry time) + payment_status TEXT NOT NULL DEFAULT 'PENDING', -- PENDING, PAID, WAIVED + + -- Validation Override (The "Human Factor") + validation_status TEXT NOT NULL DEFAULT 'OK', -- OK, WARNING, BLOCKED + override_comment TEXT, -- Why was this allowed despite warning? + + -- Sync Meta + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_entry_comp ON entry(competition_id); +CREATE INDEX idx_entry_rider ON entry(rider_id); + +-- Startliste (Start Order) +-- Subset of entries that actually start. +CREATE TABLE start_list_entry ( + id TEXT NOT NULL PRIMARY KEY, + entry_id TEXT NOT NULL REFERENCES entry(id), + + -- Ordering + start_order INTEGER, -- 1, 2, 3... + start_time_planned INTEGER, -- Epoch Millis (optional) + + -- Tournament Specifics + head_number_event TEXT, -- Startnummer am Turnier (kann von A123 abweichen) + + -- Status + status TEXT NOT NULL DEFAULT 'READY', -- READY, STARTED, DNS (Did Not Start) + + UNIQUE(entry_id) +); + +-- Ergebnisse (Results) +CREATE TABLE result ( + id TEXT NOT NULL PRIMARY KEY, + start_list_entry_id TEXT NOT NULL REFERENCES start_list_entry(id), + + -- The Outcome + rank INTEGER, -- 1, 2, 3... (NULL if eliminated) + + -- Scoring Details (Polymorphic based on Competition Type) + points_jump_faults DECIMAL(5,2), -- Springfehler + time_taken_ms INTEGER, -- Zeit in Millisekunden + score_dressage_percent DECIMAL(5,3), -- 72.500 + score_dressage_total DECIMAL(6,2), -- Summe Punkte + + -- Status Flags + classification TEXT NOT NULL DEFAULT 'OK', -- OK, EL (Elim), RET (Retired), DIS (Disq) + + -- Detailed Marks (JSON) + -- e.g. { "judge_C": 7.5, "judge_H": 7.2, "obstacles": [...] } + details_json TEXT, + + -- Money + prize_money INTEGER DEFAULT 0, -- In Cents + + -- Audit + updated_by_user_id TEXT, + updated_at INTEGER NOT NULL +); + +CREATE INDEX idx_result_starter ON result(start_list_entry_id); + +-- ================================================================== +-- 5. AUDIT LOG (NFR-07) +-- ================================================================== + +CREATE TABLE audit_log ( + id TEXT NOT NULL PRIMARY KEY, + entity_type TEXT NOT NULL, -- 'RESULT', 'ENTRY' + entity_id TEXT NOT NULL, + action TEXT NOT NULL, -- 'CREATE', 'UPDATE', 'DELETE' + + user_id TEXT, + timestamp INTEGER NOT NULL, + + changes_json TEXT -- { "score_old": 7.0, "score_new": 7.5 } +); diff --git a/docs/03_Domain/03_Analysis/Legacy_Spec_Analysis_2026-01.md b/docs/03_Domain/03_Analysis/Legacy_Spec_Analysis_2026-01.md new file mode 100644 index 00000000..f5063887 --- /dev/null +++ b/docs/03_Domain/03_Analysis/Legacy_Spec_Analysis_2026-01.md @@ -0,0 +1,75 @@ +# Analyse der Legacy-Spezifikation (OEPS Pflichtenheft 2021 V2.4) + +* **Datum:** 2026-01-14 +* **Quelle:** `docs/03_Domain/02_Reference/Legacy_Specs/OETO-2026_Meldestelle_Pflichtenheft_V2.4_2021-07-28.md` +* **Status:** Draft + +## 1. Zusammenfassung + +Das Pflichtenheft definiert das Datenaustauschformat zwischen Meldestellen-Software und dem OEPS (Österreichischer Pferdesportverband). Es ist die **maßgebliche technische Referenz** für nationale Turniere in Österreich. Die Einhaltung dieser Spezifikation ist zwingend erforderlich, um Ergebnisse an den Verband zu melden. + +## 2. Kritische Datenfelder & Identifikatoren + +Die Analyse zeigt, dass das aktuelle `Core_Model` (`Overview.md`) zu generisch ist. Für den operativen Betrieb fehlen essenzielle Identifikatoren. + +### 2.1. Identifikation von Personen & Pferden +Das System verlässt sich nicht primär auf Namen, sondern auf **Satznummern**. + +* **Pferd:** + * `Satznummer` (10-stellig, numerisch): Der primäre Key im OEPS-System. Muss zwingend persistiert und exportiert werden. + * `Kopfnummer` (4-stellig, alphanumerisch): + * National: Die permanente Registrierungsnummer beim OEPS. + * International: Eine turnierspezifische Startnummer. + * `Lebensnummer` (9-stellig): Zuchtnummer. Achtung: Bei ausländischen Pferden oft generiert/fiktiv -> Nicht zur Suche geeignet! + * `FEI-Pass` vs. `FEI-ID`: Zwei getrennte Felder! + +* **Reiter:** + * `Satznummer` (6-stellig, numerisch): Der primäre Key. + * `Lizenz` (z.B. "RD1", "R1"): Bestimmt die Startberechtigung in Klassen. + * `Startkarte`: Flag, ob die Jahresgebühr bezahlt wurde. Ohne Startkarte keine Startberechtigung (außer Gastlizenzen). + +### 2.2. Turnier & Bewerbsstruktur +Die Struktur ist starrer als im aktuellen Modell angenommen. + +* **Turniernummer:** 5-stellig. +* **Bewerbe:** + * Haben eine 2-stellige Nummer (intern) UND eine 3-stellige Nummer (für Turniere > 99 Bewerbe). + * **Abteilungen:** Ein Bewerb kann in Abteilungen (Abt. 1, Abt. 2...) unterteilt sein. Dies ist keine rein organisatorische Trennung, sondern datentechnisch relevant (Feld `ABTEILUNG`). + +## 3. Implizite Geschäftsregeln + +Aus den Datenfeldern lassen sich harte Business Rules ableiten: + +1. **Startberechtigung (Sperrliste):** Es gibt ein Flag `SPERRLISTE`. Wenn gesetzt, muss das System warnen/blockieren. Grund oft: Offene Forderungen. +2. **Nation-Logik (Gast vs. Inländer):** + * Ausländer mit österr. Lizenz + bezahlter Startkarte -> Startet für österr. Verein -> Nation im Ergebnis = "AUT". + * Ausländer ohne Mitgliedschaft -> Gastreiter -> Nation = Staatsbürgerschaft (z.B. "GER"). + * *Konsequenz:* Die "Nation" eines Starts ist kontextabhängig und nicht rein statisch am Reiter hängend. +3. **Pferde-Status:** Pferde, für die >3 Jahre keine Gebühr bezahlt wurde, gelten als "nicht registriert" -> Neuanlage erforderlich. + +## 4. Lücken im aktuellen Modell (Gap Analysis) + +| Entität | Fehlendes Attribut / Konzept | Dringlichkeit | +| :--- | :--- | :--- | +| **Pferd** | `Satznummer` (OEPS-ID) | **Hoch** (Sync unmöglich ohne dies) | +| **Pferd** | Unterscheidung `Kopfnummer` (Permanent) vs. `Startnummer` (Turnier) | Mittel | +| **Akteur** | `Satznummer` (OEPS-ID) | **Hoch** | +| **Akteur** | `Startkarte` (Status) | Hoch (Validierung) | +| **Bewerb** | `Abteilung` (Sub-Struktur) | Mittel | +| **Ergebnis** | `Ausschluss-Typ` (Disqualifikation, Aufgabe, Ausschluss) | Mittel | +| **Ergebnis** | `Geldpreis` (Formatierung, Währung ist implizit EUR) | Niedrig | + +## 5. Empfehlung für das Datenmodell + +Wir müssen die Entität `Akteur` in spezifische Rollen-Modelle ausdifferenzieren oder per Composition erweitern, da die Attribute für Reiter (Lizenz, Startkarte) für andere Akteure (Richter, Besitzer) irrelevant oder anders sind. + +**Vorschlag:** +* `Akteur` bleibt Basis (Name, Kontakt). +* `ReiterProfile` (Value Object / 1:1 Relation): Enthält `Satznummer`, `Lizenz`, `Startkarte`, `Sperrvermerk`. +* `Pferd` erhält `OEPS_Daten` (Value Object): `Satznummer`, `Kopfnummer`, `Lebensnummer`. + +## 6. Offene Fragen an den PO + +1. Wie gehen wir mit **internationalen Turnieren** (FEI) um? Das Pflichtenheft deutet an, dass auch hier OEPS-Formate genutzt werden ("Version 2.4 für internationale Bewerbe"), aber die FEI hat eigene Formate. Welches ist führend? +2. Soll das System den **Import** der `zns.zip` (Stammdaten) unterstützen? Das wäre essenziell für den Offline-Betrieb. +3. Wie strikt soll die **Validierung** sein? Soll das System eine Nennung *verhindern*, wenn die Startkarte fehlt, oder nur *warnen*? (Realität: Oft wird vor Ort nachgezahlt). diff --git a/docs/03_Domain/03_Analysis/Non_Functional_Requirements_Draft.md b/docs/03_Domain/03_Analysis/Non_Functional_Requirements_Draft.md new file mode 100644 index 00000000..f7e23e23 --- /dev/null +++ b/docs/03_Domain/03_Analysis/Non_Functional_Requirements_Draft.md @@ -0,0 +1,80 @@ +# Non-Functional Requirements (NFRs) - Phase 1 + +* **Status:** Draft +* **Fokus:** Offline-First Architektur, Robustheit, Datenintegrität + +--- + +## 1. Offline-Fähigkeit & Resilienz (Availability) + +Das System muss in einer Umgebung funktionieren, in der Netzwerkverbindungen unzuverlässig oder nicht vorhanden sind (Reitställe, ländliche Gebiete). + +* **NFR-01: Local-First Prinzip** + * Alle Kernfunktionen (Nennung, Startlistenerstellung, Ergebniserfassung, Drucken) müssen **zu 100% ohne Netzwerkverbindung** ausführbar sein. + * Die lokale Datenbank (SQLite/SQLDelight) ist die primäre Datenquelle für das UI. + * Der Server dient lediglich als Synchronisations-Hub und Backup, nicht als Laufzeit-Abhängigkeit. + +* **NFR-02: Synchronisation & Konfliktlösung** + * Sobald eine Verbindung besteht, müssen Daten im Hintergrund synchronisiert werden. + * **Konfliktstrategie:** Bei konkurrierenden Änderungen (z.B. zwei Richter ändern dasselbe Ergebnis) muss das System: + 1. Technische Konflikte automatisch lösen (z.B. "Last Write Wins" basierend auf präzisen Zeitstempeln). + 2. Fachliche Konflikte protokollieren und zur manuellen Klärung markieren. + +* **NFR-03: Wiederherstellung (Disaster Recovery)** + * Nach einem Absturz oder Stromausfall muss das System innerhalb von **< 30 Sekunden** wieder betriebsbereit sein. + * Kein Datenverlust von bereits bestätigten Eingaben (ACID-Transaktionen lokal). + +--- + +## 2. Performance & Latenz (Usability) + +Im Turnierbetrieb herrscht Zeitdruck. Wartezeiten summieren sich und führen zu Stress bei den Anwendern. + +* **NFR-04: Optimistic UI Updates** + * Benutzeraktionen (z.B. Speichern einer Note) müssen im UI **sofort (< 50ms)** bestätigt werden, ohne auf Netzwerk-Roundtrips oder Datenbank-Commits zu warten (Asynchrone Verarbeitung). + +* **NFR-05: Such-Performance** + * Die Suche nach Pferden (in > 50.000 Stammdaten) oder Reitern muss **< 200ms** dauern (Full-Text-Search Indexierung lokal). + * Dies gilt auch auf leistungsschwächerer Hardware (ältere Laptops, Tablets). + +* **NFR-06: Massendaten-Verarbeitung** + * Der Import der `zns.zip` (Stammdaten) darf den UI-Thread nicht blockieren und sollte **< 5 Minuten** dauern. + +--- + +## 3. Datenintegrität & Audit (Compliance) + +Ergebnisse entscheiden über Qualifikationen und Preisgelder. Manipulationen oder versehentliche Änderungen müssen nachvollziehbar sein. + +* **NFR-07: Audit Trail** + * Jede Änderung an einem Ergebnis (Score, Zeit, Platzierung) muss unveränderbar protokolliert werden. + * Inhalt: `Timestamp`, `User-ID`, `Old-Value`, `New-Value`, `Reason` (optional). + * Der Audit-Log muss mit synchronisiert werden. + +* **NFR-08: Validierungs-Hierarchie** + * Das System muss zwischen "Hard Constraints" (Datenbank-Integrität, z.B. Foreign Keys) und "Soft Constraints" (Fachliche Regeln, z.B. fehlende Startkarte) unterscheiden. + * Soft Constraints dürfen den Prozess nicht blockieren, müssen aber persistente Warnungen erzeugen ("Override"-Flag). + +--- + +## 4. Sicherheit (Security) + +* **NFR-09: Lokale Datensicherheit** + * Da Laptops/Tablets gestohlen werden können: Sensible Daten (Personendaten, Adressen) sollten "At Rest" verschlüsselt sein (z.B. SQLCipher), sofern die Performance (NFR-05) nicht kritisch beeinträchtigt wird. + * Minimalanforderung: Keine Speicherung von Passwörtern im Klartext. + +* **NFR-10: Rollenbasierter Zugriff (RBAC)** + * Unterscheidung der Berechtigungen im UI: + * *Richter:* Darf nur Ergebnisse für zugewiesene Bewerbe eingeben. + * *Meldestelle:* Vollzugriff. + * *Zuschauer (Kiosk-Mode):* Nur Lesezugriff auf Starter-/Ergebnislisten. + +--- + +## 5. Hardware & Umgebung + +* **NFR-11: Eingabe-Effizienz** + * Die Ergebniserfassung muss "Keyboard-First" bedienbar sein (Nummernblock-Optimierung). Maus/Touch ist für Massenerfassung zu langsam. + +* **NFR-12: Druck-Unterstützung** + * Unterstützung von lokalen Druckern (USB/Netzwerk) ohne komplexe Treiber-Installation, da Listen (Starterlisten, Ergebnisse) physisch ausgehängt werden müssen (Pflicht laut Reglement). diff --git a/docs/03_Domain/03_Analysis/Use_Cases_Draft.md b/docs/03_Domain/03_Analysis/Use_Cases_Draft.md new file mode 100644 index 00000000..01cb003a --- /dev/null +++ b/docs/03_Domain/03_Analysis/Use_Cases_Draft.md @@ -0,0 +1,112 @@ +# Use Cases Draft - Phase 1 (Core Domain) + +* **Status:** Draft +* **Fokus:** High-Level Prozessflüsse und Systemgrenzen + +--- + +## Cluster 1: Turnier-Initialisierung & Datenbasis + +### UC-01: Turnier-Stammdaten importieren +* **Akteur:** Meldestellen-Leiter +* **Auslöser:** Vorbereitung eines neuen Turniers oder Update am Turniermorgen. +* **Vorbedingung:** `zns.zip` (oder äquivalente OEPS-Daten) liegt vor. +* **Ablauf:** + 1. System liest die Datensätze für Pferde, Reiter, Vereine und Funktionäre. + 2. System aktualisiert die lokale Datenbank (Insert/Update). + 3. System markiert Datensätze mit Sperrvermerken oder fehlenden Lizenzen. +* **Nachbedingung:** Die lokale Datenbank ist die "Single Source of Truth" für Validierungen. + +### UC-02: Turnier-Konfiguration anlegen +* **Akteur:** Meldestellen-Leiter +* **Auslöser:** Erstellung eines neuen Events. +* **Vorbedingung:** Ausschreibung liegt vor. +* **Ablauf:** + 1. Akteur definiert Stammdaten (Ort, Datum, Veranstalter). + 2. Akteur legt Bewerbe an (Nummer, Klasse, Richtverfahren). + 3. Akteur definiert Gebühren (Nenngeld, Startgeld, Boxenpreise). +* **Nachbedingung:** Das Turniergerüst steht bereit für Nennungen. + +--- + +## Cluster 2: Nennungs-Management (Pre-Competition) + +### UC-03: Nennung erfassen & validieren +* **Akteur:** Meldestellen-Mitarbeiter +* **Auslöser:** Import von Online-Nennungen oder manuelle Eingabe. +* **Ablauf:** + 1. System prüft Existenz von Reiter und Pferd (via Satznummer). + 2. **Validierung:** + * Ist die Startkarte bezahlt? + * Ist die Lizenz ausreichend für die Klasse? + * Liegt eine Sperre vor? + * Ist das Pferd geimpft/registriert? + 3. Bei Validierungsfehler: System zeigt Warnung, erlaubt aber "Override" durch Akteur (z.B. "Zahlung erfolgt"). + 4. System verknüpft Paar mit Bewerb. +* **Nachbedingung:** Das Paar ist auf der "Nennliste" (noch nicht Starterliste). + +### UC-04: Pferd/Reiter tauschen +* **Akteur:** Meldestellen-Mitarbeiter +* **Auslöser:** Reiter fällt aus oder Pferd ist lahm. +* **Ablauf:** + 1. Akteur wählt bestehende Nennung. + 2. Akteur tauscht Reiter ODER Pferd aus. + 3. System führt Validierung (UC-03) für die neue Kombination durch. + 4. System protokolliert den Tausch (relevant für T-Satz im Export). +* **Nachbedingung:** Nennung ist aktualisiert, Historie ist gewahrt. + +--- + +## Cluster 3: Durchführung & Sport (Competition) + +### UC-05: Startliste erstellen +* **Akteur:** Meldestellen-Leiter +* **Auslöser:** Nennschluss für einen Bewerb ist erreicht. +* **Ablauf:** + 1. Akteur definiert Startreihenfolge (z.B. "Alphabetisch", "Gelost", "Nach Lizenz"). + 2. System generiert die Reihenfolge. + 3. System weist Kopfnummern zu (falls noch nicht geschehen). + 4. System teilt bei Bedarf in Abteilungen (siehe US-005). +* **Nachbedingung:** Die Startliste ist fixiert und kann gedruckt/publiziert werden. + +### UC-06: Ergebnis erfassen +* **Akteur:** Richter / Schreiber / Zeitnehmung +* **Auslöser:** Ein Ritt ist beendet. +* **Ablauf:** + 1. Akteur wählt Starter. + 2. Akteur gibt Rohdaten ein (Zeit, Fehlerpunkte, Wertnote). + 3. System berechnet sofort den Score und den vorläufigen Rang. + 4. System prüft auf Spezialfälle (Ausschluss, Aufgabe). +* **Nachbedingung:** Ergebnis ist gespeichert, Live-Ranking ist aktualisiert. + +### UC-07: Bewerb abschließen +* **Akteur:** Meldestellen-Leiter / Hauptrichter +* **Auslöser:** Letzter Reiter ist fertig, Einspruchsfrist abgelaufen. +* **Ablauf:** + 1. System finalisiert die Rangierung (inkl. Ex-Aequo Regeln). + 2. System berechnet Geldpreise gemäß Ausschreibung und Teilnehmerzahl. + 3. System sperrt den Bewerb für Änderungen. +* **Nachbedingung:** Ergebnisse sind "amtlich", Geldpreise sind den Konten gutgeschrieben. + +--- + +## Cluster 4: Abschluss & Finanzen + +### UC-08: Konto abrechnen (Kassieren) +* **Akteur:** Kassen-Mitarbeiter +* **Auslöser:** Teilnehmer will abreisen/bezahlen. +* **Ablauf:** + 1. System aggregiert alle Kosten (Nenngelder, Boxen, Gebühren) pro "Verantwortlicher Person". + 2. System zieht gewonnene Geldpreise ab. + 3. System erstellt Saldo. + 4. Akteur verbucht Zahlungseingang. +* **Nachbedingung:** Konto ist ausgeglichen, "Horse Pass" kann ausgegeben werden. + +### UC-09: OEPS-Export durchführen +* **Akteur:** Meldestellen-Leiter +* **Auslöser:** Turnierende. +* **Ablauf:** + 1. System prüft Datenintegrität (Alle Pflichtfelder für Export vorhanden?). + 2. System generiert `XXXXX.ERG` Datei gemäß Spezifikation V2.4. + 3. System erstellt Protokoll über eventuelle Warnungen/Abweichungen. +* **Nachbedingung:** Export-Datei liegt bereit zur Übermittlung. diff --git a/docs/03_Domain/03_Analysis/User_Stories_Draft.md b/docs/03_Domain/03_Analysis/User_Stories_Draft.md new file mode 100644 index 00000000..1aa61e05 --- /dev/null +++ b/docs/03_Domain/03_Analysis/User_Stories_Draft.md @@ -0,0 +1,109 @@ +# User Stories Draft - Phase 1 (Core Domain) + +* **Status:** Draft +* **Fokus:** Nationale Turniere (OEPS), Offline-Betrieb, Basis-Verwaltung + +--- + +## Epic 1: Stammdaten & Offline-Vorbereitung + +### US-001: Import der Verbands-Stammdaten (ZNS) +**Als** Meldestellen-Leiter +**möchte ich** die offizielle `zns.zip` Datei (Pferde, Reiter, Vereine, Richter) in das System importieren, +**damit** ich auch ohne Internetverbindung Zugriff auf alle validen Lizenz- und Pferdedaten habe. + +* **Akzeptanzkriterien:** + * System akzeptiert `zns.zip` oder entpackte `.dat` Dateien (Codepage 850). + * Importiert `PFERDE01.dat` (inkl. Mapping der 10-stelligen Satznummer). + * Importiert `LIZENZ01.dat` (inkl. Startkarten-Status und Sperrvermerke). + * Der Import ist performant genug, um am Turniermorgen aktualisiert zu werden (< 5 Min). + * Fehlerhafte Datensätze werden protokolliert, brechen den Import aber nicht ab. + +### US-002: Intelligente Akteur-Suche +**Als** Meldestellen-Mitarbeiter +**möchte ich** Reiter und Pferde über eine fehlertolerante Suche finden (Name, Kopfnummer, Lizenznummer), +**damit** ich Nennungen schnell erfassen kann, auch wenn der Reiter seine genaue Nummer nicht weiß. + +* **Akzeptanzkriterien:** + * Suche nach Pferdenamen (Teilübereinstimmung). + * Suche nach Kopfnummer (z.B. "A123"). + * Anzeige von Warnhinweisen direkt im Suchergebnis (z.B. "Sperrliste", "Keine Startkarte"). + * Unterscheidung bei Namensgleichheit durch Anzeige von Verein/Jahrgang/Abstammung. + +--- + +## Epic 2: Nennung & Check-in + +### US-003: Validierung der Startberechtigung (Startkarte) +**Als** Meldestellen-Leiter +**möchte ich**, dass das System mich warnt, wenn ein Reiter für einen Bewerb nennt, aber keine aktive Startkarte (Jahresgebühr) hat, +**damit** ich ihn zur Nachzahlung auffordern kann. + +* **Akzeptanzkriterien:** + * Prüfung des Flags `STARTKARTE` aus den Stammdaten. + * Prüfung der Lizenzklasse (z.B. darf "R1" nicht in Klasse S starten). + * **Wichtig:** Das System darf die Nennung *nicht* blockieren (Soft-Validation), sondern muss einen "Override" ermöglichen (z.B. "Zahlung vor Ort erfolgt"). + * Visuelle Hervorhebung in der Starterliste (z.B. roter Status). + +### US-004: Manuelle Nachnennung vor Ort +**Als** Meldestellen-Mitarbeiter +**möchte ich** ein Pferd-Reiter-Paar kurzfristig zu einem Bewerb hinzufügen, +**damit** Teilnehmer, die die Online-Nennfrist verpasst haben, gegen Gebühr noch starten können. + +* **Akzeptanzkriterien:** + * Auswahl von Bewerb, Reiter und Pferd. + * Automatische Berechnung der erhöhten Nenngebühr (Nachnenngebühr). + * Vergabe einer Startnummer (fortlaufend oder manuell). + * Eintrag in die `KKARTEI` (Nennliste) und `BBEWERBE` (Starterliste). + +--- + +## Epic 3: Bewerbs-Abwicklung + +### US-005: Verwaltung von Abteilungen +**Als** Meldestellen-Leiter +**möchte ich** einen Bewerb mit vielen Startern in mehrere Abteilungen (z.B. R1-Reiter vs. R2-Reiter) unterteilen, +**damit** ich getrennte Ergebnislisten und Platzierungen erstellen kann, wie es die ÖTO verlangt. + +* **Akzeptanzkriterien:** + * Ein Bewerb kann in n Abteilungen gesplittet werden. + * Starter können per Drag&Drop oder Regel (z.B. "Alle R1 in Abt. 1") zugewiesen werden. + * Jede Abteilung hat eine eigene Platzierung, aber sie teilen sich die gleichen Prüfungsparameter (Parcours). + * Export berücksichtigt das Feld `ABTEILUNG` im B-Satz. + +### US-006: Ergebniserfassung & Platzierung +**Als** Richter oder Schreiber +**möchte ich** Ergebnisse (Zeit, Fehler, Wertnote) für einen Starter eingeben, +**damit** die Rangierung automatisch berechnet wird. + +* **Akzeptanzkriterien:** + * Eingabemaske optimiert für schnelle Nummernblock-Eingabe. + * Automatische Berechnung der Rangfolge basierend auf dem Regelwerk (Fehler/Zeit vs. Wertnote). + * Handling von Spezialfällen: Ausschluss (EL), Aufgabe (RET), Disqualifikation (DQ), Nicht angetreten (DNS). + * Sofortige Aktualisierung der "Live-Ergebnisse". + +--- + +## Epic 4: Abschluss & Export + +### US-007: OEPS-Konformer Ergebnis-Export +**Als** Meldestellen-Leiter +**möchte ich** die Ergebnisse des Turniers in das definierte Format (ASCII, Codepage 850) exportieren, +**damit** ich meiner Meldepflicht gegenüber dem Verband nachkommen kann. + +* **Akzeptanzkriterien:** + * Erstellung der `XXXXX.ERG` Datei. + * Strikte Einhaltung der Spaltenbreiten und Formate (siehe Legacy Spec Analyse). + * Validierung vor Export: Warnung bei fehlenden Satznummern oder ungültigen Codes. + * Korrekte Zuordnung der Nation (Gast vs. Inländer). + +### US-008: Kassenabschluss & Abrechnung +**Als** Veranstalter +**möchte ich** eine Liste aller offenen Posten (Nenngelder, Boxen, Nachnenngebühren) pro Reiter/Verein sehen, +**damit** ich vor der Ausgabe der Pferdepässe kassieren kann. + +* **Akzeptanzkriterien:** + * Aggregierte Ansicht pro "Verantwortlicher Person" (Zahler). + * Auflistung aller Posten (Nennung, Startgeld, Gebühren). + * Verrechnung von gewonnenen Geldpreisen (Gutschrift). + * Druckfunktion für Rechnung/Quittung. diff --git a/docs/99_Journal/2026-01-15_Domain_Analysis_Session.md b/docs/99_Journal/2026-01-15_Domain_Analysis_Session.md new file mode 100644 index 00000000..35bc3f7d --- /dev/null +++ b/docs/99_Journal/2026-01-15_Domain_Analysis_Session.md @@ -0,0 +1,46 @@ +# Session Log: Domain Analysis & Core Model Definition + +* **Datum:** 2026-01-15 +* **Rolle:** Domain/Product Expert +* **Teilnehmer:** User (Stefan) +* **Status:** Abgeschlossen + +## Ziele der Session +1. Analyse der bestehenden Dokumentation (insb. OEPS Pflichtenheft). +2. Schärfung des Domänenmodells für nationale Turniere. +3. Erstellung von User Stories, Use Cases und NFRs. +4. Ableitung eines konkreten Datenbankschemas (SQL) für die Offline-First-Architektur. + +## Durchgeführte Arbeiten + +### 1. Analyse & Glossar +* **Legacy Spec Analyse:** Das OEPS Pflichtenheft 2021 V2.4 wurde detailliert analysiert. Wichtigste Erkenntnis: Identifikation erfolgt über numerische `Satznummern`, nicht Namen. +* **Glossar:** `docs/03_Domain/00_Glossary.md` erstellt. Begriffe wie *Startkarte*, *Satznummer*, *Abteilung* definiert. +* **Core Model:** `docs/03_Domain/01_Core_Model/Entities/Overview.md` aktualisiert. Entitäten `Pferd` und `Akteur` um OEPS-spezifische Felder erweitert. + +### 2. Anforderungen (Requirements) +* **User Stories:** `docs/03_Domain/03_Analysis/User_Stories_Draft.md` erstellt. Fokus auf Offline-Import (ZNS) und Fehlertoleranz ("Override"). +* **Use Cases:** `docs/03_Domain/03_Analysis/Use_Cases_Draft.md` erstellt. Clusterung in Initialisierung, Nennung, Sport und Abschluss. +* **NFRs:** `docs/03_Domain/03_Analysis/Non_Functional_Requirements_Draft.md` erstellt. Fokus auf Local-First, Konfliktlösung und Audit-Sicherheit. + +### 3. Technisches Design +* **Datenbankschema:** `docs/03_Domain/01_Core_Model/Entities/Database_Schema.sql` erstellt. + * Verwendung von UUIDs (`TEXT`) für Offline-Kompatibilität. + * Modellierung von `competition` mit `division_id` für Abteilungen. + * Einführung von `audit_log` und `version` Feldern für Sync. + +## Ergebnisse & Artefakte +| Artefakt | Pfad | Status | +| :--- | :--- | :--- | +| Glossar | `docs/03_Domain/00_Glossary.md` | Final | +| Core Model | `docs/03_Domain/01_Core_Model/Entities/Overview.md` | Updated | +| Legacy Analyse | `docs/03_Domain/03_Analysis/Legacy_Spec_Analysis_2026-01.md` | Draft | +| User Stories | `docs/03_Domain/03_Analysis/User_Stories_Draft.md` | Draft | +| Use Cases | `docs/03_Domain/03_Analysis/Use_Cases_Draft.md` | Draft | +| NFRs | `docs/03_Domain/03_Analysis/Non_Functional_Requirements_Draft.md` | Draft | +| DB Schema | `docs/03_Domain/01_Core_Model/Entities/Database_Schema.sql` | Proposal | + +## Nächste Schritte +* **Review:** Architekt und Backend-Dev müssen das Schema prüfen. +* **Implementierung:** Übertragung des SQL-Schemas in SQLDelight (`.sq` Dateien) im KMP-Modul. +* **Prototyping:** Erster "Walking Skeleton" für den ZNS-Import basierend auf den User Stories.