--- type: Roadmap status: IN_PROGRESS owner: Curator last_update: 2026-03-25 --- # Roadmap: ZNS-Importer (MVP) 🧹 **[Curator]** | 25. März 2026 **Kontext:** Um den `registration-context` und `actor-context` unter realistischen Bedingungen testen zu können, benötigen wir echte Stammdaten (Reiter, Pferde, Vereine, Funktionäre). Diese Daten werden vom ÖPS (Österreichischer Pferdesportverband) in Form einer `ZNS.zip` bereitgestellt. **Ziel:** Entwicklung eines asynchronen, robusten Importers für die Legacy-ZNS-Daten (`ZNS.zip`), der über die Compose-Desktop-App gesteuert wird und die Daten persistent im Backend (`actor-context`) ablegt. --- ## 1. Spezifikationen & Rahmenbedingungen * **Dateiformat:** Fixed-Width ASCII (Feste Spaltenbreiten, keine Trennzeichen). * **Encoding:** Zwingend **Codepage 850 (CP850)**. (Achtung: Umlaute!). * **Architektur-Muster:** Asynchroner Upload & Processing (Job-Pattern). * **Import-Reihenfolge (Abhängigkeiten beachten!):** 1. `VEREIN01.dat` (Vereine) 2. `LIZENZ01.dat` (Reiter/Lizenzen) 3. `PFERDE01.dat` (Pferde - benötigt Vereins-ID) 4. `RICHT01.dat` (Richter/Parcoursbauer) --- ## 2. Phasen & Aufgabenverteilung ### Phase 1: Backend-Infrastruktur & Parsing (👷 Backend Developer) * [x] **API Design:** * `POST /api/v1/import/zns` (Multipart/form-data, nimmt `.zip` oder `.dat` entgegen). * Rückgabe: `202 Accepted` mit einer `JobId` (UUID). * `GET /api/v1/import/zns/{jobId}/status` (Gibt aktuellen Fortschritt und Statusmeldungen zurück). * Implementiert in `backend:services:zns-import:zns-import-service` (`ZnsImportController`). ✅ * [x] **Job-Management:** * Thread-sichere In-Memory-Registry (`ImportJobRegistry`, `ConcurrentHashMap`) implementiert. * Status-Enum: `AUSSTEHEND`, `ENTPACKEN`, `LADE_VEREINE`, `LADE_REITER`, `LADE_PFERDE`, `LADE_RICHTER`, `ABGESCHLOSSEN`, `FEHLER`. ✅ * [x] **Unzip-Service:** * ZIP-Entpackung in-memory implementiert (`ZnsImportService`). * [x] **Legacy-Parser (CP850 Fixed-Width):** * `ZnsLegacyParsers` in `core:zns-parser` (KMP-Modul) implementiert. * Alle 4 Dateitypen (VEREIN01, LIZENZ01, PFERDE01, RICHT01) bytegenau gemappt. 4 Unit-Tests grün. ### Phase 2: Domain-Mapping & Persistenz (👷 Backend Developer) * [x] **Mapper-Logik:** * `DomVerein`, `DomReiter`, `DomPferd`, `DomFunktionaer` vollständig gemappt. * *Sonderfälle umgesetzt:* * `PFERDE01.dat`: Ausländische Systemnummern werden ignoriert. ✅ * `LIZENZ01.dat`: Sperrlisten-Flag (`S`) korrekt auf `DomReiter` gemappt. ✅ * [x] **Upsert-Strategie (DB):** * `ZnsImportService` implementiert find + save Logik (Upsert). 7 Unit-Tests grün. * Fehler pro Zeile werden gesammelt (kein Abbruch bei Einzelfehlern). `ZnsImportResult` mit Zählern & Fehlerlisten. ### Phase 3: Frontend-Integration (🎨 Frontend Expert) * [ ] **UI-Komponenten (Compose Desktop):** * Erstellung eines "Stammdaten-Import" Screens in der Master-Desktop-App. * Integration eines nativen File-Pickers (nur Auswahl von `.zip` zulassen). * [ ] **Netzwerk & State-Management (KMP):** * Ktor-Client anpassen für Multipart-Uploads. * Implementierung eines Polling-Mechanismus: Nach erfolgreichem Upload alle X Sekunden den Status-Endpunkt abfragen. * [ ] **User Feedback:** * Anzeige einer Progress-Bar mit Live-Updates (z. B. "Verarbeite Reiter: 1250/5000"). * Fehler-Handling (z. B. falsches Dateiformat, Timeouts) sauber darstellen. ### Phase 4: Testing & QA (🧐 QA Specialist) * [ ] **Test-Datensatz prüfen:** * Einlesen der `docs/OePS/ZNS.zip` und Überprüfung der Umlaute (CP850 Encoding Test). * [ ] **Abhängigkeits-Test:** * Sicherstellen, dass Pferde korrekt ihren Vereinen zugeordnet werden. * [ ] **Edge-Cases:** * Upload einer fehlerhaften Zip-Datei. * Abbruch des Uploads/Imports. --- ## 3. Offene Fragen / Risiken * Werden die Legacy-Daten in der Datenbank (PostgreSQL) mit UUIDs oder mit den ZNS-Satznummern als Primary Keys abgelegt? * *Architektur-Beschluss:* Wir sollten interne UUIDs als Primary Keys verwenden und die ZNS-Nummern als eindeutige Business-Keys (`UNIQUE CONSTRAINT`) ablegen. * Wie gehen wir mit gelöschten Datensätzen aus dem ZNS um? * *Vorerst:* Der ZNS-Import ist ein "Add/Update"-Only Vorgang. Löschungen müssen manuell oder in einer späteren Phase synchronisiert werden.