41 Commits

Author SHA1 Message Date
stefan a74b0bb815 build: Update Gradle Wrapper to v9.6.0
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-06-23 14:06:41 +02:00
stefan 40cf1e5d22 feat: füge neue Dokumentationen zu Richterqualifikationen (Dressur & Springen) sowie Systemmigration (Java 25, Kotlin 2.4.0, Gradle 9, Spring Boot 4) hinzu
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-06-21 21:06:11 +02:00
stefan ce63303b2c docs: massive restructuring of documentation, development guides and agent playbooks 2026-06-15 12:54:38 +02:00
stefan e4988b4397 docs: add tournament files for Ebbs Tirol 2026 2026-06-15 12:53:29 +02:00
stefan 8816e8d297 air work test 2026-06-15 12:26:22 +02:00
stefan 98d0bf0c7b docs: Turnier-Dokumente für 2026 hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-28 13:25:59 +02:00
stefan 0a90b57c2a docs: Ergänzung der Simka Core Server Dokumentation
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 13:13:24 +02:00
stefan 0ab62a2752 docs: README-Testbeschreibung aktualisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 11:36:34 +02:00
stefan 6070709bf2 docs: README-Testbeschreibung aktualisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 11:34:17 +02:00
stefan 763c2a9157 Test 2. Versuch zu committen
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-20 10:10:30 +00:00
StefanMo 4f715d10bb refactor: extrahiere ReiterLizenz in core-domain, aktualisiere Abhängigkeiten und behebe Windows-SQLite-Temp-Verzeichnisproblem 2026-05-12 23:33:48 +02:00
stefan 0b830eb675 feat: integriere VeranstaltungRepository und syncModule in Desktop-App
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-12 19:29:51 +02:00
stefan 4c37ecb952 refactor(build): redundante Variable im Gradle-Skript entfernt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:27:02 +02:00
stefan c25ef17a4a refactor(build): Typen in Gradle-Skript explizit hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:23:52 +02:00
stefan e5e3b4cfec refactor(build): Plugin-Anwendung in Gradle-Konfiguration vereinfacht
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:17:47 +02:00
stefan 7d064853e5 feat: optimiere Gradle-Konfiguration für bessere Build-Performance (JVM, Worker, Cache) und dokumentiere Änderungen
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 21:39:46 +02:00
stefan 387180c12c chore: entferne index.html
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 20:44:35 +02:00
stefan 49393d3eac feat: verbessere Build-Performance durch Standard-Deaktivierung von WASM und aktualisiere Dokumentation
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 20:44:24 +02:00
stefan e389fe9bce feat(desktop, network): Chat-Funktion hinzugefügt und P2P-Sync verbessert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-11 13:57:53 +02:00
stefan 1a4753cd73 refactor(frontend): HTML-Styles aufgeräumt und Konsistenz verbessert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 17:23:17 +02:00
stefan ece3f8bf78 feat(frontend): Grundlegendes HTML-Template für Website hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 17:09:51 +02:00
stefan 8d176ce955 refactor(gradle, desktop): Build-Konfiguration bereinigt, Ports optimiert und UI-Logik konsolidiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 14:27:22 +02:00
stefan 280db663c7 chore(build, docs): Gradle auf 9.5.0 und Kotlin auf 2.3.21 aktualisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 10:20:02 +02:00
stefan 74ef6424b7 docs(journal): Session-Log zu P2P-Guards, FilePicker-Fixes und Tests hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-08 15:08:20 +02:00
stefan 3959168695 feat(core, network): Port-Guards für Mehrfachstarts von P2P-Server integriert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-08 12:45:13 +02:00
stefan 04a435df1d refactor(core, desktop): Fehlertexte präzisiert und Verzeichnisauswahl für JFileChooser optimiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-08 12:25:58 +02:00
stefan 3aaf5cc59c feat(desktop, network): Fehlerhandling verbessert, Tools-Menü erweitert und mDNS-Discovery optimiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-07 17:18:17 +02:00
stefan a2d94bbc7e refactor(desktop, core): Exception-Handling optimiert und Divider-Komponente angepasst
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-07 15:44:08 +02:00
stefan 95a130c72e feat(desktop, device-initialization): Tools-Menü mit Backup-Option und Reset-Funktion ergänzt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-07 15:42:12 +02:00
stefan 223bf77776 feat(core, network): lokale Chat-Kommunikation und WebSocket-Server hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-07 10:58:31 +02:00
stefan 99cbfeef11 fix: aktualisiere Logs und dokumentiere Workflow-Änderungen
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 23:03:30 +02:00
stefan ed1cb507cf chore: entferne überflüssigen Abschnitt aus README
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 22:40:01 +02:00
stefan f4fab93a6c fix: setze Windows-Build-Workflow auf manuell und dokumentiere ARM64-Blockade
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 22:37:04 +02:00
stefan 9b9f60a071 fix: stabilisiere CI-Workflow und passe JAR-Namensmuster an
Feature Build — Windows MSI (via Conveyor) / 📦 Windows .msi Packaging (push) Failing after 2m3s
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 22:29:17 +02:00
stefan d219176609 fix: stabilisiere CI-Workflow und passe JAR-Namensmuster an
Feature Build — Windows MSI (via Conveyor) / 📦 Windows .msi Packaging (push) Failing after 1m19s
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 22:24:15 +02:00
stefan 7411038b3b fix: entferne CI-Blockade und aktualisiere Conveyor-Konfiguration
Feature Build — Windows MSI (via Conveyor) / 📦 Windows .msi Packaging (push) Failing after 8m16s
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 21:36:28 +02:00
stefan 77ee608094 feat: implementiere Cross-Packaging für Windows-MSI via Conveyor auf Linux
Feature Build — Windows MSI (via Conveyor) / 📦 Windows .msi Packaging (push) Has been skipped
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-06 21:26:39 +02:00
stefan 9bee2f233e fix: verbessere Fallback-Logik für Gerätenamen in JmDnsDiscoveryService
Feature Build — Windows MSI / 📦 Windows .msi Packaging (push) Has been cancelled
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 23:21:54 +02:00
stefan c317147ca4 feat: verbesserte Netzwerkfähigkeit und Chat-Test integriert
- **Discovery:** Unterstützung für Multi-Interface-Broadcast und manuelle IP-Eingabe.
- **UI:** Chat-Test für Verbindungsprüfung hinzugefügt.
- **ViewModel:** Datenübertragungslogik (Ping/Pong, Chat) implementiert.
- **Workflow:** Windows-MSI-Build als separaten Job hinzugefügt.

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 23:18:25 +02:00
stefan 15222b5453 chore: entferne veraltete Architekturdokumente
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 21:23:02 +02:00
stefan 6f15ada447 chore: dc-gui aus docker-compose.yaml auskommentiert
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 17:48:23 +02:00
901 changed files with 6613 additions and 7614 deletions
+41
View File
@@ -0,0 +1,41 @@
## 🚀 Identität & Arbeitsmodus (Chamäleon-Modus)
Du bist ein hochqualifizierter KI-Assistent für das Softwareprojekt "Meldestelle" von Stefan.
Ich weise dir in meinen Prompts Aufgaben zu. Nimm sofort die entsprechende Rolle an, beginne deine Antwort zwingend mit dem passenden Badge und passe dein Vokabular an:
* 🏗️ **[Lead Architect]:** System-Design, Gradle-Build-Logik, Modulstruktur.
* 📜 **[Rulebook Expert]:** Validiert Business-Rules gegen das ÖTO/FEI Regelwerk.
* 👷 **[Backend Developer]:** Kotlin & Spring Boot Experte.
* 🎨 **[Frontend Expert]:** KMP & Compose Desktop Spezialist.
* 🐧 **[DevOps Engineer]:** Infrastruktur (Docker, CI/CD, Proxmox).
**Arbeitsanweisung:** Bearbeite pro Antwort immer nur EINE fachliche Aufgabe.
## 🏗️ Projekt-Strategie (Reality-Reset)
1. **Desktop-First & Offline-First:** Das Primärziel ist eine autarke Compose Desktop App (KMP). Sie muss auf Turnieren ohne Internet funktionieren (lokale Persistenz).
2. **Optionales Backend:** Ein Spring Boot Stack (PostgreSQL, Valkey, Keycloak) wird nur für Multi-Tenant-Verwaltung, Registrierung und P2P-Sync genutzt.
3. **Domain-Driven Design (DDD):** Die absolute Business-Hierarchie lautet: Veranstaltung -> Turnier -> Bewerb/Abteilung.
4. **Der System-Akteur:** Der primäre "Actor" in allen Use-Cases ist *nicht* der Veranstalter, sondern zwingend die Person, die die Meldestelle betreut (Actor = Meldestelle).
## 🛠️ Der verbindliche Tech-Stack
Generiere Code ausschließlich für diese exakten Versionen und Paradigmen:
* **Frontend (KMP):** Kotlin 2.3.21, Compose Multiplatform 1.10.3, Ktor Client 3.4.1, SQLDelight.
* **Backend:** Spring Boot 3.5.9 (JDK 25), Ktor Server (wo spezifiziert), Exposed 1.1.1.
* **Infrastruktur:** Gitea (CI/CD), Docker, Pangolin Tunnel. (KEIN GitHub, KEIN Cloudflare).
## 👁️ Anti-Halluzinations-Protokoll
Du bist an strikte, evidenzbasierte Entwicklung gebunden:
1. **Kein "Erledigt" ohne Beweis:** Ein Task ist erst abgeschlossen, wenn Test-Logs oder ein Build vorliegen.
2. **Verifikation ausstehend:** Generierter, ungetesteter Code muss diesen Vermerk zwingend tragen.
3. **Fakten-Check:** Wenn du den Code nicht im Kontext hast (z.B. eine spezifische Gradle-Datei), fordere sie aktiv vom User an, anstatt blind zu raten.
## ⚙️ Provider-Spezifika (Google Gemini / Web-Meta-Modus)
* Du agierst als "Gemini" über die Web-Oberfläche. Deine primäre Aufgabe ist die strategische Meta-Ebene, Architektur-Analyse, Review von CI/CD-Pipelines und das Sparring bei komplexen Refactoring-Plänen.
* **Antwort-Stil:** Antworte prägnant, strukturiert und nutze das bereitgestellte Formatierungstoolkit (Markdown, klare Hierarchien, Code-Blöcke). Vermeide unnötige Floskeln und komm direkt auf den technischen Punkt.
+34
View File
@@ -0,0 +1,34 @@
## 🚀 Identität & Arbeitsmodus (Chamäleon-Modus)
Du bist ein hochqualifizierter KI-Assistent für das Softwareprojekt "Meldestelle" von Stefan.
Ich weise dir in meinen Prompts Aufgaben zu. Nimm sofort die entsprechende Rolle an, beginne deine Antwort zwingend mit dem passenden Badge und passe dein Vokabular an:
* 🏗️ **[Lead Architect]:** System-Design, Gradle-Build-Logik, Modulstruktur.
* 📜 **[Rulebook Expert]:** Validiert Business-Rules gegen das ÖTO/FEI Regelwerk.
* 👷 **[Backend Developer]:** Kotlin & Spring Boot Experte.
* 🎨 **[Frontend Expert]:** KMP & Compose Desktop Spezialist.
* 🐧 **[DevOps Engineer]:** Infrastruktur (Docker, CI/CD, Proxmox).
**Arbeitsanweisung:** Bearbeite pro Antwort immer nur EINE fachliche Aufgabe.
## 🏗️ Projekt-Strategie (Reality-Reset)
1. **Desktop-First & Offline-First:** Das Primärziel ist eine autarke Compose Desktop App (KMP). Sie muss auf Turnieren ohne Internet funktionieren (lokale Persistenz).
2. **Optionales Backend:** Ein Spring Boot Stack (PostgreSQL, Valkey, Keycloak) wird nur für Multi-Tenant-Verwaltung, Registrierung und P2P-Sync genutzt.
3. **Domain-Driven Design (DDD):** Die absolute Business-Hierarchie lautet: Veranstaltung -> Turnier -> Bewerb/Abteilung.
4. **Der System-Akteur:** Der primäre "Actor" in allen Use-Cases ist *nicht* der Veranstalter, sondern zwingend die Person, die die Meldestelle betreut (Actor = Meldestelle).
## 🛠️ Der verbindliche Tech-Stack
Generiere Code ausschließlich für diese exakten Versionen und Paradigmen:
* **Frontend (KMP):** Kotlin 2.3.21, Compose Multiplatform 1.10.3, Ktor Client 3.4.1, SQLDelight.
* **Backend:** Spring Boot 3.5.9 (JDK 25), Ktor Server (wo spezifiziert), Exposed 1.1.1.
* **Infrastruktur:** Gitea (CI/CD), Docker, Pangolin Tunnel. (KEIN GitHub, KEIN Cloudflare).
## 👁️ Anti-Halluzinations-Protokoll
Du bist an strikte, evidenzbasierte Entwicklung gebunden:
1. **Kein "Erledigt" ohne Beweis:** Ein Task ist erst abgeschlossen, wenn Test-Logs oder ein Build vorliegen.
2. **Verifikation ausstehend:** Generierter, ungetesteter Code muss diesen Vermerk zwingend tragen.
3. **Fakten-Check:** Wenn du den Code nicht im Kontext hast (z.B. eine spezifische Gradle-Datei), fordere sie aktiv vom User an, anstatt blind zu raten.
## ⚙️ Provider-Spezifika (JetBrains Junie / IDE-Modus)
* Dein Name ist "Junie". Du arbeitest als hochintegrierter KI-Assistent direkt innerhalb von IntelliJ IDEA.
* **Kontext-Fokus:** Nutze die lokalen Projektdateien, Indizes und das Git-Log intensiv. Wenn Refactorings oder Code-Generierungen anstehen, achte penibel darauf, dass bestehende Datei-Imports (Kotlin-Packages) nicht zerschossen werden.
* **Generierungs-Gate:** Halte dich strikt an die im Projekt hinterlegten Formatierungsregeln für Detekt und Ktlint.
+56
View File
@@ -0,0 +1,56 @@
name: Feature Build — Windows MSI (via Conveyor)
on:
workflow_dispatch: # Nur noch manueller Start möglich, da ARM64-Runner inkompatibel
# push:
# branches: [ "feature/*" ] # Deaktiviert wegen ARM64 Exec Format Error
jobs:
package-windows:
name: 📦 Windows .msi Packaging
# Desktop-CI ist nun via Conveyor auf Linux möglich
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup JDK 21 (Temurin)
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: gradle
- name: Gradle Build (Uber-JAR)
run: |
./gradlew :frontend:shells:meldestelle-desktop:jvmJar --no-daemon
ls -lh frontend/shells/meldestelle-desktop/build/libs/
- name: Setup Conveyor
run: |
# Conveyor-Installation via Debian-Paket (stabiler in CI)
sudo apt-get update && sudo apt-get install -y curl
# Wir nutzen die offizielle Empfehlung für Debian-basierte Systeme
curl -L https://conveyor.hydraulic.dev/install.sh -o install-conveyor.sh
# Validierung: Wenn es kein Shell-Skript ist (sondern HTML), abbrechen
if grep -q "<!DOCTYPE HTML" install-conveyor.sh; then
echo "Fehler: Download-URL lieferte HTML statt Skript. Nutze npm-Fallback."
npm install -g @hydraulic/conveyor
else
chmod +x install-conveyor.sh
./install-conveyor.sh
fi
echo "$HOME/.conveyor/bin" >> $GITHUB_PATH
- name: Windows .msi mit Conveyor bauen
run: |
# HINWEIS: Erfordert aktuell einen x64-Linux-Runner.
# Schlägt auf ARM64 (Zora) mit 'Exec format error' fehl.
CONVEYOR_BIN=$(which conveyor || echo "$HOME/.conveyor/bin/conveyor")
$CONVEYOR_BIN make windows-msi
- name: .msi Artefakt hochladen
uses: actions/upload-artifact@v4
with:
name: meldestelle-windows-feature-build
path: output/*.msi
if-no-files-found: error
+4
View File
@@ -56,3 +56,7 @@ desktop.ini
docs/temp/ docs/temp/
docs/Bin/ docs/Bin/
docs/_archive/ docs/_archive/
# Conveyor
conveyor.rootkey
output/
+9 -9
View File
@@ -3,7 +3,7 @@
Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten. Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten.
Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions. Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions.
## 🚀 Strategische Ausrichtung (Reality-Reset 28.04.2026) ## 🚀 Strategische Ausrichtung (Reality-Reset 15.06.2026)
Das Projekt **"Meldestelle"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software. Das Projekt **"Meldestelle"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software.
1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert. 1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert.
@@ -17,21 +17,21 @@ abgeschlossene Phasen ohne entsprechende Implementierung sind untersagt.
Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kontext und die Verantwortlichkeit zu klären. Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kontext und die Verantwortlichkeit zu klären.
* **🏗️ [Lead Architect]**: Hüter der **MASTER_ROADMAP**. Verantwortlich für System-Design, Build-Logik (Gradle), Modulstruktur und ADRs. * **🏗️ [Lead Architect]**: Hüter der **MASTER_ROADMAP**. Verantwortlich für System-Design, Build-Logik (Gradle), Modulstruktur und ADRs.
* [Playbook](docs/04_Agents/Playbooks/Architect.md) * [Playbook](docs/05_Governance/Agents/Playbooks/Architect.md)
* **📜 [Rulebook Expert]**: Wächter über **ÖTO & FEI**. Validiert Business-Rules gegen das offizielle Pferdesport-Regelwerk. * **📜 [Rulebook Expert]**: Wächter über **ÖTO & FEI**. Validiert Business-Rules gegen das offizielle Pferdesport-Regelwerk.
* [Playbook](docs/04_Agents/Playbooks/RulebookExpert.md) * [Playbook](docs/05_Governance/Agents/Playbooks/RulebookExpert.md)
* **👷 [Backend Developer]**: Kotlin & Spring Boot Experte. Fokus auf DDD, Persistenz (Postgres) und **Delta-Sync APIs**. * **👷 [Backend Developer]**: Kotlin & Spring Boot Experte. Fokus auf DDD, Persistenz (Postgres) und **Delta-Sync APIs**.
* [Playbook](docs/04_Agents/Playbooks/BackendDeveloper.md) * [Playbook](docs/05_Governance/Agents/Playbooks/BackendDeveloper.md)
* **🎨 [Frontend Expert]**: KMP & Compose Desktop Spezialist. Implementiert State-Management und High-Performance UI. * **🎨 [Frontend Expert]**: KMP & Compose Desktop Spezialist. Implementiert State-Management und High-Performance UI.
* [Playbook](docs/04_Agents/Playbooks/FrontendExpert.md) * [Playbook](docs/05_Governance/Agents/Playbooks/FrontendExpert.md)
* **🖌️ [UI/UX Designer]**: "Toolsmith" für High-Density Enterprise-UIs. Fokus auf Tastatur-Bedienbarkeit und Effizienz. * **🖌️ [UI/UX Designer]**: "Toolsmith" für High-Density Enterprise-UIs. Fokus auf Tastatur-Bedienbarkeit und Effizienz.
* [Playbook](docs/04_Agents/Playbooks/UIUXDesigner.md) * [Playbook](docs/05_Governance/Agents/Playbooks/UIUXDesigner.md)
* **🐧 [DevOps Engineer]**: Infrastruktur-Automatisierung (Docker, Gitea-Actions). Fokus auf Stabilität und lokale Dev-Umgebung. * **🐧 [DevOps Engineer]**: Infrastruktur-Automatisierung (Docker, Gitea-Actions). Fokus auf Stabilität und lokale Dev-Umgebung.
* [Playbook](docs/04_Agents/Playbooks/DevOpsEngineer.md) * [Playbook](docs/05_Governance/Agents/Playbooks/DevOpsEngineer.md)
* **🧐 [QA Specialist]**: Test-Stratege (Shift-Left). Fokus auf Unit-, Integration- und Edge-Case-Tests (Testing Pyramid). * **🧐 [QA Specialist]**: Test-Stratege (Shift-Left). Fokus auf Unit-, Integration- und Edge-Case-Tests (Testing Pyramid).
* [Playbook](docs/04_Agents/Playbooks/QASpecialist.md) * [Playbook](docs/05_Governance/Agents/Playbooks/QASpecialist.md)
* **🧹 [Curator]**: Wissens-Management & Dokumentations-Check (ADR, Reference, Journal). Beendet jede Session. * **🧹 [Curator]**: Wissens-Management & Dokumentations-Check (ADR, Reference, Journal). Beendet jede Session.
* [Playbook](docs/04_Agents/Playbooks/Curator.md) * [Playbook](docs/05_Governance/Agents/Playbooks/Curator.md)
## 2. Der "Meldestelle"-Workflow ## 2. Der "Meldestelle"-Workflow
1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`. 1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`.
+6 -2
View File
@@ -20,7 +20,7 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities | | [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur | | [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md) Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/Concepts/konzept-offline-first-desktop-backend-de.md)
--- ---
@@ -114,4 +114,8 @@ Beiträge sind willkommen. Bitte lies zunächst die Entwickler-Guides unter [`do
Dieses Projekt steht unter der [MIT License](LICENSE). Dieses Projekt steht unter der [MIT License](LICENSE).
## Gitea - Test ---
## Test
Das ist der 2. Versuch über Remote zu Committen
@@ -8,7 +8,7 @@ import io.valkey.springframework.data.valkey.core.ValkeyTemplate
import io.valkey.springframework.data.valkey.serializer.StringValkeySerializer import io.valkey.springframework.data.valkey.serializer.StringValkeySerializer
import kotlinx.coroutines.joinAll import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.testcontainers.containers.GenericContainer import org.testcontainers.containers.GenericContainer
@@ -70,7 +70,7 @@ class ValkeyDistributedCachePerformanceTest {
} }
@Test @Test
fun `test cache performance with high concurrent access`() = runTest { fun `test cache performance with high concurrent access`() = runBlocking {
logger.info { "Starting concurrent access test" } logger.info { "Starting concurrent access test" }
val numberOfCoroutines = 100 val numberOfCoroutines = 100
val operationsPerCoroutine = 50 val operationsPerCoroutine = 50
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
@@ -2,6 +2,7 @@
package at.mocode.zns.importer package at.mocode.zns.importer
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.* import at.mocode.masterdata.domain.repository.*
import at.mocode.zns.parser.ZnsFunktionaerParser import at.mocode.zns.parser.ZnsFunktionaerParser
import at.mocode.zns.parser.ZnsPferdParser import at.mocode.zns.parser.ZnsPferdParser
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -4,8 +4,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
@@ -3,6 +3,7 @@
package at.mocode.masterdata.domain.model package at.mocode.masterdata.domain.model
import at.mocode.core.domain.model.DatenQuelleE import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.serialization.InstantSerializer import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.LocalDateSerializer import at.mocode.core.domain.serialization.LocalDateSerializer
@@ -14,16 +15,6 @@ import kotlin.time.Clock
import kotlin.time.Instant import kotlin.time.Instant
import kotlin.uuid.Uuid import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
/** /**
* Domain model representing a rider (Reiter) in the actor-context. * Domain model representing a rider (Reiter) in the actor-context.
* *
@@ -4,10 +4,10 @@ package at.mocode.masterdata.infrastructure.persistence.reiter
import at.mocode.core.domain.model.DatenQuelleE import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterAltersKlasseE import at.mocode.core.domain.model.ReiterAltersKlasseE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.database.DatabaseFactory import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.Reiter import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.ReiterRepository import at.mocode.masterdata.domain.repository.ReiterRepository
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.v1.core.and
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# =================================================================== # ===================================================================
# === CENTRALIZED BUILD ARGUMENTS === # === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1 ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25 ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT ARG VERSION=1.0.0-SNAPSHOT
+51 -30
View File
@@ -38,7 +38,7 @@ plugins {
// ### ALLPROJECTS CONFIGURATION ### // ### ALLPROJECTS CONFIGURATION ###
// ################################################################## // ##################################################################
val isWasmEnabled = findProperty("enableWasm")?.toString()?.toBoolean() ?: false val isWasmEnabled: Boolean = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Zentrale Versionierung — liest version.properties (SemVer) // Zentrale Versionierung — liest version.properties (SemVer)
@@ -47,10 +47,10 @@ val versionProps =
java.util.Properties().also { props -> java.util.Properties().also { props ->
rootProject.file("version.properties").inputStream().use { props.load(it) } rootProject.file("version.properties").inputStream().use { props.load(it) }
} }
val vMajor = versionProps.getProperty("VERSION_MAJOR", "1") val vMajor: String = versionProps.getProperty("VERSION_MAJOR", "1")
val vMinor = versionProps.getProperty("VERSION_MINOR", "0") val vMinor: String = versionProps.getProperty("VERSION_MINOR", "0")
val vPatch = versionProps.getProperty("VERSION_PATCH", "0") val vPatch: String = versionProps.getProperty("VERSION_PATCH", "0")
val vQualifier = versionProps.getProperty("VERSION_QUALIFIER", "").trim() val vQualifier: String = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier" val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier"
allprojects { allprojects {
@@ -90,7 +90,7 @@ subprojects {
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED") jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
// Suppress ByteBuddy/Mockito dynamic agent loading warnings (Java 21+) // Suppress ByteBuddy/Mockito dynamic agent loading warnings (Java 21+)
jvmArgs("-XX:+EnableDynamicAgentLoading") jvmArgs("-XX:+EnableDynamicAgentLoading")
// Increase test JVM memory with a stable configuration jvmArgs("--enable-native-access=ALL-UNNAMED")
minHeapSize = "512m" minHeapSize = "512m"
maxHeapSize = "2g" maxHeapSize = "2g"
// Parallel test execution for better performance // Parallel test execution for better performance
@@ -113,7 +113,7 @@ subprojects {
// (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings) // (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings)
// to avoid compiler-flag incompatibilities across toolchains. // to avoid compiler-flag incompatibilities across toolchains.
// (B) Conditional Wasm/JS Target handling based on `enableWasm` property // (B) Conditional Wasm/JS Target handling based on the ` enableWasm ` property
// This significantly reduces build times during Desktop development. // This significantly reduces build times during Desktop development.
// Flag is defined at the beginning of the script. // Flag is defined at the beginning of the script.
@@ -166,6 +166,7 @@ subprojects {
jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false") jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false")
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED") jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
jvmArgs("-XX:+EnableDynamicAgentLoading") jvmArgs("-XX:+EnableDynamicAgentLoading")
jvmArgs("--enable-native-access=ALL-UNNAMED")
maxHeapSize = "2g" maxHeapSize = "2g"
dependsOn("testClasses") dependsOn("testClasses")
} }
@@ -175,20 +176,30 @@ subprojects {
// Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin) // Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin)
tasks.withType<Exec>().configureEach { tasks.withType<Exec>().configureEach {
// Merge existing NODE_OPTIONS with --no-deprecation // Merge existing NODE_OPTIONS with --no-deprecation
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS") val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation" val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged) environment("NODE_OPTIONS", merged)
// Also set the legacy switch to silence warnings entirely // Also set the legacy switch to silence warnings entirely
environment("NODE_NO_WARNINGS", "1") environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues // Set a Chrome binary path to avoid snap permission issues
environment("CHROME_BIN", "/usr/bin/google-chrome-stable") if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROMIUM_BIN", "/usr/bin/chromium") environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium") environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
} }
// ------------------------------ // ------------------------------
// Detekt & Ktlint default setup // Detekt & Ktlint default setup
// ------------------------------ // ------------------------------
// PERFORMANCE: Deaktiviert standardmäßig in jedem Build, nur explizit ausführen
tasks.withType<Detekt>().configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
tasks.matching { it.name == "ktlintCheck" }.configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
plugins.withId("io.gitlab.arturbosch.detekt") { plugins.withId("io.gitlab.arturbosch.detekt") {
extensions.configure(DetektExtension::class.java) { extensions.configure(DetektExtension::class.java) {
buildUponDefaultConfig = true buildUponDefaultConfig = true
@@ -267,7 +278,6 @@ tasks.register("checkBundleBudget") {
} }
shells.forEach { shell -> shells.forEach { shell ->
val key = shell.path.trimStart(':').replace(':', '/') // or use a colon form for budgets keys below
val colonKey = shell.path.trimStart(':').replace('/', ':').trim() // ensure ":a:b:c" val colonKey = shell.path.trimStart(':').replace('/', ':').trim() // ensure ":a:b:c"
// Budgets are keyed by a Gradle path with colons but without leading colon in config for readability // Budgets are keyed by a Gradle path with colons but without leading colon in config for readability
val budgetKeyCandidates = val budgetKeyCandidates =
@@ -362,8 +372,8 @@ tasks.register("staticAnalysis") {
// Apply Dokka (V2) automatically to Kotlin subprojects // Apply Dokka (V2) automatically to Kotlin subprojects
subprojects { subprojects {
plugins.withId("org.jetbrains.kotlin.jvm") { apply(plugin = "org.jetbrains.dokka") } plugins.withId("org.jetbrains.kotlin.jvm") { pluginManager.apply("org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.multiplatform") { apply(plugin = "org.jetbrains.dokka") } plugins.withId("org.jetbrains.kotlin.multiplatform") { pluginManager.apply("org.jetbrains.dokka") }
} }
// Aggregate tasks to build multi-module docs in Markdown (GFM) and HTML // Aggregate tasks to build multi-module docs in Markdown (GFM) and HTML
@@ -372,27 +382,36 @@ val dokkaAll =
tasks.register("dokkaAll") { tasks.register("dokkaAll") {
group = "documentation" group = "documentation"
description = "Builds Dokka (V2) for all modules and aggregates outputs under build/dokka/all" description = "Builds Dokka (V2) for all modules and aggregates outputs under build/dokka/all"
// Trigger Dokka generation in all subprojects that have the Dokka plugin // PERFORMANCE: Nur ausführen wenn explizit gefordert
dependsOn( enabled = project.hasProperty("runDokka")
// Capture required values for configuration cache
val rootBuildDir = layout.buildDirectory.get().asFile
val subprojectData =
subprojects subprojects
.filter { it.plugins.hasPlugin("org.jetbrains.dokka") } .filter { it.plugins.hasPlugin("org.jetbrains.dokka") }
.map { "${it.path}:dokkaGenerate" }, .map { p ->
) Triple(p.path, p.name, p.layout.buildDirectory.get().asFile)
}
// Trigger Dokka generation in all subprojects that have the Dokka plugin
dependsOn(subprojectData.map { "${it.first}:dokkaGenerate" })
doLast { doLast {
val dest = layout.buildDirectory.dir("dokka/all").get().asFile val dest = File(rootBuildDir, "dokka/all")
if (dest.exists()) dest.deleteRecursively() if (dest.exists()) dest.deleteRecursively()
dest.mkdirs() dest.mkdirs()
val modules = mutableListOf<Pair<String, String>>() val modules = mutableListOf<Pair<String, String>>()
subprojects.filter { it.plugins.hasPlugin("org.jetbrains.dokka") }.forEach { p -> subprojectData.forEach { (pPath, pName, pBuildDir) ->
// Dokka V2 writes into build/dokka/html // Dokka V2 writes into build/dokka/html
val outHtml = p.layout.buildDirectory.dir("dokka/html").get().asFile val outHtml = File(pBuildDir, "dokka/html")
if (outHtml.exists()) { if (outHtml.exists()) {
val modulePath = p.path.trimStart(':').replace(':', '/') val modulePath = pPath.trimStart(':').replace(':', '/')
val targetDir = File(dest, modulePath) val targetDir = File(dest, modulePath)
outHtml.copyRecursively(targetDir, overwrite = true) outHtml.copyRecursively(targetDir, overwrite = true)
modules.add(p.name to modulePath) modules.add(pName to modulePath)
} }
} }
@@ -451,17 +470,19 @@ tasks.register("docs") {
// Apply Node warning suppression on root project Exec tasks as well // Apply Node warning suppression on root project Exec tasks as well
// Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env // Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env
tasks.withType<Exec>().configureEach { tasks.withType<Exec>().configureEach {
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS") val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation" val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged) environment("NODE_OPTIONS", merged)
environment("NODE_NO_WARNINGS", "1") environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues // Set a Chrome binary path to avoid snap permission issues
environment("CHROME_BIN", "/usr/bin/google-chrome-stable") if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROMIUM_BIN", "/usr/bin/chromium") environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium") environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
} }
tasks.wrapper { tasks.wrapper {
gradleVersion = "9.4.1" gradleVersion = "9.5.0"
distributionType = Wrapper.DistributionType.BIN distributionType = Wrapper.DistributionType.BIN
} }
+46
View File
@@ -0,0 +1,46 @@
include required("/stdlib/jdk/21/amazon.conf")
include required("https://raw.githubusercontent.com/hydraulic-software/conveyor/master/configs/jvm/extract-native-libraries.conf")
app {
display-name = "Meldestelle"
rdns-name = "at.mocode.meldestelle"
vendor = "mo-code.at"
contact-email = "support@mo-code.at"
version = "1.0.1"
description = "ÖTO-konforme Turnier-Meldestelle Profi Desktop App"
# Ziel-Plattformen: Windows und Linux
machines = [ windows.amd64, linux.amd64.glibc ]
site.base-url = "localhost"
# Icons werden im Ordner gesucht
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources/icon.png"
jvm {
gui {
main-class = "at.mocode.frontend.shell.desktop.MainKt"
}
jvm-options = [
"-Xms256m",
"-Xmx1024m",
"-Dfile.encoding=UTF-8",
"--enable-native-access=ALL-UNNAMED"
]
}
# JARs aus dem Gradle-Build
inputs += "frontend/shells/meldestelle-desktop/build/libs/*.jar"
windows {
upgrade-uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
menu-group = "Meldestelle"
desktop-shortcut = true
}
linux {
debian.control.depends = "libasound2, libgl1-mesa-glx, libx11-6"
}
}
conveyor.compatibility-level = 22
@@ -0,0 +1,19 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.domain.model
import at.mocode.core.domain.serialization.LocalDateSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
@@ -1,10 +1,10 @@
package at.mocode.zns.parser package at.mocode.zns.parser
import at.mocode.core.domain.model.DatenQuelleE import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.parser.FixedWidthLineReader import at.mocode.core.utils.parser.FixedWidthLineReader
import at.mocode.masterdata.domain.model.Reiter import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid import kotlin.uuid.Uuid
+20 -20
View File
@@ -12,8 +12,8 @@ services:
context: . context: .
dockerfile: backend/infrastructure/gateway/Dockerfile dockerfile: backend/infrastructure/gateway/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -102,8 +102,8 @@ services:
context: . context: .
dockerfile: backend/services/ping/Dockerfile dockerfile: backend/services/ping/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -179,8 +179,8 @@ services:
context: . context: .
dockerfile: backend/services/masterdata/Dockerfile dockerfile: backend/services/masterdata/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -256,8 +256,8 @@ services:
context: . context: .
dockerfile: backend/services/events/Dockerfile dockerfile: backend/services/events/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -331,8 +331,8 @@ services:
context: . context: .
dockerfile: backend/services/zns-import/Dockerfile dockerfile: backend/services/zns-import/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -407,8 +407,8 @@ services:
context: . context: .
dockerfile: backend/services/results/results-service/Dockerfile dockerfile: backend/services/results/results-service/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -482,8 +482,8 @@ services:
context: . context: .
dockerfile: backend/services/billing/billing-service/Dockerfile dockerfile: backend/services/billing/billing-service/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -555,8 +555,8 @@ services:
context: . context: .
dockerfile: backend/services/mail/Dockerfile dockerfile: backend/services/mail/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -627,8 +627,8 @@ services:
context: . context: .
dockerfile: backend/services/scheduling/scheduling-service/Dockerfile dockerfile: backend/services/scheduling/scheduling-service/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
@@ -700,8 +700,8 @@ services:
context: . context: .
dockerfile: backend/services/series/series-service/Dockerfile dockerfile: backend/services/series/series-service/Dockerfile
args: args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}" GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}" JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}" VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}" BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels: labels:
+1 -1
View File
@@ -3,7 +3,7 @@ name: "${PROJECT_NAME:-meldestelle}"
include: include:
- dc-infra.yaml - dc-infra.yaml
- dc-backend.yaml - dc-backend.yaml
- dc-gui.yaml #- dc-gui.yaml
- dc-ops.yaml - dc-ops.yaml
# Globale Definitionen, falls nötig (meistens reichen die in den Teil-Dateien, # Globale Definitionen, falls nötig (meistens reichen die in den Teil-Dateien,
@@ -1,71 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-15
---
# Frontend-Architektur & Modularisierungsstrategie
**Status:** ENTWURF
**Zuletzt aktualisiert:** 2026-01-19
**Kontext:** Migration zu Clean Architecture & Feature-Modulen
---
## 1. Übersicht
Die Frontend-Architektur von **Meldestelle** basiert auf **Kotlin Multiplatform (KMP)** mit **Compose Multiplatform** für die Benutzeroberfläche. Wir folgen einem strikten **Clean Architecture**-Ansatz, um Testbarkeit, Skalierbarkeit und Trennung der Zuständigkeiten sicherzustellen.
## 2. Modulstruktur
Das Projekt ist in folgende Schichten unterteilt:
### 2.1 Core-Module (`frontend/core`)
Wiederverwendbare Komponenten, die unabhängig von spezifischen Geschäftsfunktionen sind.
* `core-network`: Zentrale HTTP-Client-Konfiguration (Auth, Logging, ContentNegotiation).
* `core-sync`: Generische Synchronisierungslogik (`SyncManager`, `SyncableRepository`).
* `core-ui`: Gemeinsame UI-Komponenten und Design-System.
### 2.2 Feature-Module (`frontend/features`)
Jede Geschäftsdomäne (z.B. `ping`, `auth`, `events`) liegt in ihrem eigenen Modul.
Ein Feature-Modul MUSS die **Clean Architecture** Paketstruktur einhalten:
* `at.mocode.{feature}.feature.domain`
* **Entitäten:** Reine Datenklassen.
* **Interfaces:** Repository-Interfaces, Service-Interfaces.
* **Use Cases:** Geschäftslogik (optional, für komplexe Logik).
* `at.mocode.{feature}.feature.data`
* **Implementierungen:** Repository-Implementierungen, API-Clients.
* **DTOs:** Data Transfer Objects (wenn von Domain-Entitäten abweichend).
* `at.mocode.{feature}.feature.presentation`
* **ViewModels:** Zustandsverwaltung.
* **Screens:** Composable-Funktionen.
* `at.mocode.{feature}.feature.di`
* **Koin-Modul:** Konfiguration der Dependency Injection.
### 2.3 Shells (`frontend/shells`)
Anwendungs-Einstiegspunkte, die alles zusammenführen.
* `meldestelle-portal`: Die Haupt-Web-/Desktop-Anwendung.
## 3. Migrationsstrategie (Übergangsphase)
Wir migrieren aktuell von einer monolithischen `clients`-Paketstruktur zu modularen Feature-Modulen.
**Regeln für die Migration:**
1. **Neue Features:** Müssen direkt in `frontend/features/{name}` unter Verwendung der Clean Architecture-Struktur implementiert werden.
2. **Bestehende Features:** Werden schrittweise migriert.
3. **Koexistenz:** Während des Übergangs ist Legacy-Code in `clients/` erlaubt, aber als veraltet markiert.
4. **Dependency Injection:** Legacy-Code muss die neuen Koin-Module verwenden, sofern verfügbar.
5. **Keine Ghost-Klassen:** Klassen nicht duplizieren. Wenn eine Klasse in ein Feature-Modul verschoben wird, muss die alte in `clients/` gelöscht werden.
## 4. Wichtige Entscheidungen (ADRs)
### ADR-001: Entkopplung der Sync-Logik
* **Entscheidung:** ViewModels dürfen nicht direkt vom `SyncManager` abhängen.
* **Begründung:** Um einfacheres Testen zu ermöglichen und die Komplexität des generischen Sync-Mechanismus zu verbergen.
* **Umsetzung:** Ein Domain-Service-Interface (z.B. `PingSyncService`) einführen, das den `SyncManager`-Aufruf kapselt.
### ADR-002: Feature-Modul-Isolation
* **Entscheidung:** Feature-Module sollten nach Möglichkeit nicht direkt voneinander abhängen.
* **Kommunikation:** Gemeinsame Core-Module oder lose Kopplung über Interfaces/Events verwenden, wenn modulübergreifende Kommunikation nötig ist.
---
**Freigegeben von:** Lead Architect
@@ -1,51 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
---
# Open-Source-Konformität & Lizenz-Checkliste
Dieses Dokument dient der Überwachung und Sicherstellung der Open-Source-Konformität des Projekts **Meldestelle**. Es wird vom Lead Architect gepflegt.
## Status der Kern-Komponenten (Stand: Januar 2026)
| Komponente | Lizenz | Status | Risiko | Maßnahme / Kommentar |
| :--- | :--- | :--- | :--- | :--- |
| **Kotlin / JVM** | Apache 2.0 / GPLv2+CE | ✅ OK | Sehr gering | Standard-Stack. |
| **Spring Boot / Cloud** | Apache 2.0 | ✅ OK | Sehr gering | |
| **PostgreSQL** | PostgreSQL (BSD-like) | ✅ OK | Sehr gering | |
| **Redis** | **RSALv2 / SSPL** | ⚠️ KRITISCH | Hoch | **Umstieg auf Valkey (BSD) geplant.** |
| **Consul** | **BSL 1.1** | ⚠️ BEOBACHTEN | Mittel | Lizenzänderung durch HashiCorp. Für interne Nutzung aktuell unkritisch. |
| **Keycloak** | Apache 2.0 | ✅ OK | Gering | |
| **SQLDelight** | Apache 2.0 | ✅ OK | Sehr gering | |
| **Redisson** | Apache 2.0 (Core) | ✅ OK | Gering | Sicherstellen, dass keine PRO-Features genutzt werden. |
---
## Checkliste für neue Abhängigkeiten
Bevor eine neue Bibliothek oder Infrastruktur-Komponente hinzugefügt wird, muss sie folgende Kriterien erfüllen:
1. **Lizenz-Typ:**
* Bevorzugt: Apache 2.0, MIT, BSD (3-Clause).
* Akzeptabel: MPL 2.0.
* Einzelfallprüfung: LGPL (nur als dynamische Bibliothek).
* **Verboten:** AGPL, SSPL, RSAL, BSL (sofern nicht explizit vom Architect freigegeben).
2. **Community & Governance:**
* Wird das Projekt von einer neutralen Foundation (Apache, CNCF, Linux Foundation) verwaltet?
* Gibt es eine "Single Vendor" Abhängigkeit (Risiko einer plötzlichen Lizenzänderung)?
3. **Transitive Abhängigkeiten:**
* Bringt die Bibliothek "versteckte" Copyleft-Lizenzen mit? (Check via Gradle License Plugin).
---
## TODOs & Strategische Entscheidungen
- [ ] **Migration Redis -> Valkey:** Umstellung der Docker-Images und Test der Kompatibilität.
- [ ] **Consul Review:** Jährliche Prüfung der BSL-Auswirkungen auf unser Deployment-Modell.
- [ ] **Automatisierung:** Integration eines License-Check-Plugins in den CI-Build (z.B. `com.github.jk1.dependency-license-report`).
---
*Dieses Dokument ist Teil der "Docs-as-Code" Strategie und muss bei jeder Änderung am Tech-Stack aktualisiert werden.*
@@ -0,0 +1,54 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
---
# Open-Source-Konformität & Lizenz-Checkliste
Dieses Dokument dient der Überwachung und Sicherstellung der Open-Source-Konformität des Projekts **Meldestelle**. Es
wird vom Lead Architect gepflegt.
## Status der Kern-Komponenten (Stand: Januar 2026)
| Komponente | Lizenz | Status | Risiko | Maßnahme / Kommentar |
|:------------------------|:----------------------|:--------------|:------------|:------------------------------------------------------------------------|
| **Kotlin / JVM** | Apache 2.0 / GPLv2+CE | ✅ OK | Sehr gering | Standard-Stack. |
| **Spring Boot / Cloud** | Apache 2.0 | ✅ OK | Sehr gering | |
| **PostgreSQL** | PostgreSQL (BSD-like) | ✅ OK | Sehr gering | |
| **Redis** | **RSALv2 / SSPL** | ⚠️ KRITISCH | Hoch | **Umstieg auf Valkey (BSD) geplant.** |
| **Consul** | **BSL 1.1** | ⚠️ BEOBACHTEN | Mittel | Lizenzänderung durch HashiCorp. Für interne Nutzung aktuell unkritisch. |
| **Keycloak** | Apache 2.0 | ✅ OK | Gering | |
| **SQLDelight** | Apache 2.0 | ✅ OK | Sehr gering | |
| **Redisson** | Apache 2.0 (Core) | ✅ OK | Gering | Sicherstellen, dass keine PRO-Features genutzt werden. |
---
## Checkliste für neue Abhängigkeiten
Bevor eine neue Bibliothek oder Infrastruktur-Komponente hinzugefügt wird, muss sie folgende Kriterien erfüllen:
1. **Lizenz-Typ:**
* Bevorzugt: Apache 2.0, MIT, BSD (3-Clause).
* Akzeptabel: MPL 2.0.
* Einzelfallprüfung: LGPL (nur als dynamische Bibliothek).
* **Verboten:** AGPL, SSPL, RSAL, BSL (sofern nicht explizit vom Architect freigegeben).
2. **Community & Governance:**
* Wird das Projekt von einer neutralen Foundation (Apache, CNCF, Linux Foundation) verwaltet?
* Gibt es eine "Single Vendor" Abhängigkeit (Risiko einer plötzlichen Lizenzänderung)?
3. **Transitive Abhängigkeiten:**
* Bringt die Bibliothek "versteckte" Copyleft-Lizenzen mit? (Check via Gradle License Plugin).
---
## TODOs & Strategische Entscheidungen
- [ ] **Migration Redis -> Valkey:** Umstellung der Docker-Images und Test der Kompatibilität.
- [ ] **Consul Review:** Jährliche Prüfung der BSL-Auswirkungen auf unser Deployment-Modell.
- [ ] **Automatisierung:** Integration eines License-Check-Plugins in den CI-Build (z.B.
`com.github.jk1.dependency-license-report`).
---
*Dieses Dokument ist Teil der "Docs-as-Code" Strategie und muss bei jeder Änderung am Tech-Stack aktualisiert werden.*
@@ -3,6 +3,7 @@
Status: April 2026 Status: April 2026
## ✅ Abgeschlossene Migrationen (Feature-Module) ## ✅ Abgeschlossene Migrationen (Feature-Module)
- `billing-feature`: `at.mocode.frontend.features.billing` (KMP) - `billing-feature`: `at.mocode.frontend.features.billing` (KMP)
- `verein-feature`: `at.mocode.frontend.features.verein` (KMP) - `verein-feature`: `at.mocode.frontend.features.verein` (KMP)
- `nennung-feature`: `at.mocode.frontend.features.nennung` (KMP) - `nennung-feature`: `at.mocode.frontend.features.nennung` (KMP)
@@ -13,11 +14,14 @@ Status: April 2026
- `ping-feature`: `at.mocode.ping.feature` (muss noch auf `at.mocode.frontend.features.ping` vereinheitlicht werden) - `ping-feature`: `at.mocode.ping.feature` (muss noch auf `at.mocode.frontend.features.ping` vereinheitlicht werden)
## 🚧 Ausstehende Migrationen (von `at.mocode.desktop.v2` zu Features) ## 🚧 Ausstehende Migrationen (von `at.mocode.desktop.v2` zu Features)
Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/` basieren noch auf `StoreV2` (In-Memory Mock) und sollten in KMP-Module überführt werden:
Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/` basieren noch auf
`StoreV2` (In-Memory Mock) und sollten in KMP-Module überführt werden:
1. **Onboarding**: `OnboardingScreen.kt` -> Design-System Integration erfolgt, KMP-Modul folgt. 1. **Onboarding**: `OnboardingScreen.kt` -> Design-System Integration erfolgt, KMP-Modul folgt.
## 🧹 Architektur-Cleanup ## 🧹 Architektur-Cleanup
- [ ] `at.mocode.desktop.v2.StoreV2` entfernen, sobald alle Screens auf ViewModels und API-Repositories umgestellt sind. - [ ] `at.mocode.desktop.v2.StoreV2` entfernen, sobald alle Screens auf ViewModels und API-Repositories umgestellt sind.
- [ ] `at.mocode.desktop.v2.TurnierStoreV2` konsolidieren mit dem `turnier-feature`. - [ ] `at.mocode.desktop.v2.TurnierStoreV2` konsolidieren mit dem `turnier-feature`.
- [ ] Paketnamen vereinheitlichen: `at.mocode.ping.feature` -> `at.mocode.frontend.features.ping`. - [ ] Paketnamen vereinheitlichen: `at.mocode.ping.feature` -> `at.mocode.frontend.features.ping`.
@@ -26,6 +30,7 @@ Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/d
- [ ] `DesktopMainLayout.kt`: Die `when`-Zweige für `v2` Screens aufräumen, sobald die Module bereit sind. - [ ] `DesktopMainLayout.kt`: Die `when`-Zweige für `v2` Screens aufräumen, sobald die Module bereit sind.
## ✅ Abgeschlossen am 11.04.2026 ## ✅ Abgeschlossen am 11.04.2026
- Migration `pferde-feature`, `reiter-feature`, `funktionaer-feature`, `veranstalter-feature`. - Migration `pferde-feature`, `reiter-feature`, `funktionaer-feature`, `veranstalter-feature`.
- Integration in `DesktopMainLayout` und `AppScreen`. - Integration in `DesktopMainLayout` und `AppScreen`.
- Bereinigung der Repository-Pakete. - Bereinigung der Repository-Pakete.
@@ -9,7 +9,9 @@ last_update: 2026-04-03
## Ziel und Rahmen ## Ziel und Rahmen
Dieses Dokument definiert das Synchronisations-Konzept zwischen der Compose Desktop App (Meldestelle-Zentrale) und dem Backend in einem Offline-First Szenario. Es baut auf ADR-0021 (Tenant-Isolation) und ADR-0022 (LAN-Sync mit Lamport-Uhren) auf und erweitert sie um die WAN/Backend-Synchronisation. Dieses Dokument definiert das Synchronisations-Konzept zwischen der Compose Desktop App (Meldestelle-Zentrale) und dem
Backend in einem Offline-First Szenario. Es baut auf ADR-0021 (Tenant-Isolation) und ADR-0022 (LAN-Sync mit
Lamport-Uhren) auf und erweitert sie um die WAN/Backend-Synchronisation.
Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb des Veranstaltungsbetriebs. Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb des Veranstaltungsbetriebs.
@@ -18,32 +20,38 @@ Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb
1. Offline-First: Die Desktop-App ist voll funktionsfähig ohne Netzwerk; Synchronisation erfolgt opportunistisch. 1. Offline-First: Die Desktop-App ist voll funktionsfähig ohne Netzwerk; Synchronisation erfolgt opportunistisch.
2. Event-isoliert: Pro Veranstaltung eigener Datenraum (gemäß ADR-0021). Keine Vermischung von Events. 2. Event-isoliert: Pro Veranstaltung eigener Datenraum (gemäß ADR-0021). Keine Vermischung von Events.
3. Einheitliches Änderungsmodell: Wiederverwendung des `SyncEvent`-Logs (ADR-0022) für Desktop↔Backend. 3. Einheitliches Änderungsmodell: Wiederverwendung des `SyncEvent`-Logs (ADR-0022) für Desktop↔Backend.
4. Domänen-Mastership: Klare Schreibhoheiten reduzieren Konflikte, fachliche Regeln haben Vorrang vor rein technischen Timestamps. 4. Domänen-Mastership: Klare Schreibhoheiten reduzieren Konflikte, fachliche Regeln haben Vorrang vor rein technischen
Timestamps.
5. Deterministische Konfliktauflösung: Lamport-Uhren + Regel-Matrix; keine Abhängigkeit von Systemuhren. 5. Deterministische Konfliktauflösung: Lamport-Uhren + Regel-Matrix; keine Abhängigkeit von Systemuhren.
## Topologie & Rollen ## Topologie & Rollen
- Backend (Zentrale Plattform): - Backend (Zentrale Plattform):
- Master für: Stammdaten (Reiter, Pferde, Vereine, Funktionäre), Identität/Rollen, Gebührenkataloge, globale Referenzen. - Master für: Stammdaten (Reiter, Pferde, Vereine, Funktionäre), Identität/Rollen, Gebührenkataloge, globale
Referenzen.
- Aggregations-/Archiv-Quelle nach Veranstaltungsende (finale Ergebnisse, Abrechnungen). - Aggregations-/Archiv-Quelle nach Veranstaltungsende (finale Ergebnisse, Abrechnungen).
- Desktop (Meldestelle-Zentrale): - Desktop (Meldestelle-Zentrale):
- Master während der Veranstaltung für: Nennungen (operativ), Startreihenfolgen, Startlisten-Status, Ergebnisse/Protokolle (falls Richter nicht direkt am Backend), Kassa-Operationen vor Ort. - Master während der Veranstaltung für: Nennungen (operativ), Startreihenfolgen, Startlisten-Status,
- Hält lokales `SyncEvent`-Log + Snapshots (vgl. ADR-0022) und synchronisiert mit Backend, sobald Konnektivität besteht. Ergebnisse/Protokolle (falls Richter nicht direkt am Backend), Kassa-Operationen vor Ort.
- Hält lokales `SyncEvent`-Log + Snapshots (vgl. ADR-0022) und synchronisiert mit Backend, sobald Konnektivität
besteht.
Hinweis Mehrfach-Desktops: Genau eine „Zentrale“ pro Veranstaltung besitzt Schreibhoheit (Konfig-Flag `isEventAuthority=true`). Weitere Geräte sind Replikate/Clients. Hinweis Mehrfach-Desktops: Genau eine „Zentrale“ pro Veranstaltung besitzt Schreibhoheit (Konfig-Flag
`isEventAuthority=true`). Weitere Geräte sind Replikate/Clients.
## Datenkategorien & Mastership ## Datenkategorien & Mastership
| Kategorie | Master | Desktop Rechte | Backend Rechte | | Kategorie | Master | Desktop Rechte | Backend Rechte |
|--------------------------|----------------|--------------------------------|-----------------------------------| |---------------------------|-----------------|----------------------------------------------|----------------------------------|
| Stammdaten (Actor) | Backend | Lesen, lokal „provisional“ anlegen (Temp-ID) | Vollzugriff, ID-Zuteilung, Merge | | Stammdaten (Actor) | Backend | Lesen, lokal „provisional“ anlegen (Temp-ID) | Vollzugriff, ID-Zuteilung, Merge |
| Veranstaltungs-Stammdaten| Backend | Lesen | Vollzugriff | | Veranstaltungs-Stammdaten | Backend | Lesen | Vollzugriff |
| Nennungen operativ | Desktop | Vollzugriff | Lesen, Import nach Sync | | Nennungen operativ | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Startreihenfolge/Status | Desktop | Vollzugriff | Lesen, Import nach Sync | | Startreihenfolge/Status | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Bewertungen/Ergebnisse | Desktop/Richter| Vollzugriff (Eventzeitraum) | Lesen, Publikation/Archiv | | Bewertungen/Ergebnisse | Desktop/Richter | Vollzugriff (Eventzeitraum) | Lesen, Publikation/Archiv |
| Kassa/Finanzen vor Ort | Desktop | Vollzugriff | Lesen, Abgleich Summen | | Kassa/Finanzen vor Ort | Desktop | Vollzugriff | Lesen, Abgleich Summen |
Konflikte über Kategoriegrenzen werden durch Mastership-Regeln verhindert; verbleibende Konflikte werden per Regel-Matrix gelöst. Konflikte über Kategoriegrenzen werden durch Mastership-Regeln verhindert; verbleibende Konflikte werden per
Regel-Matrix gelöst.
## Änderungsmodell (Wiederverwendung `SyncEvent`) ## Änderungsmodell (Wiederverwendung `SyncEvent`)
@@ -71,11 +79,13 @@ data class SyncEvent(
## Lamport-Uhren & Vector-Clock (Optional) ## Lamport-Uhren & Vector-Clock (Optional)
- Primär: Lamport-Uhren wie ADR-0022. Gleichstand → lexikografisch größere `originNodeId` gewinnt (Determinismus). - Primär: Lamport-Uhren wie ADR-0022. Gleichstand → lexikografisch größere `originNodeId` gewinnt (Determinismus).
- Optional für feingranulare Erkennung: Per-Aggregat Vector-Clock (`Map<nodeId, lamport>`) zur Diagnose; Entscheidungsgrundlage bleibt Lamport + Fachregeln. - Optional für feingranulare Erkennung: Per-Aggregat Vector-Clock (`Map<nodeId, lamport>`) zur Diagnose;
Entscheidungsgrundlage bleibt Lamport + Fachregeln.
## Sync-Protokoll Desktop ↔ Backend (HTTPS) ## Sync-Protokoll Desktop ↔ Backend (HTTPS)
Transport: HTTPS (HTTP/2), JSON oder Protobuf, idempotente Endpunkte. Auth: mTLS zwischen Desktop und Backend ODER OAuth2 Client Credentials + Signatur der Batch-Payload. Transport: HTTPS (HTTP/2), JSON oder Protobuf, idempotente Endpunkte. Auth: mTLS zwischen Desktop und Backend ODER
OAuth2 Client Credentials + Signatur der Batch-Payload.
Empfohlene Endpunkte (pro `eventId`): Empfohlene Endpunkte (pro `eventId`):
@@ -94,42 +104,55 @@ Idempotenz: Jeder `SyncEvent` wird durch `(eventId, originNodeId, sequenceNumber
## Konfliktauflösung ## Konfliktauflösung
1) Strukturkonflikte (gleiches Aggregat, konkurrierende Events): 1) Strukturkonflikte (gleiches Aggregat, konkurrierende Events):
- Wenn eine Seite nicht Master ist → Event wird angenommen, aber als `PENDING_REVIEW` markiert; fachliche Entscheidung erforderlich (Backend-UI oder Desktop-Review-Queue).
- Wenn eine Seite nicht Master ist → Event wird angenommen, aber als `PENDING_REVIEW` markiert; fachliche Entscheidung
erforderlich (Backend-UI oder Desktop-Review-Queue).
- Beide Master (Sonderfälle, z. B. Ergebnisse während parallelem Backend-Fix): - Beide Master (Sonderfälle, z. B. Ergebnisse während parallelem Backend-Fix):
- Lamport höher gewinnt. - Lamport höher gewinnt.
- Gleichstand → `originNodeId`-Tiebreaker. - Gleichstand → `originNodeId`-Tiebreaker.
- Zusätzlich fachliche Heuristik optional: „Korrektur-Events“ (z. B. `ErgebnisKorrigiert`) schlagen normale `ErgebnisErfasst` bei gleichem Lamport. - Zusätzlich fachliche Heuristik optional: „Korrektur-Events“ (z. B. `ErgebnisKorrigiert`) schlagen normale
`ErgebnisErfasst` bei gleichem Lamport.
2) Identitätskonflikte (provisionale Stammdaten): 2) Identitätskonflikte (provisionale Stammdaten):
- Desktop darf temporäre Einträge (Temp-ID `tmp-...`) erzeugen. - Desktop darf temporäre Einträge (Temp-ID `tmp-...`) erzeugen.
- Beim Push führt Backend `Upsert+Merge` aus, weist finale IDs zu und liefert `IdMapping { tmpId -> finalId }` zurück. - Beim Push führt Backend `Upsert+Merge` aus, weist finale IDs zu und liefert `IdMapping { tmpId -> finalId }` zurück.
- Desktop ersetzt Referenzen transaktional und emittiert ein lokales `IdRemapped`-Event (kein Re-Upload nötig, außer für Diagnose). - Desktop ersetzt Referenzen transaktional und emittiert ein lokales `IdRemapped`-Event (kein Re-Upload nötig, außer für
Diagnose).
3) Reihenfolge-/Kausalitätskonflikte: 3) Reihenfolge-/Kausalitätskonflikte:
- Bei fehlenden Vorgänger-Events antwortet Backend mit `rejected: [id]` und `requiredSinceSeq`. Desktop zieht Delta (`pull`) und wiederholt den `push`.
- Bei fehlenden Vorgänger-Events antwortet Backend mit `rejected: [id]` und `requiredSinceSeq`. Desktop zieht Delta (
`pull`) und wiederholt den `push`.
## Snapshots & Recovery ## Snapshots & Recovery
- Snapshot-Intervall: standardmäßig 100 Events pro `(aggregateType, scope)` (wie ADR-0022), für WAN-Sync zusätzlich Full-State-Snapshot pro Veranstaltung vor Event-Abschluss. - Snapshot-Intervall: standardmäßig 100 Events pro `(aggregateType, scope)` (wie ADR-0022), für WAN-Sync zusätzlich
- Recovery: Desktop kann mit leerem Log starten → `snapshot/request` Full-State + `snapshotSeq` → weitere Deltas über `pull`. Full-State-Snapshot pro Veranstaltung vor Event-Abschluss.
- USB-Fallback (Notbetrieb): Export/Import von `sync_events` und `sync_snapshots` als verschlüsselte Archive (`.msync`). Offene Spezifikation; separater PoC. - Recovery: Desktop kann mit leerem Log starten → `snapshot/request` → Full-State + `snapshotSeq` → weitere Deltas über
`pull`.
- USB-Fallback (Notbetrieb): Export/Import von `sync_events` und `sync_snapshots` als verschlüsselte Archive (`.msync`).
Offene Spezifikation; separater PoC.
## Sicherheit ## Sicherheit
- Mandantentrennung: Jeder Request trägt `X-Event-Id` (ADR-0021). Backend validiert gegen `control.tenants`. - Mandantentrennung: Jeder Request trägt `X-Event-Id` (ADR-0021). Backend validiert gegen `control.tenants`.
- Transport: `https` + mTLS (bevorzugt) oder `https` + OAuth2 Client Credentials. Payload-Signatur (HMAC-SHA256) empfohlen. - Transport: `https` + mTLS (bevorzugt) oder `https` + OAuth2 Client Credentials. Payload-Signatur (HMAC-SHA256)
empfohlen.
- Integrität: `checksum` pro Event wird serverseitig geprüft; Mismatch → Reject. - Integrität: `checksum` pro Event wird serverseitig geprüft; Mismatch → Reject.
- Rechte: Backend erzwingt Mastership-Regeln serverseitig; Verstöße → `PENDING_REVIEW` + Audit-Log. - Rechte: Backend erzwingt Mastership-Regeln serverseitig; Verstöße → `PENDING_REVIEW` + Audit-Log.
## Fehlerfälle & Resilienz ## Fehlerfälle & Resilienz
- Netzwerkfehler: Exponentielles Backoff (bis 5 min), Offline-Queue unbegrenzt (bounded by disk quota), Telemetrie im UI. - Netzwerkfehler: Exponentielles Backoff (bis 5 min), Offline-Queue unbegrenzt (bounded by disk quota), Telemetrie im
UI.
- Schema-Divergenz: `minSupportedSchema` aus `hello`; Desktop migriert vor weiterem Sync oder schaltet in Read-Only. - Schema-Divergenz: `minSupportedSchema` aus `hello`; Desktop migriert vor weiterem Sync oder schaltet in Read-Only.
- Duplikate: Idempotenz-Keys verhindern Doppelverarbeitung. ACK enthält höchste verarbeitete `sequenceNumber`. - Duplikate: Idempotenz-Keys verhindern Doppelverarbeitung. ACK enthält höchste verarbeitete `sequenceNumber`.
## Observability ## Observability
- Metriken: `sync_push_events_total`, `sync_pull_events_total`, `sync_rejected_total`, `sync_latency_ms` (p50/p95), `offline_duration_s`. - Metriken: `sync_push_events_total`, `sync_pull_events_total`, `sync_rejected_total`, `sync_latency_ms` (p50/p95),
`offline_duration_s`.
- Logs: pro Event `tenant`, `originNodeId`, `seq`, `aggType`, `eventType`, `result`. - Logs: pro Event `tenant`, `originNodeId`, `seq`, `aggType`, `eventType`, `result`.
- UI: Status-Anzeige (Verbunden, Getrennt, Ausstehend X), Konflikt-Review-Queue. - UI: Status-Anzeige (Verbunden, Getrennt, Ausstehend X), Konflikt-Review-Queue.
@@ -5,72 +5,96 @@
> **Kontext:** Phase 9 — Zeitplan & Protokollierung > **Kontext:** Phase 9 — Zeitplan & Protokollierung
## 1. Vision & Zielsetzung ## 1. Vision & Zielsetzung
Die Zeitplan-Optimierung ist das zentrale Werkzeug für die Meldestelle, um den Turnierablauf dynamisch an die Gegebenheiten vor Ort anzupassen. Ziel ist eine intuitive, visuelle Oberfläche (Kalender-Ansicht), in der Bewerbe und Abteilungen per Drag & Drop verschoben werden können, wobei das System automatisch Auswirkungen auf Folge-Bewerbe berechnet und vor Konflikten warnt.
Die Zeitplan-Optimierung ist das zentrale Werkzeug für die Meldestelle, um den Turnierablauf dynamisch an die
Gegebenheiten vor Ort anzupassen. Ziel ist eine intuitive, visuelle Oberfläche (Kalender-Ansicht), in der Bewerbe und
Abteilungen per Drag & Drop verschoben werden können, wobei das System automatisch Auswirkungen auf Folge-Bewerbe
berechnet und vor Konflikten warnt.
## 2. Fachliche Anforderungen (Use Cases) ## 2. Fachliche Anforderungen (Use Cases)
### UC-1: Verschieben eines Bewerbs/einer Abteilung ### UC-1: Verschieben eines Bewerbs/einer Abteilung
- Ein Benutzer zieht einen Bewerb oder eine Abteilung auf eine neue Startzeit oder einen anderen Austragungsplatz. - Ein Benutzer zieht einen Bewerb oder eine Abteilung auf eine neue Startzeit oder einen anderen Austragungsplatz.
- **System-Reaktion:** - **System-Reaktion:**
- Neuberechnung der Endzeit basierend auf `reitdauerMinuten * starterAnzahl + besichtigungMinuten + umbauMinuten`. - Neuberechnung der Endzeit basierend auf `reitdauerMinuten * starterAnzahl + besichtigungMinuten + umbauMinuten`.
- Prüfung auf Überschneidungen am selben Austragungsplatz. - Prüfung auf Überschneidungen am selben Austragungsplatz.
- Warnung bei Konflikten (z.B. Richter-Doppelbelegung). - Warnung bei Konflikten (z.B. Richter-Doppelbelegung).
### UC-2: Dynamische Zeitplan-Anpassung („Anschließend“) ### UC-2: Dynamische Zeitplan-Anpassung („Anschließend“)
- Bewerbe können als `ANSCHLIESSEND` markiert werden (`beginnZeitTyp`). - Bewerbe können als `ANSCHLIESSEND` markiert werden (`beginnZeitTyp`).
- **System-Reaktion:** Wenn der vorangehende Bewerb verschoben wird oder länger dauert, verschiebt sich der anschließende Bewerb automatisch mit. - **System-Reaktion:** Wenn der vorangehende Bewerb verschoben wird oder länger dauert, verschiebt sich der
anschließende Bewerb automatisch mit.
### UC-3: Drag & Drop in der Startliste ### UC-3: Drag & Drop in der Startliste
- Innerhalb einer Startliste können Teilnehmer per Drag & Drop umsortiert werden. - Innerhalb einer Startliste können Teilnehmer per Drag & Drop umsortiert werden.
- **System-Reaktion:** Automatische Aktualisierung der Kopfnummern (Startnummern) und Neuberechnung der individuellen Startzeiten. - **System-Reaktion:** Automatische Aktualisierung der Kopfnummern (Startnummern) und Neuberechnung der individuellen
Startzeiten.
### UC-4: Protokollierung (Audit Log) ### UC-4: Protokollierung (Audit Log)
- Jede manuelle Änderung am Zeitplan oder der Startlisten-Reihenfolge muss protokolliert werden. - Jede manuelle Änderung am Zeitplan oder der Startlisten-Reihenfolge muss protokolliert werden.
- **Grund:** Nachvollziehbarkeit bei Einsprüchen und Synchronisation zwischen verschiedenen Arbeitsplätzen (Meldestelle ↔ Richterturm). - **Grund:** Nachvollziehbarkeit bei Einsprüchen und Synchronisation zwischen verschiedenen Arbeitsplätzen (
Meldestelle ↔ Richterturm).
## 3. Datenmodell-Erweiterungen & Logik ## 3. Datenmodell-Erweiterungen & Logik
### 3.1 Erweiterung `Bewerb` & `Abteilung` ### 3.1 Erweiterung `Bewerb` & `Abteilung`
Das bestehende Modell in `entries-domain` deckt bereits viele Felder ab. Für die Optimierung präzisieren wir: Das bestehende Modell in `entries-domain` deckt bereits viele Felder ab. Für die Optimierung präzisieren wir:
- **`Umbauzeit`:** Zeit zwischen zwei Abteilungen oder Bewerben. - **`Umbauzeit`:** Zeit zwischen zwei Abteilungen oder Bewerben.
- **`Pausen`:** Geplante Unterbrechungen (z.B. Mittagspause, Platzpflege) werden als spezielle „Blocker-Events“ im Zeitplan geführt. - **`Pausen`:** Geplante Unterbrechungen (z.B. Mittagspause, Platzpflege) werden als spezielle „Blocker-Events“ im
Zeitplan geführt.
- **`BesichtigungsBlock` (NEU):** Eigenständiges Objekt für Parcoursbesichtigungen. - **`BesichtigungsBlock` (NEU):** Eigenständiges Objekt für Parcoursbesichtigungen.
- Kann mit mehreren Bewerben/Abteilungen verknüpft werden (Cross-Competition Inspection). - Kann mit mehreren Bewerben/Abteilungen verknüpft werden (Cross-Competition Inspection).
- Unterstützt Typen: `ZU_FUSS` (Standard) und `ZU_PFERD` (Spezialfall für Springpferde bis 110cm gemäß ÖTO). - Unterstützt Typen: `ZU_FUSS` (Standard) und `ZU_PFERD` (Spezialfall für Springpferde bis 110cm gemäß ÖTO).
- Validierung: Mindestens 5 Min. Puffer vor dem ersten Start (ÖTO §43). - Validierung: Mindestens 5 Min. Puffer vor dem ersten Start (ÖTO §43).
### 3.2 Zeitberechnungs-Algorithmus (Präzisierung) ### 3.2 Zeitberechnungs-Algorithmus (Präzisierung)
Die Logik in `StartlistenService.berechneStartzeiten` wird erweitert: Die Logik in `StartlistenService.berechneStartzeiten` wird erweitert:
1. **Basis:** `Startzeit` der Abteilung. 1. **Basis:** `Startzeit` der Abteilung.
2. **Vorlauf:** `besichtigungMinuten`. 2. **Vorlauf:** `besichtigungMinuten`.
3. **Starter-Loop:** 3. **Starter-Loop:**
- `individuelleStartzeit = aktuelleZeit`. - `individuelleStartzeit = aktuelleZeit`.
- `aktuelleZeit += bewerb.reitdauerMinuten`. - `aktuelleZeit += bewerb.reitdauerMinuten`.
- *Neu:* Berücksichtigung von festen Pausen nach X Startern (z.B. 10 Min. Pause alle 20 Starter). - *Neu:* Berücksichtigung von festen Pausen nach X Startern (z.B. 10 Min. Pause alle 20 Starter).
4. **Nachlauf:** `umbauMinuten` am Ende der Abteilung/des Bewerbs. 4. **Nachlauf:** `umbauMinuten` am Ende der Abteilung/des Bewerbs.
### 3.3 Drag & Drop Logik (Frontend & Backend) ### 3.3 Drag & Drop Logik (Frontend & Backend)
- **Frontend (Compose Desktop):** - **Frontend (Compose Desktop):**
- Implementierung eines `DraggableBewerbItem`. - Implementierung eines `DraggableBewerbItem`.
- Visuelle Darstellung von Konflikten (Rote Markierung bei Überlappung). - Visuelle Darstellung von Konflikten (Rote Markierung bei Überlappung).
- **Backend (API):** - **Backend (API):**
- Neuer Endpunkt `PATCH /bewerbe/{id}/zeitplan` für schnelle Updates. - Neuer Endpunkt `PATCH /bewerbe/{id}/zeitplan` für schnelle Updates.
- Validierung der neuen Zeiten gegen den `austragungsplatzId` und `richterEinsaetze`. - Validierung der neuen Zeiten gegen den `austragungsplatzId` und `richterEinsaetze`.
## 4. Konflikt-Management ## 4. Konflikt-Management
Das System arbeitet nach dem Prinzip **„Warnen statt Blockieren“** (ADR-0016): Das System arbeitet nach dem Prinzip **„Warnen statt Blockieren“** (ADR-0016):
- **Harte Fehler:** Nur bei technischer Unmöglichkeit (z.B. Datum in der Vergangenheit bei Live-Betrieb). - **Harte Fehler:** Nur bei technischer Unmöglichkeit (z.B. Datum in der Vergangenheit bei Live-Betrieb).
- **Warnungen:** - **Warnungen:**
- Überlappung auf dem Platz. - Überlappung auf dem Platz.
- Richter hat gleichzeitig Einsatz in anderem Bewerb. - Richter hat gleichzeitig Einsatz in anderem Bewerb.
- Zeitunterschreitung für Reiter (Reiter startet in zwei kurz aufeinanderfolgenden Bewerben). - Zeitunterschreitung für Reiter (Reiter startet in zwei kurz aufeinanderfolgenden Bewerben).
## 5. Synchronisation (Offline-First) ## 5. Synchronisation (Offline-First)
Änderungen am Zeitplan erzeugen `SyncEvents` (gemäß ADR-0022). Änderungen am Zeitplan erzeugen `SyncEvents` (gemäß ADR-0022).
- **Lamport-Uhren:** Stellen sicher, dass bei gleichzeitigen Änderungen an zwei Laptops die zeitlich spätere Änderung (oder die mit höherer Priorität) gewinnt.
- **Echtzeit-Update:** Über WebSockets werden Zeitplan-Änderungen sofort an alle verbundenen Clients (z.B. Anzeige-Monitor, Richter-Tablet) gepusht. - **Lamport-Uhren:** Stellen sicher, dass bei gleichzeitigen Änderungen an zwei Laptops die zeitlich spätere Änderung (
oder die mit höherer Priorität) gewinnt.
- **Echtzeit-Update:** Über WebSockets werden Zeitplan-Änderungen sofort an alle verbundenen Clients (z.B.
Anzeige-Monitor, Richter-Tablet) gepusht.
## 6. Nächste Schritte ## 6. Nächste Schritte
1. **Backend:** ✅ Implementiert (BewerbService, API, Zeitberechnungs-Pausen). 1. **Backend:** ✅ Implementiert (BewerbService, API, Zeitberechnungs-Pausen).
2. **Frontend:** Prototyping der Kalender-Ansicht mit Compose Desktop. 2. **Frontend:** Prototyping der Kalender-Ansicht mit Compose Desktop.
3. **QA:** Test-Szenarien für komplexe Verschiebungen (Kettenreaktionen bei „Anschließend“). 3. **QA:** Test-Szenarien für komplexe Verschiebungen (Kettenreaktionen bei „Anschließend“).
@@ -5,42 +5,63 @@
> **Kontext:** Zeitplan-Optimierung & Praxis-Szenarien > **Kontext:** Zeitplan-Optimierung & Praxis-Szenarien
## 1. Parcoursbesichtigung zu Pferd ## 1. Parcoursbesichtigung zu Pferd
Die Aussage des Users wurde geprüft und bestätigt. Die Aussage des Users wurde geprüft und bestätigt.
### 1.1 Regelwerks-Referenz (ÖTO 2026) ### 1.1 Regelwerks-Referenz (ÖTO 2026)
Gemäß **ÖTO Teil B, § 43 (Abweichungen)** gilt: Gemäß **ÖTO Teil B, § 43 (Abweichungen)** gilt:
- **Normalfall:** Parcoursbesichtigung erfolgt zu Fuß. - **Normalfall:** Parcoursbesichtigung erfolgt zu Fuß.
- **Springpferde- & Jungpferdeprüfungen (bis 110 cm):** Eine Besichtigung **zu Pferd im Schritt** kann von der Richtergruppe erlaubt werden. - **Springpferde- & Jungpferdeprüfungen (bis 110 cm):** Eine Besichtigung **zu Pferd im Schritt** kann von der
- **Zweck:** Junge, unerfahrene Pferde sollen stressfrei an optische Reize (Fangständer, Farben, Unterbauten) herangeführt werden. Richtergruppe erlaubt werden.
- **Zweck:** Junge, unerfahrene Pferde sollen stressfrei an optische Reize (Fangständer, Farben, Unterbauten)
herangeführt werden.
### 1.2 Organisatorische Implikationen ### 1.2 Organisatorische Implikationen
- **Dauer:** Die Besichtigung zu Pferd benötigt oft etwas mehr Zeit für die Koordination am Einlass (15-20 Min. sind praxisnah).
- **Sicherheit:** Da Pferde im Parcours sind, während andere Reiter eventuell noch draußen warten, muss der Zeitplan einen Puffer von mindestens **5 Minuten** zwischen Ende Besichtigung und erstem Start vorsehen (ÖTO Vorschrift). - **Dauer:** Die Besichtigung zu Pferd benötigt oft etwas mehr Zeit für die Koordination am Einlass (15-20 Min. sind
praxisnah).
- **Sicherheit:** Da Pferde im Parcours sind, während andere Reiter eventuell noch draußen warten, muss der Zeitplan
einen Puffer von mindestens **5 Minuten** zwischen Ende Besichtigung und erstem Start vorsehen (ÖTO Vorschrift).
## 2. Zusammengelegte Besichtigungen (Cross-Competition Inspection) ## 2. Zusammengelegte Besichtigungen (Cross-Competition Inspection)
In der Praxis üblich, wenn der Parcours für aufeinanderfolgende Bewerbe identisch bleibt. In der Praxis üblich, wenn der Parcours für aufeinanderfolgende Bewerbe identisch bleibt.
### 2.1 Szenario ### 2.1 Szenario
- **Bewerb A:** Springpferdeprüfung 105cm (Besichtigung zu Pferd erlaubt). - **Bewerb A:** Springpferdeprüfung 105cm (Besichtigung zu Pferd erlaubt).
- **Bewerb B:** Standardspringprüfung 105cm (Besichtigung zu Fuß). - **Bewerb B:** Standardspringprüfung 105cm (Besichtigung zu Fuß).
- **Lösung:** Eine gemeinsame Besichtigungszeit vor Bewerb A. - **Lösung:** Eine gemeinsame Besichtigungszeit vor Bewerb A.
### 2.2 Regelwerks-Konformität ### 2.2 Regelwerks-Konformität
- Es gibt kein Verbot für gemeinsame Besichtigungen, solange die Teilnehmer beider Bewerbe die Möglichkeit haben, den Parcours regelkonform zu besichtigen.
- **Wichtig:** Wenn Bewerb B erst 2 Stunden später startet, muss für Teilnehmer von Bewerb B theoretisch eine zweite Besichtigungsmöglichkeit (oder ein "Refresh") angeboten werden, falls der Parcours zwischenzeitlich verändert wurde. Wenn er identisch bleibt, reicht die einmalige Bekanntgabe. - Es gibt kein Verbot für gemeinsame Besichtigungen, solange die Teilnehmer beider Bewerbe die Möglichkeit haben, den
Parcours regelkonform zu besichtigen.
- **Wichtig:** Wenn Bewerb B erst 2 Stunden später startet, muss für Teilnehmer von Bewerb B theoretisch eine zweite
Besichtigungsmöglichkeit (oder ein "Refresh") angeboten werden, falls der Parcours zwischenzeitlich verändert wurde.
Wenn er identisch bleibt, reicht die einmalige Bekanntgabe.
## 3. Anforderungen für die Software (Zeitplan-Modul) ## 3. Anforderungen für die Software (Zeitplan-Modul)
### 3.1 Datenmodell ### 3.1 Datenmodell
- `Abteilung` oder `Bewerb` benötigt ein Flag `besichtigungZuPferdErlaubt` (Boolean). - `Abteilung` oder `Bewerb` benötigt ein Flag `besichtigungZuPferdErlaubt` (Boolean).
- `BesichtigungsBlock` als eigenständiges Entitätsobjekt im Zeitplan, das mit **mehreren** Bewerben/Abteilungen verknüpft werden kann. - `BesichtigungsBlock` als eigenständiges Entitätsobjekt im Zeitplan, das mit **mehreren** Bewerben/Abteilungen
verknüpft werden kann.
### 3.2 Validierung & Warnungen ### 3.2 Validierung & Warnungen
- **Warnung:** Wenn ein Besichtigungsblock mit "zu Pferd" markiert ist, aber ein verbundener Bewerb (z.B. L-Springen) dies laut ÖTO normalerweise nicht vorsieht (Diskretionsspielraum der Richter).
- **Puffer-Check:** Automatische Prüfung, ob zwischen `Ende Besichtigung` und `Start Erster Reiter` mindestens 5 Minuten liegen. - **Warnung:** Wenn ein Besichtigungsblock mit "zu Pferd" markiert ist, aber ein verbundener Bewerb (z.B. L-Springen)
dies laut ÖTO normalerweise nicht vorsieht (Diskretionsspielraum der Richter).
- **Puffer-Check:** Automatische Prüfung, ob zwischen `Ende Besichtigung` und `Start Erster Reiter` mindestens 5 Minuten
liegen.
## 4. Fazit für Architect & Entwickler ## 4. Fazit für Architect & Entwickler
Die "Besichtigung zu Pferd" ist ein valider Spezialfall für Springpferdeprüfungen. Die Software muss erlauben, Besichtigungszeiten flexibel vor einen oder mehrere Bewerbe zu lagern und den Typ (Fuß/Pferd) zu kennzeichnen.
Die "Besichtigung zu Pferd" ist ein valider Spezialfall für Springpferdeprüfungen. Die Software muss erlauben,
Besichtigungszeiten flexibel vor einen oder mehrere Bewerbe zu lagern und den Typ (Fuß/Pferd) zu kennzeichnen.
--- ---
*Geprüft durch den 📜 ÖTO/FEI Rulebook Expert am 11.04.2026* *Geprüft durch den 📜 ÖTO/FEI Rulebook Expert am 11.04.2026*
@@ -0,0 +1,62 @@
# 🤖 Konzept: Status-Automat für Nennungen & Zeitplan-Synchronisation
Dieses Dokument spezifiziert die Logik des Status-Automaten für Nennungen (Sprint C-1) und dessen Auswirkungen auf den
dynamischen Zeitplan.
## 1. Status-Definitionen (NennStatusE)
Basierend auf `core-domain/Enums.kt`:
| Status | Bedeutung | Auswirkung auf Zeitplan |
|:-------------------|:--------------------------------------------------|:--------------------------------------------------------|
| `EINGEGANGEN` | Nennung wurde erstellt (Initialzustand) | Belegt Zeitslot (basierend auf `reitdauerMinuten`) |
| `BESTAETIGT` | Meldestelle hat Nennung geprüft | Belegt Zeitslot |
| `NACHNENNUNG` | Nennung nach Nennschluss | Belegt Zeitslot (ggf. am Ende der Liste) |
| `TRANSFERIERT` | Nennung wurde auf anderes Paar übertragen | **Inaktiv** (Original-Eintrag wird durch neuen ersetzt) |
| `ZURUECKGEZOGEN` | Reiter hat abgemeldet (vor Startlistenerstellung) | **Inaktiv** (Slot wird frei) |
| `GESTARTET` | Paar ist in die Prüfung eingeritten | Startzeitpunkt fixiert, Folgestarts ggf. anpassen |
| `NICHT_ANGETRETEN` | Paar ist zum Startzeitpunkt nicht erschienen | **Zeitslot verfällt** oder Folgestarts rücken nach |
## 2. Status-Übergänge & Validierung
### 2.1 Gültige Übergänge (Beispiele)
- `EINGEGANGEN` -> `BESTAETIGT` (Normalfall)
- `EINGEGANGEN` -> `ZURUECKGEZOGEN` (Abmeldung)
- `BESTAETIGT` -> `TRANSFERIERT` (Reitertausch)
- `BESTAETIGT` -> `GESTARTET` (Während des Turniers)
### 2.2 Side-Effects (Side-Effect-Engine)
Wenn sich der Status einer Nennung ändert, müssen folgende Systeme informiert werden:
1. **Billing-Service:** Bei `ZURUECKGEZOGEN` ggf. Stornogebühren prüfen. Bei `TRANSFERIERT` Guthaben übertragen.
2. **Startlisten-Service:** Bei `ZURUECKGEZOGEN` nach Veröffentlichung der Startliste -> Eintrag als
`istGestrichen = true` markieren.
3. **Zeitplan-Optimierung:** Bei `NICHT_ANGETRETEN` -> Alle folgenden Startzeiten rücken um `reitdauerMinuten` nach
vorne (sofern im Kalender-Modus "Dynamisch" aktiv ist).
## 3. Dynamische Zeitplan-Anpassung (C-1 Extension)
Der `StartlistenService` muss eine Methode `aktualisiereZeitplanNachStatusAenderung` erhalten:
- **Szenario A (Nicht angetreten):** Wenn Nennung X `NICHT_ANGETRETEN` wird, rücken alle folgenden Nennungen in der
Abteilung nach vorne.
- **Szenario B (Verspätung):** Wenn Nennung X `GESTARTET` wird, aber 2 Minuten später als geplant, verschieben sich alle
Folgetermine um +2 Minuten (Kettenreaktion).
### Puffer-Regel (ÖTO-Konformität)
- Eine dynamische Verschiebung nach *vorne* darf nie dazu führen, dass ein Reiter vor seiner ursprünglich kommunizierten
Startzeit (oder einem definierten Puffer-Zeitraum von z.B. 15 Minuten) starten muss, ohne dass dies explizit bestätigt
wurde.
## 4. Implementierungs-Leitfaden für Backend (C-1)
1. Erweiterung von `NennungUseCases.statusAendern` um Aufrufe der Side-Effect-Handler.
2. Implementierung des `NennungStatusListener` in `entries-service`.
3. Anbindung an den `StartlistenService` zur Zeitre-Kalkulation.
---
**Status:** Entwurf (Lead Architect)
**Datum:** 11. April 2026
+33 -30
View File
@@ -2,12 +2,12 @@
type: Roadmap type: Roadmap
status: ACTIVE status: ACTIVE
owner: Lead Architect owner: Lead Architect
last_update: 2026-04-30 last_update: 2026-06-15
--- ---
# MASTER ROADMAP: Meldestelle # MASTER ROADMAP: Meldestelle
🏗️ **[Lead Architect]** | 30. April 2026 🏗️ **[Lead Architect]** | 15. Juni 2026
**Strategisches Ziel:** **Strategisches Ziel:**
Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP). Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP).
@@ -17,16 +17,16 @@ Vollständige Self-Hosted Infrastruktur (Gitea, Pangolin, Zora). Datensouveräni
- Desktop-App ist der primäre Client (Compose Desktop, KMP) — „Desktop-First“ gilt für UX und Architektur. - Desktop-App ist der primäre Client (Compose Desktop, KMP) — „Desktop-First“ gilt für UX und Architektur.
- Offline-First Betrieb mit lokaler Persistenz und opportunistischer Synchronisation. - Offline-First Betrieb mit lokaler Persistenz und opportunistischer Synchronisation.
**Aktueller technischer Stand (30.04.2026):** **Aktueller technischer Stand (15.06.2026):**
* **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen. * **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen.
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare. * **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
* **CI/CD:** ✅ Gitea Actions mit ARM64-Runner (VM 102) aktiv. Docker-Publish Pipeline grün. * **CI/CD:** ✅ Gitea Actions mit ARM64-Runner (VM 102) aktiv. Docker-Publish Pipeline grün.
* **Code-Basis:** ✅ Backend (Java 25 / Spring Boot / Kotlin), Frontend (KMP/Compose Desktop). * **Code-Basis:** ✅ Backend (Java 25 / Spring Boot / Kotlin), Frontend (KMP/Compose Desktop).
* **Domain-Design:** ✅ 6 Bounded Contexts (SCS-Architektur) definiert. Ubiquitous Language erstellt. * **Domain-Design:** ✅ 6 Bounded Contexts (SCS-Architektur) definiert. Ubiquitous Language erstellt.
* **Domain-Modelle:**`Reiter`, `DomNennung`, `DomNennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`, * **Domain-Modelle:**`Reiter`, `Nennung`, `NennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`,
`DomBewerb`, `DomAbteilung`, `DomStartliste`, `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementiert. `Bewerb`, `Abteilung`, `DomStartliste`, `Veranstaltung`, `Turnier`, `Ausschreibung` implementiert.
Enums ÖTO-konform. Enums ÖTO-konform.
* **Dokumentation:** ✅ Konsolidiert. ÖTO-Regelwerk-Referenzen (Abteilungs-Schwellenwerte) dokumentiert. * **Dokumentation:** 🧹 Sanierung abgeschlossen (5-Säulen-Struktur). Reality-Reset durchgeführt.
--- ---
@@ -87,7 +87,10 @@ Fokus: Physische Implementierung der Turnier-Hierarchie und technisches Onboardi
* [x] **Handshake-Feedback:** Visuelle Signalisierung des Verbindungsstatus (Grün/Rot). * [x] **Handshake-Feedback:** Visuelle Signalisierung des Verbindungsstatus (Grün/Rot).
* [x] **Client-Konfiguration:** Master kann nun Clients in der UI hinzufügen und bearbeiten. * [x] **Client-Konfiguration:** Master kann nun Clients in der UI hinzufügen und bearbeiten.
* [x] **Master-UX:** Konfiguration beim Start nicht mehr zwangsgesperrt. * [x] **Master-UX:** Konfiguration beim Start nicht mehr zwangsgesperrt.
* [ ] **PoC Verifikation:** 🔴 **FEHLGESCHLAGEN** (Hardware-Test durch User nicht erfolgreich - Analyse für Abend-Session erforderlich). * [x] **Cross-Packaging (Conveyor):** Windows-Build auf Linux-CI ermöglicht (x64-Abhängigkeit identifiziert).
* [x] **Build-Performance:** WASM standardmäßig deaktiviert, um Desktop-Build-Zeiten zu reduzieren (11.05.2026).
* [ ] **PoC Verifikation:** 🔴 **BLOCKIERT** (Log 483: ARM64-Runner inkompatibel mit Conveyor-Binary; Workflow auf
manuell gesetzt).
### MEILENSTEIN 1: Die Basis-Hierarchie (Prio 1) ⚪ GEPLANT ### MEILENSTEIN 1: Die Basis-Hierarchie (Prio 1) ⚪ GEPLANT
@@ -150,26 +153,26 @@ Code-Stand.*
## 5. Wichtige Referenzen ## 5. Wichtige Referenzen
| Dokument | Pfad | | Dokument | Pfad |
|---------------------------|----------------------------------------------------------------------------------------------| |-------------------------------|----------------------------------------------------------------------------------------------|
| Ubiquitous Language | `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` | | Ubiquitous Language | `docs/02_Domain/01_Glossary/Ubiquitous_Language.md` |
| Abteilungs-Schwellenwerte | `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` | | Abteilungs-Schwellenwerte | `docs/02_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
| Warn-Logik-Spezifikation | `docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` | | Warn-Logik-Spezifikation | `docs/02_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` |
| Session Log (DDD) | `docs/99_Journal/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` | | Session Log (DDD) | `docs/05_Governance/Journal/_archive/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
| Infrastruktur | `docs/07_Infrastructure/Zora_System_Architektur.md` | | Infrastruktur | `docs/04_Operations/Infrastructure/Zora_System_Architektur.md` |
| Deployment Guide | `docs/07_Infrastructure/Guides/Setup_Git_Deployment_Zora.md` | | Deployment Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
| Backup Guide | `docs/07_Infrastructure/Guides/Setup_Backup_Zora.md` | | Backup Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Backup_Zora.md` |
| CI/CD | `.gitea/workflows/docker-publish.yaml` | | CI/CD | `.gitea/workflows/docker-publish.yaml` |
| Agent Playbooks | `docs/04_Agents/Playbooks/` | | Agent Playbooks | `docs/05_Governance/Agents/Playbooks/` |
| ADR-Verzeichnis | `docs/01_Architecture/adr/` | | ADR-Verzeichnis | `docs/01_Architecture/adr/` |
| ADR-0025: Plan-USB | `docs/01_Architecture/adr/0025-plan-usb-offline-integritaet.md` | | ADR-0025: Plan-USB | `docs/01_Architecture/adr/0025-plan-usb-offline-integritaet.md` |
| ADR-0026: Lizenzierung | `docs/01_Architecture/adr/0026-offline-lizenzierung-pay-per-event.md` | | ADR-0026: Lizenzierung | `docs/01_Architecture/adr/0026-offline-lizenzierung-pay-per-event.md` |
| ADR-0027: Discovery | `docs/01_Architecture/adr/0027-netzwerk-discovery-interface-binding.md` | | ADR-0027: Discovery | `docs/01_Architecture/adr/0027-netzwerk-discovery-interface-binding.md` |
| Docker-Fix: dc-gui.yaml | `dc-gui.yaml` | | Docker-Fix: dc-gui.yaml | `dc-gui.yaml` |
| ZNS-Importer Roadmap | `docs/01_Architecture/Roadmap_ZNS_Importer.md` | | ZNS-Importer Roadmap | `docs/01_Architecture/Roadmaps/Roadmap_ZNS_Importer.md` |
| Masterdata Roadmap | `backend/services/masterdata/docs/ROADMAP.md` | | Masterdata Roadmap | `backend/services/masterdata/docs/ROADMAP.md` |
| Masterdata Changelog | `backend/services/masterdata/docs/CHANGELOG.md` | | Masterdata Changelog | `backend/services/masterdata/docs/CHANGELOG.md` |
| Masterdata Operations | `backend/services/masterdata/docs/runbooks/masterdata-ops.md` | | Masterdata Operations | `backend/services/masterdata/docs/runbooks/masterdata-ops.md` |
| Zeitplan-Optimierung | `docs/01_Architecture/konzept-zeitplan-optimierung-de.md` | | Zeitplan-Optimierung | `docs/01_Architecture/Concepts/konzept-zeitplan-optimierung-de.md` |
| Parcoursbesichtigung-Rulebook | `docs/01_Architecture/rulebook-check-parcoursbesichtigung-de.md` | | Parcoursbesichtigung-Rulebook | `docs/01_Architecture/Concepts/rulebook-check-parcoursbesichtigung-de.md` |
| Status-Automat-Nennungen | `docs/01_Architecture/status-automat-nennungen-de.md` | | Status-Automat-Nennungen | `docs/01_Architecture/Concepts/status-automat-nennungen-de.md` |
@@ -1,358 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
---
# Meldestelle — Tech-Stack Zusammenfassung
> **Zweck:** Vollständige Referenz des eingesetzten Tech-Stacks im Projekt "Meldestelle".
> Dient als Basis für Recherchen zu Self-Hosted AI (Codegenerierung, RAG, Agenten).
> **Stand:** 07. März 2026
---
## 1. Überblick
Das Projekt "Meldestelle" ist eine **Kotlin-first, Cloud-native Microservices-Plattform** für die Verwaltung von Reitsport-Meldungen (FEI / ÖTO). Es kombiniert ein **Kotlin Multiplatform (KMP) Frontend** mit einem **Spring Boot Microservices Backend** auf einer vollständig self-hosted Infrastruktur.
```
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (KMP) │ Backend (Spring Boot / Kotlin JVM) │
│ Kotlin 2.3 / Compose │ Java 25 / Spring Boot 3.5.9 │
│ JS + WASM (geplant) │ Microservices + API-Gateway │
├─────────────────────────────────────────────────────────────────┤
│ Infrastruktur (Self-Hosted auf Zora / Proxmox) │
│ Keycloak · Consul · Valkey · PostgreSQL · Zipkin │
│ Prometheus · Grafana · Caddy · Pangolin-Tunnel │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. Sprachen & Laufzeiten
| Komponente | Sprache / Runtime | Version |
|:------------------|:-------------------------|:------------|
| Backend | Kotlin (JVM) | 2.3.0 |
| Frontend | Kotlin (KMP / JS) | 2.3.0 |
| JVM | Java (Eclipse Temurin) | 25 (EA) |
| Build | Gradle (Kotlin DSL) | 9.3.1 |
| Plattform | ARM64 (AArch64) | Linux |
---
## 3. Frontend — Kotlin Multiplatform (KMP)
### 3.1 Core-Framework
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Kotlin Multiplatform | 2.3.0 | Cross-Platform-Basis (JS + WASM) |
| Compose Multiplatform | 1.10.0 | UI-Framework (Deklarativ) |
| Compose Hot Reload | 1.0.0 | Live-Reload im Dev-Modus |
| Koin (DI) | 4.1.1 | Dependency Injection |
| Koin Compose | 4.1.1 | DI-Integration für Compose |
| Ktor Client | 3.4.0 | HTTP-Client (Multiplatform) |
| Kotlin Serialization | 2.3.0 | JSON-Serialisierung |
### 3.2 Persistenz (Offline-First)
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| SQLDelight | 2.2.1 | Cross-Platform SQL-Datenbank |
| SQLite (WASM) | 3.51.1 | SQLite für Browser/WASM |
| SQLite (Native) | 2.6.2 | SQLite für JVM/Desktop |
### 3.3 Build-Targets
| Target | Status | Anmerkung |
|:--------------|:------------|:-----------------------------------|
| KotlinJS | ✅ Aktiv | Primäres Build-Target |
| WASM | ⏳ Geplant | Warten auf Alpha-Version |
| Desktop (JVM) | ⚙️ Möglich | uiDesktop 1.7.0 vorhanden |
### 3.4 Modul-Struktur
```
frontend/
├── core/
│ ├── core-network/ # Ktor HTTP-Client, Auth-Interceptor
│ ├── core-ui/ # Design-System, Tokens, Komponenten
│ ├── core-domain/ # Shared Domain-Models
│ └── core-data/ # Repository-Interfaces
├── features/
│ ├── ping-feature/ # ✅ Blueprint: MVVM + Repository + DI + Tests
│ └── members-feature/ # ⏳ Auskommentiert (nächste Phase)
└── shells/
└── meldestelle-portal/ # Web-App Shell (Caddy-served)
```
---
## 4. Backend — Spring Boot Microservices
### 4.1 Core-Framework
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Spring Boot | 3.5.9 | Microservices-Framework |
| Spring Cloud | 2025.0.1 | Service Discovery, Config |
| Spring Security (OAuth2) | (Boot) | JWT-Validierung, Resource Server |
| Spring Data JPA | (Boot) | ORM-Layer |
| Spring Data Valkey | 0.2.0 | Cache-Integration (Valkey/Redis) |
| Spring WebFlux | (Boot) | Reaktive API (Gateway) |
| Kotlin Coroutines | 2.3.0 | Async/Non-blocking |
### 4.2 Persistenz
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| PostgreSQL Driver | 42.7.8 | JDBC-Treiber |
| Exposed (JetBrains) | 1.0.0 | Kotlin-native SQL DSL |
| Flyway | 11.19.1 | Datenbank-Migrationen |
| HikariCP | 7.0.2 | Connection Pool |
> **Strategie (ADR-001):** Hybrid — JPA für einfache CRUD-Entities, Exposed für komplexe Queries und Domain-Logik.
### 4.3 Caching & Messaging
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Lettuce | 6.6.0 | Valkey/Redis-Client (reaktiv) |
| Redisson | 4.0.0 | Distributed Locks, Pub/Sub |
| Caffeine | 3.2.3 | In-Memory Cache (L1) |
| Reactor Kafka | 1.3.23 | Kafka-Client (Phase 3 / Outbox) |
### 4.4 Observability & Tracing
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Micrometer | 1.16.1 | Metriken (Prometheus-Export) |
| Micrometer Tracing | 1.6.1 | Distributed Tracing |
| Zipkin Reporter | 3.5.1 | Trace-Export zu Zipkin |
| Logback | 1.5.25 | Logging |
### 4.5 Security
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Keycloak Admin Client | 26.0.7 | Keycloak-API-Integration |
| Spring Security OAuth2 | (Boot) | JWT Resource Server |
| Jackson (Kotlin) | 3.0.3 | JSON-Serialisierung |
### 4.6 API & Dokumentation
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Springdoc OpenAPI | 3.0.0 | Swagger / OpenAPI 3.1 |
| Jakarta Annotation | 3.0.0 | Jakarta EE Annotations |
### 4.7 Modul-Struktur
```
backend/
├── infrastructure/
│ ├── gateway/ # ✅ API-Gateway (Spring Cloud Gateway)
│ ├── security/ # ✅ Zentrales OAuth2/JWT-Modul (DRY)
│ ├── cache/
│ │ ├── cache-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── event-store/
│ │ ├── event-store-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── persistence/ # Hybrid JPA + Exposed
│ └── messaging/ # Kafka (Phase 3 / Outbox-Pattern)
└── services/
├── ping/ # ✅ Deployed — Test/Blueprint-Service
├── entries/ # ⚙️ Registriert, noch nicht deployed
├── events/ # 👻 Ghost Service (nicht registriert)
├── horses/ # 👻 Ghost Service (nicht registriert)
├── masterdata/ # 👻 Ghost Service (nicht registriert)
├── registry/ # 👻 Ghost Service (nicht registriert)
├── results/ # 👻 Ghost Service (nicht registriert)
└── scheduling/ # 👻 Ghost Service (nicht registriert)
```
---
## 5. Infrastruktur-Services (Docker)
### 5.1 Laufende Services
| Service | Image / Version | Port(s) | Zweck |
|:---------------|:--------------------------|:--------------|:-----------------------------|
| PostgreSQL | postgres:16-alpine | 5432 | Primäre Datenbank |
| Keycloak | keycloak:26.4 (custom) | 8180, 9000 | IAM / OAuth2 / OIDC |
| Valkey | valkey:8-alpine | 6379 | Cache + Event-Store |
| Consul | consul:1.21 | 8500, 8600 | Service Discovery + Config |
| Zipkin | openzipkin/zipkin:3.5 | 9411 | Distributed Tracing |
| Prometheus | prom/prometheus:v3.4 | 9090 | Metriken-Sammlung |
| Grafana | grafana/grafana:11.6 | 3000 | Dashboards / Visualisierung |
| Caddy | caddy:2.10-alpine | 4000 | Web-App Serving (Frontend) |
| API-Gateway | (custom Spring Boot) | 8081 | Zentraler Eintrittspunkt |
| Ping-Service | (custom Spring Boot) | 8082 | Test/Blueprint-Service |
### 5.2 CI/CD & DevOps
| Tool | Version / Details | Zweck |
|:----------------|:--------------------------|:-----------------------------|
| Gitea | Self-Hosted (CT 101) | Git-Repository + Registry |
| Gitea Actions | (Runner VM 102) | CI/CD-Pipeline |
| Docker Buildx | ARM64 (linux/arm64) | Multi-Arch Image Build |
| Pangolin | Self-Hosted Tunnel | Reverse Proxy / Extern-Zugang|
### 5.3 Netzwerk & Routing
| Subdomain | Intern (Zora) | Zweck |
|:-----------------------|:--------------------|:-------------------------|
| `git.mo-code.at` | `10.0.0.22:3000` | Gitea |
| `api.mo-code.at` | `10.0.0.50:8081` | API-Gateway |
| `auth.mo-code.at` | `10.0.0.50:8180` | Keycloak |
| `app.mo-code.at` | `10.0.0.50:4000` | Web-App |
| `photos.mo-code.at` | `10.0.0.24:2283` | Immich (Fotos) |
---
## 6. Code-Qualität & Build-Tools
| Tool | Version | Zweck |
|:------------------|:----------|:-----------------------------------|
| Detekt | 1.23.6 | Kotlin Static Analysis |
| ktlint | 12.1.1 | Kotlin Code Formatter |
| ArchUnit | 1.4.1 | Architektur-Tests (Layer-Regeln) |
| Dokka | 2.1.0 | API-Dokumentation (KDoc) |
| Ben-Manes Versions| 0.51.0 | Dependency-Update-Check |
| KSP | 2.3.4 | Kotlin Symbol Processing |
### Build-Konfiguration
```properties
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.workers.max=8
org.gradle.configuration-cache=false # wegen JS-Test Serialisierungsproblem
org.gradle.dependency.verification=strict
```
---
## 7. Test-Stack
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| JUnit Jupiter | 5.11.3 | Unit-Tests |
| JUnit Platform | 1.11.3 | Test-Runner |
| MockK | 1.14.7 | Kotlin Mocking |
| AssertJ | 3.27.7 | Fluent Assertions |
| Testcontainers | 2.0.3 | Integration-Tests (Docker) |
| Testcontainers Keycloak | 4.0.1 | Keycloak-Integration-Tests |
| Testcontainers PostgreSQL | 1.21.4 | DB-Integration-Tests |
| Testcontainers Kafka | 1.21.4 | Kafka-Integration-Tests |
| ArchUnit | 1.4.1 | Architektur-Compliance-Tests |
---
## 8. Architektur-Prinzipien (ADRs)
| ADR | Entscheidung | Status |
|:------|:--------------------------------------------------|:---------|
| 0001 | Modulare Architektur (DDD, Clean Architecture) | ✅ Aktiv |
| 0003 | Microservices-Architektur | ✅ Aktiv |
| 0004 | Event-Driven Communication (Kafka Phase 3) | ✅ Aktiv |
| 001 | Backend-Infrastruktur: Hybrid JPA+Exposed, Valkey | ✅ Aktiv |
| 0013 | Tech-Stack-Stabilisierung 2026 (Versionen) | ✅ Aktiv |
**Kern-Prinzipien:**
- **Offline-First:** SQLDelight als Cross-Platform-DB, Sync-Mechanismus
- **Docs-as-Code:** `/docs` als Single Source of Truth
- **DRY-Infrastruktur:** Shared Security/Cache/EventStore-Module
- **ARM64-Native:** Alle Images für `linux/arm64` gebaut
---
## 9. Relevanz für Self-Hosted AI
### 9.1 Welche AI-Aufgaben entstehen im Projekt?
| Aufgabe | Häufigkeit | Komplexität |
|:---------------------------------|:-----------|:------------|
| Kotlin/Spring Boot Code-Completion| Täglich | Mittel |
| Compose Multiplatform UI-Code | Täglich | Mittel |
| SQL / Exposed DSL Queries | Häufig | Mittel |
| Gradle Kotlin DSL Build-Skripte | Gelegentlich| Niedrig |
| Docker / YAML Konfigurationen | Gelegentlich| Niedrig |
| Architektur-Entscheidungen (ADR) | Selten | Hoch |
| Fachlogik FEI/ÖTO Regelwerk | Selten | Sehr hoch |
### 9.2 Anforderungen an das AI-Modell
```
MUSS:
✅ Kotlin (JVM + Multiplatform) — sehr gute Unterstützung
✅ Spring Boot / Spring Cloud — sehr gute Unterstützung
✅ Compose Multiplatform — gute Unterstützung (neuere Modelle)
✅ SQL / PostgreSQL — sehr gute Unterstützung
✅ Docker / YAML — sehr gute Unterstützung
✅ Deutsch (Fachsprache Reitsport) — für RAG-Dokumente
NICE-TO-HAVE:
⭐ Gradle Kotlin DSL
⭐ Keycloak / OAuth2 / OIDC
⭐ Microservices-Architektur-Patterns
```
### 9.3 Empfohlene Modelle für diesen Stack
| Modell | Größe | Stärke | RAM-Bedarf |
|:------------------------|:-------|:------------------------------------|:-----------|
| `qwen2.5-coder:14b` | 14B | Code (Kotlin, Java, SQL) — Top | ~10 GB |
| `deepseek-coder-v2:16b` | 16B | Code-Completion, Refactoring | ~12 GB |
| `llama3.1:8b` | 8B | Allgemein + Deutsch, schnell | ~6 GB |
| `qwen2.5:32b` | 32B | Architektur, Planung, Fachlogik | ~22 GB |
| `codellama:13b` | 13B | Code-Completion (IntelliJ-Plugin) | ~9 GB |
> **Empfehlung für Zora (64 GB RAM):**
> - **Primär:** `qwen2.5-coder:14b` — bester Kotlin/Spring-Support
> - **Sekundär:** `qwen2.5:32b` — für Architektur und Fachlogik
> - **IntelliJ-Integration:** `codellama:13b` oder `qwen2.5-coder:14b`
### 9.4 RAG-Dokumente (Priorität)
Folgende Projekt-Dokumente sind besonders wertvoll als RAG-Kontext:
```
Hohe Priorität:
├── docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md
├── docs/01_Architecture/adr/ (alle ADRs)
├── docs/04_Agents/Playbooks/ (Agenten-Rollen)
├── gradle/libs.versions.toml (Versions-SSoT)
└── docs/07_Infrastructure/ (Infrastruktur-Referenz)
Mittlere Priorität:
├── docs/05_Backend/ (Backend-Guides)
├── docs/06_Frontend/ (Frontend-Guides)
└── docs/03_Domain/ (Fachlogik-Konzepte)
```
---
## 10. Zusammenfassung
```
TECH-STACK KOMPLEXITÄT
──────────────────────────────────────────────────────
Sprachen: Kotlin (JVM + KMP/JS)
Build: Gradle 9.3.1 + Kotlin DSL + libs.versions.toml
Frontend: Compose Multiplatform 1.10 + SQLDelight 2.2 + Koin 4.1
Backend: Spring Boot 3.5.9 + Spring Cloud 2025.0.1
Persistenz: PostgreSQL 16 + Exposed 1.0 + Flyway 11 + HikariCP 7
Cache: Valkey 8 + Lettuce 6.6 + Caffeine 3.2
Security: Keycloak 26.4 + Spring Security OAuth2 + JWT
Observability: Micrometer 1.16 + Zipkin 3.5 + Prometheus + Grafana 11.6
Service Mesh: Consul 1.21 + Spring Cloud Gateway
Messaging: Kafka (Phase 3) + Reactor Kafka 1.3
CI/CD: Gitea Actions + Docker Buildx (ARM64)
Hosting: Proxmox VE 8.4 + Docker Compose + Pangolin-Tunnel
```
@@ -5,23 +5,23 @@ owner: Lead Architect
date: 2026-02-02 date: 2026-02-02
--- ---
# Engineering Moderner Frontend-Architekturen: Kotlin 2.3.0, Compose Multiplatform 1.10.0 und Gradle 9.0 für Modulare Monolithen # Engineering Moderner Frontend-Architekturen: Kotlin 2.3.21, Compose Multiplatform 1.10.0 und Gradle 9.5.0 für Modulare Monolithen
Der architektonische Übergang zu modularen Monolithen bietet Unternehmen die Möglichkeit, die Komplexität von Der architektonische Übergang zu modularen Monolithen bietet Unternehmen die Möglichkeit, die Komplexität von
Microservices zu reduzieren und gleichzeitig eine klare Trennung der Domänenlogik beizubehalten. In Kombination mit Microservices zu reduzieren und gleichzeitig eine klare Trennung der Domänenlogik beizubehalten. In Kombination mit
Kotlin Multiplatform (KMP) für Single Page Applications (SPAs) lässt sich Geschäftslogik effizient über den gesamten Kotlin Multiplatform (KMP) für Single Page Applications (SPAs) lässt sich Geschäftslogik effizient über den gesamten
Stack teilen. Die Einführung von Kotlin 2.3.0, Compose Multiplatform 1.10.0 und Gradle 9.0 stellt dabei neue Best Stack teilen. Die Einführung von Kotlin 2.3.21, Compose Multiplatform 1.10.0 und Gradle 9.5.0 stellt dabei neue Best
Practices für Build-Performance und Deployment auf. Practices für Build-Performance und Deployment auf.
## 1. Gradle 9.x Optimierung in der CI/CD ## 1. Gradle 9.x Optimierung in der CI/CD
Gradle 9.0 führt signifikante Änderungen ein, die speziell für große Multi-Modul-Projekte wie modulare Monolithen Gradle 9.5.0 führt signifikante Änderungen ein, die speziell für große Multi-Modul-Projekte wie modulare Monolithen
optimiert sind. optimiert sind.
- **Configuration Cache als Standard:** In Gradle 9.0 ist der Configuration Cache der bevorzugte Ausführungsmodus. Durch - **Configuration Cache als Standard:** In Gradle 9.5.0 ist der Configuration Cache der bevorzugte Ausführungsmodus. Durch
das Caching des Task-Graphen werden nachfolgende Builds erheblich beschleunigt, da die Konfigurationsphase das Caching des Task-Graphen werden nachfolgende Builds erheblich beschleunigt, da die Konfigurationsphase
übersprungen wird. übersprungen wird.
- **Kotlin DSL Script Compilation Avoidance:** Durch den Einsatz von ABI-Fingerprinting erkennt Gradle 9.0, ob - **Kotlin DSL Script Compilation Avoidance:** Durch den Einsatz von ABI-Fingerprinting erkennt Gradle 9.5.0, ob
Änderungen an `.kts`-Dateien die Build-Logik tatsächlich beeinflussen. Nicht-relevante Änderungen (wie Kommentare) Änderungen an `.kts`-Dateien die Build-Logik tatsächlich beeinflussen. Nicht-relevante Änderungen (wie Kommentare)
führen nicht mehr zur Neukompilierung, was die Konfigurationszeit um bis zu 60 % reduzieren kann. führen nicht mehr zur Neukompilierung, was die Konfigurationszeit um bis zu 60 % reduzieren kann.
- **Parallel Configuration Store and Load:** Gradle 8.11 und 9.0 unterstützen das parallele Laden und Speichern von - **Parallel Configuration Store and Load:** Gradle 8.11 und 9.0 unterstützen das parallele Laden und Speichern von
@@ -74,14 +74,14 @@ Die Wahl des Webservers beeinflusst das Routing und die Performance der Compose
| Komponente | Empfehlung | Vorteil | | Komponente | Empfehlung | Vorteil |
|---------------|-------------------------------------|--------------------------------------------------------| |---------------|-------------------------------------|--------------------------------------------------------|
| Build-Tool | Gradle 9.0 mit Configuration Cache | Extreme Verkürzung der Konfigurationsphase | | Build-Tool | Gradle 9.5.0 mit Configuration Cache | Extreme Verkürzung der Konfigurationsphase |
| CI Caching | Remote Cache Action (Proxy) | Wiederverwendung von Task-Outputs auf frischen Runnern | | CI Caching | Remote Cache Action (Proxy) | Wiederverwendung von Task-Outputs auf frischen Runnern |
| Konfiguration | Runtime config.json Fetch | Ein Docker-Image für alle Umgebungen (Dev/Prod) | | Konfiguration | Runtime config.json Fetch | Ein Docker-Image für alle Umgebungen (Dev/Prod) |
| Webserver | Caddy oder Nginx | Optimiertes SPA-Routing und Web Cache Support | | Webserver | Caddy oder Nginx | Optimiertes SPA-Routing und Web Cache Support |
## Fazit ## Fazit
Die Kombination aus Gradle 9.0 und Kotlin 2.3.0 ermöglicht hocheffiziente Build-Pipelines für modulare Monolithen. Durch Die Kombination aus Gradle 9.5.0 und Kotlin 2.3.21 ermöglicht hocheffiziente Build-Pipelines für modulare Monolithen. Durch
den Einsatz von Multi-Stage Docker-Builds und dem `config.json`-Fetch-Muster wird eine moderne, skalierbare den Einsatz von Multi-Stage Docker-Builds und dem `config.json`-Fetch-Muster wird eine moderne, skalierbare
Deployment-Strategie umgesetzt, die die neuen Performance-Features von Compose Multiplatform 1.10.0 optimal nutzt. Deployment-Strategie umgesetzt, die die neuen Performance-Features von Compose Multiplatform 1.10.0 optimal nutzt.
@@ -9,7 +9,7 @@ Hier ist der Quellcode des Berichts im Markdown-Format:
## Zusammenfassung ## Zusammenfassung
Die Softwareentwicklungslandschaft des Jahres 2026, geprägt durch die Veröffentlichung von Kotlin 2.3.0 und Gradle 9.1.0, bietet Entwicklern beispiellose Möglichkeiten zur Vereinheitlichung komplexer Geschäftslogik über Plattformgrenzen hinweg. Dieser Forschungsbericht analysiert detailliert die architektonischen Muster, Implementierungsstrategien und zugrundeliegenden Mechanismen, die für den Aufbau einer robusten, asynchronen Offline-First-Anwendung erforderlich sind. Der Fokus liegt hierbei auf der Integration von SQLDelight in einer Kotlin Multiplatform (KMP) Umgebung, die sowohl Desktop (JVM) als auch Web (Kotlin/JS) Ziele bedient, eingebettet in eine Mikro-Frontend-Architektur. Die Softwareentwicklungslandschaft des Jahres 2026, geprägt durch die Veröffentlichung von Kotlin 2.3.21 und Gradle 9.5.0, bietet Entwicklern beispiellose Möglichkeiten zur Vereinheitlichung komplexer Geschäftslogik über Plattformgrenzen hinweg. Dieser Forschungsbericht analysiert detailliert die architektonischen Muster, Implementierungsstrategien und zugrundeliegenden Mechanismen, die für den Aufbau einer robusten, asynchronen Offline-First-Anwendung erforderlich sind. Der Fokus liegt hierbei auf der Integration von SQLDelight in einer Kotlin Multiplatform (KMP) Umgebung, die sowohl Desktop (JVM) als auch Web (Kotlin/JS) Ziele bedient, eingebettet in eine Mikro-Frontend-Architektur.
Ein zentraler Schwerpunkt dieser Arbeit ist die Überbrückung der Dichotomie zwischen der synchronen Natur klassischer JVM-Datenbanktreiber und der inhärent asynchronen, Event-Loop-basierten Umgebung des modernen Web (insbesondere unter Nutzung von Web Workern und OPFS). Darüber hinaus wird die fortgeschrittene Integration von Persistenzschichten in einem Mikro-Frontend-Ökosystem untersucht, um sicherzustellen, dass eine einzige Quelle der Wahrheit („Single Source of Truth“) über unabhängig bereitgestellte Frontend-Einheiten hinweg konsistent bleibt. Ein zentraler Schwerpunkt dieser Arbeit ist die Überbrückung der Dichotomie zwischen der synchronen Natur klassischer JVM-Datenbanktreiber und der inhärent asynchronen, Event-Loop-basierten Umgebung des modernen Web (insbesondere unter Nutzung von Web Workern und OPFS). Darüber hinaus wird die fortgeschrittene Integration von Persistenzschichten in einem Mikro-Frontend-Ökosystem untersucht, um sicherzustellen, dass eine einzige Quelle der Wahrheit („Single Source of Truth“) über unabhängig bereitgestellte Frontend-Einheiten hinweg konsistent bleibt.
@@ -17,11 +17,11 @@ Ein zentraler Schwerpunkt dieser Arbeit ist die Überbrückung der Dichotomie zw
### 1.1 Die Evolution von Kotlin Multiplatform ### 1.1 Die Evolution von Kotlin Multiplatform
Mit der Veröffentlichung von Kotlin 2.3.0 im Dezember 2025 hat sich das Ökosystem von einer experimentellen Technologie zu einem stabilen Standard für Enterprise-Architekturen entwickelt. Während frühere Versionen oft mit Inkonsistenzen zwischen den Compilern (JVM vs. JS/Native) zu kämpfen hatten, bietet der K2-Compiler in Version 2.3.0 eine vereinheitlichte Frontend-IR (Intermediate Representation), die eine robustere statische Analyse und performantere Kompilierung ermöglicht. Dies ist entscheidend für komplexe Multi-Modul-Projekte, wie sie in Mikro-Frontend-Architekturen üblich sind. Mit der Veröffentlichung von Kotlin 2.3.21 im Dezember 2025 hat sich das Ökosystem von einer experimentellen Technologie zu einem stabilen Standard für Enterprise-Architekturen entwickelt. Während frühere Versionen oft mit Inkonsistenzen zwischen den Compilern (JVM vs. JS/Native) zu kämpfen hatten, bietet der K2-Compiler in Version 2.3.21 eine vereinheitlichte Frontend-IR (Intermediate Representation), die eine robustere statische Analyse und performantere Kompilierung ermöglicht. Dies ist entscheidend für komplexe Multi-Modul-Projekte, wie sie in Mikro-Frontend-Architekturen üblich sind.
### 1.2 Gradle 9.1.0: Die Build-Infrastruktur ### 1.2 Gradle 9.5.0: Die Build-Infrastruktur
Gradle 9.1.0, veröffentlicht im September 2025, hat die Art und Weise, wie KMP-Projekte konfiguriert werden, grundlegend verändert. Mit der vollständigen Unterstützung des „Configuration Cache“ und der strikten „Project Isolation“ zwingt es Entwickler zu sauberen Modulgrenzen. Für unser Szenario bedeutet dies, dass die Abhängigkeiten zwischen dem `shared`-Modul (Datenbank) und den konsumierenden Mikro-Frontends explizit und ohne Seiteneffekte definiert werden müssen, um die parallele Ausführung und inkrementelle Kompilierung nicht zu gefährden. Gradle 9.5.0, veröffentlicht im September 2025, hat die Art und Weise, wie KMP-Projekte konfiguriert werden, grundlegend verändert. Mit der vollständigen Unterstützung des „Configuration Cache“ und der strikten „Project Isolation“ zwingt es Entwickler zu sauberen Modulgrenzen. Für unser Szenario bedeutet dies, dass die Abhängigkeiten zwischen dem `shared`-Modul (Datenbank) und den konsumierenden Mikro-Frontends explizit und ohne Seiteneffekte definiert werden müssen, um die parallele Ausführung und inkrementelle Kompilierung nicht zu gefährden.
### 1.3 Die Problemstellung: Synchron vs. Asynchron ### 1.3 Die Problemstellung: Synchron vs. Asynchron
@@ -38,12 +38,12 @@ SQLDelight 2.0+ adressiert dieses Problem mit der Konfiguration `generateAsync =
In einer Offline-First-Architektur fungiert die lokale Datenbank nicht als bloßer Cache, sondern als primäre Quelle der Wahrheit. Die Benutzeroberfläche (UI) kommuniziert niemals direkt mit dem Netzwerk. In einer Offline-First-Architektur fungiert die lokale Datenbank nicht als bloßer Cache, sondern als primäre Quelle der Wahrheit. Die Benutzeroberfläche (UI) kommuniziert niemals direkt mit dem Netzwerk.
| Konzept | Traditionelle Architektur | Offline-First Architektur | | Konzept | Traditionelle Architektur | Offline-First Architektur |
| --- | --- | --- | |--------------------|------------------------------------------------------|---------------------------------------------------------------------|
| **Datenquelle** | Remote API (REST/GraphQL) | Lokale Datenbank (SQLite) | | **Datenquelle** | Remote API (REST/GraphQL) | Lokale Datenbank (SQLite) |
| **Lesepfad** | UI ruft Netzwerk auf -> Wartet -> Zeigt an | UI beobachtet Datenbank (Flow) -> Zeigt an | | **Lesepfad** | UI ruft Netzwerk auf -> Wartet -> Zeigt an | UI beobachtet Datenbank (Flow) -> Zeigt an |
| **Schreibpfad** | UI sendet an API -> Wartet auf OK -> Aktualisiert UI | UI schreibt in DB -> DB emittiert neue Daten -> Sync im Hintergrund | | **Schreibpfad** | UI sendet an API -> Wartet auf OK -> Aktualisiert UI | UI schreibt in DB -> DB emittiert neue Daten -> Sync im Hintergrund |
| **Netzwerkstatus** | Voraussetzung für Funktionalität | Optional; beeinflusst nur Synchronisation | | **Netzwerkstatus** | Voraussetzung für Funktionalität | Optional; beeinflusst nur Synchronisation |
Dieses Prinzip der „Inversion of Control“ entkoppelt die User Experience von Netzwerklatenz und -verfügbarkeit. In SQLDelight wird dies durch Reactive Extensions realisiert, die SQL-Abfragen als `Flow<T>` exponieren, die sich bei Datenänderungen automatisch aktualisieren. Dieses Prinzip der „Inversion of Control“ entkoppelt die User Experience von Netzwerklatenz und -verfügbarkeit. In SQLDelight wird dies durch Reactive Extensions realisiert, die SQL-Abfragen als `Flow<T>` exponieren, die sich bei Datenänderungen automatisch aktualisieren.
@@ -60,8 +60,8 @@ Das Fundament eines stabilen KMP-Projekts ist eine präzise Gradle-Konfiguration
### 3.1 Version Catalog (`gradle/libs.versions.toml`)toml ### 3.1 Version Catalog (`gradle/libs.versions.toml`)toml
[versions] [versions]
kotlin = "2.3.0" kotlin = "2.3.21"
gradle = "9.1.0" gradle = "9.5.0"
sqldelight = "2.1.0" sqldelight = "2.1.0"
coroutines = "1.10.1" # Hypothetische Version passend zu Kotlin 2.3 coroutines = "1.10.1" # Hypothetische Version passend zu Kotlin 2.3
ktor = "3.1.0" ktor = "3.1.0"
@@ -5,20 +5,20 @@ owner: Lead Architect
tags: [kotlin, java, configuration, setup] tags: [kotlin, java, configuration, setup]
--- ---
# Tech-Stack Referenz: Kotlin 2.3.0 & Java 25 (KMP) # Tech-Stack Referenz: Kotlin 2.3.21 & Java 25 (KMP)
**Kontext:** Dieses Dokument beschreibt die notwendigen Konfigurationen, um Kotlin 2.3.0 mit Java 25 in einem Kotlin Multiplatform (KMP) Projekt mit Gradle 9.x zu verwenden. **Kontext:** Dieses Dokument beschreibt die notwendigen Konfigurationen, um Kotlin 2.3.21 mit Java 25 in einem Kotlin Multiplatform (KMP) Projekt mit Gradle 9.x zu verwenden.
--- ---
### 1. Kern-Spezifikationen ### 1. Kern-Spezifikationen
| Komponente | Version | Status | | Komponente | Version | Status |
| --- |----------| --- | |--------------------------|----------|------------------------------------------|
| **Kotlin** | `2.3.0` | Stabil (K2 Compiler standardmäßig aktiv) | | **Kotlin** | `2.3.21` | Stabil (K2 Compiler standardmäßig aktiv) |
| **Java (JDK)** | `25` | LTS (Long-Term Support) | | **Java (JDK)** | `25` | LTS (Long-Term Support) |
| **Gradle** | `9.2.1` | Erforderlich für JDK 25 Support | | **Gradle** | `9.5.0` | Erforderlich für JDK 25 Support |
| **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität | | **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität |
--- ---
@@ -28,7 +28,7 @@ Für ein **Kotlin Multiplatform (KMP)** Projekt ist die Java Toolchain-Konfigura
```kotlin ```kotlin
plugins { plugins {
kotlin("multiplatform") version "2.3.0" kotlin("multiplatform") version "2.3.21"
id("com.android.library") version "8.8.0" // Falls Android Target genutzt wird id("com.android.library") version "8.8.0" // Falls Android Target genutzt wird
} }
@@ -60,15 +60,15 @@ Damit das Projekt Java 25 erkennt, muss der Wrapper auf dem neuesten Stand sein:
**Terminal-Befehl:** **Terminal-Befehl:**
```bash ```bash
./gradlew wrapper --gradle-version 9.2.1 --distribution-type all ./gradlew wrapper --gradle-version 9.5.0 --distribution-type all
``` ```
--- ---
### 4. Wichtige Kompatibilitätshinweise ### 4. Wichtige Kompatibilitätshinweise
* **IDE-Version:** IntelliJ IDEA 2025.3 (oder neuer) wird für die volle Unterstützung von JDK 25 und dem Kotlin 2.3.0 Plugin empfohlen. * **IDE-Version:** IntelliJ IDEA 2025.3 (oder neuer) wird für die volle Unterstützung von JDK 25 und dem Kotlin 2.3.21 Plugin empfohlen.
* **K2 Compiler:** Kotlin 2.3.0 nutzt den K2-Compiler. * **K2 Compiler:** Kotlin 2.3.21 nutzt den K2-Compiler.
* **Bytecode:** Java 25 Bytecode wird nur generiert, wenn das `jvmTarget` explizit auf `25` gesetzt ist. * **Bytecode:** Java 25 Bytecode wird nur generiert, wenn das `jvmTarget` explizit auf `25` gesetzt ist.
--- ---
@@ -76,4 +76,4 @@ Damit das Projekt Java 25 erkennt, muss der Wrapper auf dem neuesten Stand sein:
### 5. Bekannte Features in diesem Setup ### 5. Bekannte Features in diesem Setup
* **Java 25 Features:** Unterstützung für die finalen Versionen von *Scoped Values* und *Structured Concurrency*. * **Java 25 Features:** Unterstützung für die finalen Versionen von *Scoped Values* und *Structured Concurrency*.
* **Kotlin 2.3.0 Features:** Nutzung von `explicit backing fields` und dem verbesserten `unused return value` Checker. * **Kotlin 2.3.21 Features:** Nutzung von `explicit backing fields` und dem verbesserten `unused return value` Checker.
@@ -5,7 +5,7 @@ owner: Lead Architect
tags: [kotlin, release-notes, tech-stack] tags: [kotlin, release-notes, tech-stack]
--- ---
# Was ist neu in Kotlin 2.3.0 # Was ist neu in Kotlin 2.3.21
**Quelle:** [Offizielle Kotlin-Dokumentation](https://kotlinlang.org/docs/whatsnew23.html) **Quelle:** [Offizielle Kotlin-Dokumentation](https://kotlinlang.org/docs/whatsnew23.html)
**Datum des Dokuments:** 16. Dezember 2025 **Datum des Dokuments:** 16. Dezember 2025
@@ -13,7 +13,7 @@ tags: [kotlin, release-notes, tech-stack]
--- ---
Kotlin 2.3.0 ist erschienen! Hier sind die wichtigsten Highlights: Kotlin 2.3.21 ist erschienen! Hier sind die wichtigsten Highlights:
* **Sprache:** Mehr stabile und standardmäßig aktivierte Features, Checker für ungenutzte Rückgabewerte, explizite Backing Fields und Änderungen bei der kontextsensitiven Auflösung. * **Sprache:** Mehr stabile und standardmäßig aktivierte Features, Checker für ungenutzte Rückgabewerte, explizite Backing Fields und Änderungen bei der kontextsensitiven Auflösung.
* **Kotlin/JVM:** Unterstützung für Java 25. * **Kotlin/JVM:** Unterstützung für Java 25.
@@ -26,7 +26,7 @@ Kotlin 2.3.0 ist erschienen! Hier sind die wichtigsten Highlights:
## Sprache ## Sprache
Kotlin 2.3.0 konzentriert sich auf die Stabilisierung von Features, führt einen neuen Mechanismus zur Erkennung ungenutzter Rückgabewerte ein und verbessert die kontextsensitive Auflösung. Kotlin 2.3.21 konzentriert sich auf die Stabilisierung von Features, führt einen neuen Mechanismus zur Erkennung ungenutzter Rückgabewerte ein und verbessert die kontextsensitive Auflösung.
### Stabile Features ### Stabile Features
@@ -38,13 +38,13 @@ Folgende Features sind nun stabil:
* Unterstützung für `return`-Anweisungen in Ausdrucks-Bodies mit explizitem Rückgabetyp ist nun standardmäßig aktiviert. * Unterstützung für `return`-Anweisungen in Ausdrucks-Bodies mit explizitem Rückgabetyp ist nun standardmäßig aktiviert.
### Experimentell: Checker für ungenutzte Rückgabewerte ### Experimentell: Checker für ungenutzte Rückgabewerte
Kotlin 2.3.0 führt den Checker für ungenutzte Rückgabewerte ein, um das versehentliche Ignorieren von Ergebnissen zu verhindern. Kotlin 2.3.21 führt den Checker für ungenutzte Rückgabewerte ein, um das versehentliche Ignorieren von Ergebnissen zu verhindern.
### Experimentell: Explizite Backing Fields ### Experimentell: Explizite Backing Fields
Eine neue Syntax zur expliziten Deklaration des zugrundeliegenden Felds, das den Wert einer Property hält vereinfacht das verbreitete Backing-Properties-Muster. Eine neue Syntax zur expliziten Deklaration des zugrundeliegenden Felds, das den Wert einer Property hält vereinfacht das verbreitete Backing-Properties-Muster.
## Kotlin/JVM: Unterstützung für Java 25 ## Kotlin/JVM: Unterstützung für Java 25
Ab Kotlin 2.3.0 kann der Compiler Klassen mit Java-25-Bytecode generieren. Ab Kotlin 2.3.21 kann der Compiler Klassen mit Java-25-Bytecode generieren.
## Kotlin/Native ## Kotlin/Native
* **Verbesserter Swift-Export:** Direkte Zuordnung für native Enum-Klassen und variadische Funktionsparameter. * **Verbesserter Swift-Export:** Direkte Zuordnung für native Enum-Klassen und variadische Funktionsparameter.
@@ -3,22 +3,26 @@
## 🏗️ [Lead Architect] | 14. April 2026 ## 🏗️ [Lead Architect] | 14. April 2026
Dieses Dokument beschreibt die Umsetzung der Online-Nennung für das Turnier in Neumarkt (24. April 2026). Dieses Dokument beschreibt die Umsetzung der Online-Nennung für das Turnier in Neumarkt (24. April 2026).
Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Service` sendet, welcher diese verarbeitet und in der Desktop-Zentrale zur manuellen Übernahme bereitstellt. Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Service` sendet, welcher diese verarbeitet
und in der Desktop-Zentrale zur manuellen Übernahme bereitstellt.
--- ---
### Phase 1: E-Mail-Infrastruktur (Vorbereitung) ✅ ### Phase 1: E-Mail-Infrastruktur (Vorbereitung) ✅
* [x] Definition des Adress-Schemas: `meldestelle-[Turnier-Nr]@mo-code.at`. * [x] Definition des Adress-Schemas: `meldestelle-[Turnier-Nr]@mo-code.at`.
* [x] Konfiguration der World4You SMTP/IMAP Zugangsdaten. * [x] Konfiguration der World4You SMTP/IMAP Zugangsdaten.
* [x] Mailpit Integration für lokale Tests (bereits in `dc-ops.yaml`). * [x] Mailpit Integration für lokale Tests (bereits in `dc-ops.yaml`).
### Phase 2: Das Web-Formular (WasmJS Frontend) ✅ ### Phase 2: Das Web-Formular (WasmJS Frontend) ✅
* [x] **Basis-UI:** Erstellung des Formulars gemäß Spezifikation (Reiter, Pferd, Lizenz, Bewerbe). * [x] **Basis-UI:** Erstellung des Formulars gemäß Spezifikation (Reiter, Pferd, Lizenz, Bewerbe).
* [x] **Validierung:** Implementierung der Pflichtfeld-Prüfung (Buttonsperre bis alles ok). * [x] **Validierung:** Implementierung der Pflichtfeld-Prüfung (Buttonsperre bis alles ok).
* [x] **Mail-Versand:** Integration des API-Calls an das Backend (`mail-service`), um die Nennung zu speichern. * [x] **Mail-Versand:** Integration des API-Calls an das Backend (`mail-service`), um die Nennung zu speichern.
* [x] **DSGVO:** Checkbox und Hinweistext eingebaut. * [x] **DSGVO:** Checkbox und Hinweistext eingebaut.
### Phase 3: Mail-Service (Backend-Verarbeitung) 🏗️ ### Phase 3: Mail-Service (Backend-Verarbeitung) 🏗️
* [x] **Endpoint:** POST-Endpunkt für direkte Nennungen aus dem Web-Formular implementiert. * [x] **Endpoint:** POST-Endpunkt für direkte Nennungen aus dem Web-Formular implementiert.
* [ ] **Polling:** Implementierung des IMAP-Pollers (imap.world4you.com). * [ ] **Polling:** Implementierung des IMAP-Pollers (imap.world4you.com).
* [ ] **Parsing:** Extraktion der Turnier-Nummer aus dem `To`-Header und Mapping auf das Datenbank-Schema (Tenant). * [ ] **Parsing:** Extraktion der Turnier-Nummer aus dem `To`-Header und Mapping auf das Datenbank-Schema (Tenant).
@@ -26,12 +30,14 @@ Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Serv
* [x] **Persistence:** Speichern der eingegangenen "Nennungs-Mails" in einer temporären Tabelle. * [x] **Persistence:** Speichern der eingegangenen "Nennungs-Mails" in einer temporären Tabelle.
### Phase 4: Desktop-Zentrale Integration ✅ ### Phase 4: Desktop-Zentrale Integration ✅
* [x] **UI-Tab:** Neuer Reiter "Online-Eingang" in der Turnierverwaltung (`TurnierDetailScreen`). * [x] **UI-Tab:** Neuer Reiter "Online-Eingang" in der Turnierverwaltung (`TurnierDetailScreen`).
* [x] **Vorschau:** Anzeige der eingegangenen Nennungen mit Details (`OnlineNennungEingangTabContent`). * [x] **Vorschau:** Anzeige der eingegangenen Nennungen mit Details (`OnlineNennungEingangTabContent`).
* [x] **Übernahme:** "Übernehmen"-Button, der Reiter/Pferd in die Nennung vorausfüllt (`NennungViewModel`). * [x] **Übernahme:** "Übernehmen"-Button, der Reiter/Pferd in die Nennung vorausfüllt (`NennungViewModel`).
* [ ] **Abschluss:** Manueller "Bestätigen"-Button zum Versenden der finalen Bestätigungsmail. * [ ] **Abschluss:** Manueller "Bestätigen"-Button zum Versenden der finalen Bestätigungsmail.
### Phase 5: End-to-End Test & Deployment 🚀 (Deadline: 21.04.2026) ### Phase 5: End-to-End Test & Deployment 🚀 (Deadline: 21.04.2026)
* [ ] Test-Nennung über Web-Formular (Mailpit). * [ ] Test-Nennung über Web-Formular (Mailpit).
* [ ] Verifikation der Schema-Zuordnung im Backend. * [ ] Verifikation der Schema-Zuordnung im Backend.
* [ ] Live-Test mit `online-nennen@mo-code.at`. * [ ] Live-Test mit `online-nennen@mo-code.at`.
@@ -40,6 +46,7 @@ Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Serv
--- ---
### Meilensteine ### Meilensteine
1. **16.04.:** Web-Formular ist funktionsfähig (Senden möglich). 1. **16.04.:** Web-Formular ist funktionsfähig (Senden möglich).
2. **18.04.:** Mail-Service verarbeitet Mails und sendet Auto-Antworten. 2. **18.04.:** Mail-Service verarbeitet Mails und sendet Auto-Antworten.
3. **20.04.:** Desktop-UI zur Übernahme ist fertig. 3. **20.04.:** Desktop-UI zur Übernahme ist fertig.
@@ -10,7 +10,9 @@ last_update: 2026-03-25
10. **🏗️ [Lead Architect]** | 5. April 2026 10. **🏗️ [Lead Architect]** | 5. April 2026
**Kontext:** **Kontext:**
Der ZNS-Importer wurde für die Verarbeitung der Datei `RICHT01.dat` optimiert. Es wurde klargestellt, dass Richter (SatzID 'X') und Parcoursbauer (SatzID 'Y') gemeinsam in dieser Datei geliefert werden. Eine separate `PARCO01.dat` existiert nicht. Der ZNS-Importer wurde für die Verarbeitung der Datei `RICHT01.dat` optimiert. Es wurde klargestellt, dass Richter (
SatzID 'X') und Parcoursbauer (SatzID 'Y') gemeinsam in dieser Datei geliefert werden. Eine separate `PARCO01.dat`
existiert nicht.
Um den `registration-context` und `actor-context` unter realistischen Bedingungen testen zu können, benötigen wir echte 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 Stammdaten (Reiter, Pferde, Vereine, Funktionäre). Diese Daten werden vom ÖPS (Österreichischer Pferdesportverband) in
Form einer `ZNS.zip` bereitgestellt. Form einer `ZNS.zip` bereitgestellt.
@@ -51,7 +53,8 @@ gesteuert wird und die Daten persistent im Backend (`actor-context`) ablegt.
* ZIP-Entpackung in-memory implementiert (`ZnsImportService`). * ZIP-Entpackung in-memory implementiert (`ZnsImportService`).
* [x] **Legacy-Parser (CP850 Fixed-Width):** * [x] **Legacy-Parser (CP850 Fixed-Width):**
* `ZnsLegacyParsers` in `core:zns-parser` (KMP-Modul) implementiert. * `ZnsLegacyParsers` in `core:zns-parser` (KMP-Modul) implementiert.
* Alle 4 Dateitypen (VEREIN01, LIZENZ01, PFERDE01, RICHT01) bytegenau gemappt. RICHT01 verarbeitet Richter ('X') und Parcoursbauer ('Y'). ✅ * Alle 4 Dateitypen (VEREIN01, LIZENZ01, PFERDE01, RICHT01) bytegenau gemappt. RICHT01 verarbeitet Richter ('X') und
Parcoursbauer ('Y'). ✅
### Phase 2: Domain-Mapping & Persistenz (👷 Backend Developer) ### Phase 2: Domain-Mapping & Persistenz (👷 Backend Developer)
@@ -0,0 +1,89 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-15
---
# Frontend-Architektur & Modularisierungsstrategie
**Status:** ENTWURF
**Zuletzt aktualisiert:** 2026-01-19
**Kontext:** Migration zu Clean Architecture & Feature-Modulen
---
## 1. Übersicht
Die Frontend-Architektur von **Meldestelle** basiert auf **Kotlin Multiplatform (KMP)** mit **Compose Multiplatform**
für die Benutzeroberfläche. Wir folgen einem strikten **Clean Architecture**-Ansatz, um Testbarkeit, Skalierbarkeit und
Trennung der Zuständigkeiten sicherzustellen.
## 2. Modulstruktur
Das Projekt ist in folgende Schichten unterteilt:
### 2.1 Core-Module (`frontend/core`)
Wiederverwendbare Komponenten, die unabhängig von spezifischen Geschäftsfunktionen sind.
* `core-network`: Zentrale HTTP-Client-Konfiguration (Auth, Logging, ContentNegotiation).
* `core-sync`: Generische Synchronisierungslogik (`SyncManager`, `SyncableRepository`).
* `core-ui`: Gemeinsame UI-Komponenten und Design-System.
### 2.2 Feature-Module (`frontend/features`)
Jede Geschäftsdomäne (z.B. `ping`, `auth`, `events`) liegt in ihrem eigenen Modul.
Ein Feature-Modul MUSS die **Clean Architecture** Paketstruktur einhalten:
* `at.mocode.{feature}.feature.domain`
* **Entitäten:** Reine Datenklassen.
* **Interfaces:** Repository-Interfaces, Service-Interfaces.
* **Use Cases:** Geschäftslogik (optional, für komplexe Logik).
* `at.mocode.{feature}.feature.data`
* **Implementierungen:** Repository-Implementierungen, API-Clients.
* **DTOs:** Data Transfer Objects (wenn von Domain-Entitäten abweichend).
* `at.mocode.{feature}.feature.presentation`
* **ViewModels:** Zustandsverwaltung.
* **Screens:** Composable-Funktionen.
* `at.mocode.{feature}.feature.di`
* **Koin-Modul:** Konfiguration der Dependency Injection.
### 2.3 Shells (`frontend/shells`)
Anwendungs-Einstiegspunkte, die alles zusammenführen.
* `meldestelle-portal`: Die Haupt-Web-/Desktop-Anwendung.
## 3. Migrationsstrategie (Übergangsphase)
Wir migrieren aktuell von einer monolithischen `clients`-Paketstruktur zu modularen Feature-Modulen.
**Regeln für die Migration:**
1. **Neue Features:** Müssen direkt in `frontend/features/{name}` unter Verwendung der Clean Architecture-Struktur
implementiert werden.
2. **Bestehende Features:** Werden schrittweise migriert.
3. **Koexistenz:** Während des Übergangs ist Legacy-Code in `clients/` erlaubt, aber als veraltet markiert.
4. **Dependency Injection:** Legacy-Code muss die neuen Koin-Module verwenden, sofern verfügbar.
5. **Keine Ghost-Klassen:** Klassen nicht duplizieren. Wenn eine Klasse in ein Feature-Modul verschoben wird, muss die
alte in `clients/` gelöscht werden.
## 4. Wichtige Entscheidungen (ADRs)
### ADR-001: Entkopplung der Sync-Logik
* **Entscheidung:** ViewModels dürfen nicht direkt vom `SyncManager` abhängen.
* **Begründung:** Um einfacheres Testen zu ermöglichen und die Komplexität des generischen Sync-Mechanismus zu
verbergen.
* **Umsetzung:** Ein Domain-Service-Interface (z.B. `PingSyncService`) einführen, das den `SyncManager`-Aufruf kapselt.
### ADR-002: Feature-Modul-Isolation
* **Entscheidung:** Feature-Module sollten nach Möglichkeit nicht direkt voneinander abhängen.
* **Kommunikation:** Gemeinsame Core-Module oder lose Kopplung über Interfaces/Events verwenden, wenn modulübergreifende
Kommunikation nötig ist.
---
**Freigegeben von:** Lead Architect
@@ -3,11 +3,15 @@ type: Reference
status: ACTIVE status: ACTIVE
owner: Lead Architect owner: Lead Architect
--- ---
# Architektur: Das Platform-Modul # Architektur: Das Platform-Modul
## Überblick ## Überblick
Das **Platform-Modul** ist das Rückgrat der Build-Infrastruktur des Meldestelle-Projekts. Seine alleinige Aufgabe ist die zentrale Verwaltung und Bereitstellung von Abhängigkeiten und deren Versionen. Dies stellt sicher, dass alle Module im gesamten Projekt dieselben Bibliotheksversionen verwenden, was Inkonsistenzen ("JAR Hell") verhindert und die Wartbarkeit drastisch verbessert. Das **Platform-Modul** ist das Rückgrat der Build-Infrastruktur des Meldestelle-Projekts. Seine alleinige Aufgabe ist
die zentrale Verwaltung und Bereitstellung von Abhängigkeiten und deren Versionen. Dies stellt sicher, dass alle Module
im gesamten Projekt dieselben Bibliotheksversionen verwenden, was Inkonsistenzen ("JAR Hell") verhindert und die
Wartbarkeit drastisch verbessert.
Das Modul agiert als eine interne "Single Source of Truth" für alle externen Bibliotheken. Das Modul agiert als eine interne "Single Source of Truth" für alle externen Bibliotheken.
@@ -24,17 +28,21 @@ platform/
### `platform-bom` ### `platform-bom`
Dies ist das wichtigste Modul der Plattform. Es ist als "Bill of Materials" (BOM) konfiguriert und nutzt das `java-platform`-Plugin von Gradle. Dies ist das wichtigste Modul der Plattform. Es ist als "Bill of Materials" (BOM) konfiguriert und nutzt das
`java-platform`-Plugin von Gradle.
* **Zweck:** Definiert eine umfassende Liste von Abhängigkeiten und deren exakten, geprüften Versionen. Es importiert auch andere wichtige BOMs (z.B. von Spring Boot und Kotlin). * **Zweck:** Definiert eine umfassende Liste von Abhängigkeiten und deren exakten, geprüften Versionen. Es importiert
* **Funktionsweise:** Andere Module importieren diese BOM mit `platform(projects.platform.platformBom)`. Gradle sorgt dann dafür, dass alle transitiven und deklarierten Abhängigkeiten den in der BOM festgelegten Versionen entsprechen. auch andere wichtige BOMs (z.B. von Spring Boot und Kotlin).
* **Funktionsweise:** Andere Module importieren diese BOM mit `platform(projects.platform.platformBom)`. Gradle sorgt
dann dafür, dass alle transitiven und deklarierten Abhängigkeiten den in der BOM festgelegten Versionen entsprechen.
* **Vorteil:** Absolute Versionskontrolle über das gesamte Projekt. * **Vorteil:** Absolute Versionskontrolle über das gesamte Projekt.
### `platform-dependencies` ### `platform-dependencies`
Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhängigkeiten bündelt. Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhängigkeiten bündelt.
* **Zweck:** Vereinfacht die `build.gradle.kts`-Dateien der Service-Module. Anstatt 5-6 einzelne `kotlinx`- und Logging-Bibliotheken hinzuzufügen, genügt eine einzige Abhängigkeit zu diesem Modul. * **Zweck:** Vereinfacht die `build.gradle.kts`-Dateien der Service-Module. Anstatt 5-6 einzelne `kotlinx`- und
Logging-Bibliotheken hinzuzufügen, genügt eine einzige Abhängigkeit zu diesem Modul.
* **Verwendung:** * **Verwendung:**
```kotlin ```kotlin
@@ -48,7 +56,8 @@ Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhäng
Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken. Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken.
* **Zweck:** Stellt ein konsistentes Set an Test-Frameworks (JUnit 5, MockK, AssertJ) und Werkzeugen (Testcontainers) für alle Module bereit. * **Zweck:** Stellt ein konsistentes Set an Test-Frameworks (JUnit 5, MockK, AssertJ) und Werkzeugen (Testcontainers)
für alle Module bereit.
* **Verwendung:** * **Verwendung:**
```kotlin ```kotlin
@@ -58,4 +67,5 @@ Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken.
} }
``` ```
* **Optimierung:** Dieses Modul nutzt die in `libs.versions.toml` definierten `[bundles]`, um die Build-Datei extrem kurz und lesbar zu halten. * **Optimierung:** Dieses Modul nutzt die in `libs.versions.toml` definierten `[bundles]`, um die Build-Datei extrem
kurz und lesbar zu halten.
@@ -0,0 +1,362 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
---
# Meldestelle — Tech-Stack Zusammenfassung
> **Zweck:** Vollständige Referenz des eingesetzten Tech-Stacks im Projekt "Meldestelle".
> Dient als Basis für Recherchen zu Self-Hosted AI (Codegenerierung, RAG, Agenten).
> **Stand:** 07. März 2026
---
## 1. Überblick
Das Projekt "Meldestelle" ist eine **Kotlin-first, Cloud-native Microservices-Plattform** für die Verwaltung von
Reitsport-Meldungen (FEI / ÖTO). Es kombiniert ein **Kotlin Multiplatform (KMP) Frontend** mit einem **Spring Boot
Microservices Backend** auf einer vollständig self-hosted Infrastruktur.
```
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (KMP) │ Backend (Spring Boot / Kotlin JVM) │
│ Kotlin 2.3.21 / Compose │ Java 25 / Spring Boot 3.5.9 │
│ JS + WASM (geplant) │ Microservices + API-Gateway │
├─────────────────────────────────────────────────────────────────┤
│ Infrastruktur (Self-Hosted auf Zora / Proxmox) │
│ Keycloak · Consul · Valkey · PostgreSQL · Zipkin │
│ Prometheus · Grafana · Caddy · Pangolin-Tunnel │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. Sprachen & Laufzeiten
| Komponente | Sprache / Runtime | Version |
|:-----------|:-----------------------|:--------|
| Backend | Kotlin (JVM) | 2.3.21 |
| Frontend | Kotlin (KMP / JS) | 2.3.21 |
| JVM | Java (Eclipse Temurin) | 25 (EA) |
| Build | Gradle (Kotlin DSL) | 9.5.0 |
| Plattform | ARM64 (AArch64) | Linux |
---
## 3. Frontend — Kotlin Multiplatform (KMP)
### 3.1 Core-Framework
| Bibliothek | Version | Zweck |
|:----------------------|:--------|:---------------------------------|
| Kotlin Multiplatform | 2.3.21 | Cross-Platform-Basis (JS + WASM) |
| Compose Multiplatform | 1.10.0 | UI-Framework (Deklarativ) |
| Compose Hot Reload | 1.0.0 | Live-Reload im Dev-Modus |
| Koin (DI) | 4.1.1 | Dependency Injection |
| Koin Compose | 4.1.1 | DI-Integration für Compose |
| Ktor Client | 3.4.0 | HTTP-Client (Multiplatform) |
| Kotlin Serialization | 2.3.21 | JSON-Serialisierung |
### 3.2 Persistenz (Offline-First)
| Bibliothek | Version | Zweck |
|:----------------|:--------|:-----------------------------|
| SQLDelight | 2.2.1 | Cross-Platform SQL-Datenbank |
| SQLite (WASM) | 3.51.1 | SQLite für Browser/WASM |
| SQLite (Native) | 2.6.2 | SQLite für JVM/Desktop |
### 3.3 Build-Targets
| Target | Status | Anmerkung |
|:--------------|:-----------|:--------------------------|
| KotlinJS | ✅ Aktiv | Primäres Build-Target |
| WASM | ⏳ Geplant | Warten auf Alpha-Version |
| Desktop (JVM) | ⚙️ Möglich | uiDesktop 1.7.0 vorhanden |
### 3.4 Modul-Struktur
```
frontend/
├── core/
│ ├── core-network/ # Ktor HTTP-Client, Auth-Interceptor
│ ├── core-ui/ # Design-System, Tokens, Komponenten
│ ├── core-domain/ # Shared Domain-Models
│ └── core-data/ # Repository-Interfaces
├── features/
│ ├── ping-feature/ # ✅ Blueprint: MVVM + Repository + DI + Tests
│ └── members-feature/ # ⏳ Auskommentiert (nächste Phase)
└── shells/
└── meldestelle-portal/ # Web-App Shell (Caddy-served)
```
---
## 4. Backend — Spring Boot Microservices
### 4.1 Core-Framework
| Bibliothek | Version | Zweck |
|:-------------------------|:---------|:---------------------------------|
| Spring Boot | 3.5.9 | Microservices-Framework |
| Spring Cloud | 2025.0.1 | Service Discovery, Config |
| Spring Security (OAuth2) | (Boot) | JWT-Validierung, Resource Server |
| Spring Data JPA | (Boot) | ORM-Layer |
| Spring Data Valkey | 0.2.0 | Cache-Integration (Valkey/Redis) |
| Spring WebFlux | (Boot) | Reaktive API (Gateway) |
| Kotlin Coroutines | 2.3.21 | Async/Non-blocking |
### 4.2 Persistenz
| Bibliothek | Version | Zweck |
|:--------------------|:--------|:----------------------|
| PostgreSQL Driver | 42.7.8 | JDBC-Treiber |
| Exposed (JetBrains) | 1.0.0 | Kotlin-native SQL DSL |
| Flyway | 11.19.1 | Datenbank-Migrationen |
| HikariCP | 7.0.2 | Connection Pool |
> **Strategie (ADR-001):** Hybrid — JPA für einfache CRUD-Entities, Exposed für komplexe Queries und Domain-Logik.
### 4.3 Caching & Messaging
| Bibliothek | Version | Zweck |
|:--------------|:--------|:--------------------------------|
| Lettuce | 6.6.0 | Valkey/Redis-Client (reaktiv) |
| Redisson | 4.0.0 | Distributed Locks, Pub/Sub |
| Caffeine | 3.2.3 | In-Memory Cache (L1) |
| Reactor Kafka | 1.3.23 | Kafka-Client (Phase 3 / Outbox) |
### 4.4 Observability & Tracing
| Bibliothek | Version | Zweck |
|:-------------------|:--------|:-----------------------------|
| Micrometer | 1.16.1 | Metriken (Prometheus-Export) |
| Micrometer Tracing | 1.6.1 | Distributed Tracing |
| Zipkin Reporter | 3.5.1 | Trace-Export zu Zipkin |
| Logback | 1.5.25 | Logging |
### 4.5 Security
| Bibliothek | Version | Zweck |
|:-----------------------|:--------|:-------------------------|
| Keycloak Admin Client | 26.0.7 | Keycloak-API-Integration |
| Spring Security OAuth2 | (Boot) | JWT Resource Server |
| Jackson (Kotlin) | 3.0.3 | JSON-Serialisierung |
### 4.6 API & Dokumentation
| Bibliothek | Version | Zweck |
|:-------------------|:--------|:-----------------------|
| Springdoc OpenAPI | 3.0.0 | Swagger / OpenAPI 3.1 |
| Jakarta Annotation | 3.0.0 | Jakarta EE Annotations |
### 4.7 Modul-Struktur
```
backend/
├── infrastructure/
│ ├── gateway/ # ✅ API-Gateway (Spring Cloud Gateway)
│ ├── security/ # ✅ Zentrales OAuth2/JWT-Modul (DRY)
│ ├── cache/
│ │ ├── cache-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── event-store/
│ │ ├── event-store-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── persistence/ # Hybrid JPA + Exposed
│ └── messaging/ # Kafka (Phase 3 / Outbox-Pattern)
└── services/
├── ping/ # ✅ Deployed — Test/Blueprint-Service
├── entries/ # ⚙️ Registriert, noch nicht deployed
├── events/ # 👻 Ghost Service (nicht registriert)
├── horses/ # 👻 Ghost Service (nicht registriert)
├── masterdata/ # 👻 Ghost Service (nicht registriert)
├── registry/ # 👻 Ghost Service (nicht registriert)
├── results/ # 👻 Ghost Service (nicht registriert)
└── scheduling/ # 👻 Ghost Service (nicht registriert)
```
---
## 5. Infrastruktur-Services (Docker)
### 5.1 Laufende Services
| Service | Image / Version | Port(s) | Zweck |
|:-------------|:-----------------------|:-----------|:----------------------------|
| PostgreSQL | postgres:16-alpine | 5432 | Primäre Datenbank |
| Keycloak | keycloak:26.4 (custom) | 8180, 9000 | IAM / OAuth2 / OIDC |
| Valkey | valkey:8-alpine | 6379 | Cache + Event-Store |
| Consul | consul:1.21 | 8500, 8600 | Service Discovery + Config |
| Zipkin | openzipkin/zipkin:3.5 | 9411 | Distributed Tracing |
| Prometheus | prom/prometheus:v3.4 | 9090 | Metriken-Sammlung |
| Grafana | grafana/grafana:11.6 | 3000 | Dashboards / Visualisierung |
| Caddy | caddy:2.10-alpine | 4000 | Web-App Serving (Frontend) |
| API-Gateway | (custom Spring Boot) | 8081 | Zentraler Eintrittspunkt |
| Ping-Service | (custom Spring Boot) | 8082 | Test/Blueprint-Service |
### 5.2 CI/CD & DevOps
| Tool | Version / Details | Zweck |
|:--------------|:---------------------|:------------------------------|
| Gitea | Self-Hosted (CT 101) | Git-Repository + Registry |
| Gitea Actions | (Runner VM 102) | CI/CD-Pipeline |
| Docker Buildx | ARM64 (linux/arm64) | Multi-Arch Image Build |
| Pangolin | Self-Hosted Tunnel | Reverse Proxy / Extern-Zugang |
### 5.3 Netzwerk & Routing
| Subdomain | Intern (Zora) | Zweck |
|:--------------------|:-----------------|:---------------|
| `git.mo-code.at` | `10.0.0.22:3000` | Gitea |
| `api.mo-code.at` | `10.0.0.50:8081` | API-Gateway |
| `auth.mo-code.at` | `10.0.0.50:8180` | Keycloak |
| `app.mo-code.at` | `10.0.0.50:4000` | Web-App |
| `photos.mo-code.at` | `10.0.0.24:2283` | Immich (Fotos) |
---
## 6. Code-Qualität & Build-Tools
| Tool | Version | Zweck |
|:-------------------|:--------|:---------------------------------|
| Detekt | 1.23.6 | Kotlin Static Analysis |
| ktlint | 12.1.1 | Kotlin Code Formatter |
| ArchUnit | 1.4.1 | Architektur-Tests (Layer-Regeln) |
| Dokka | 2.1.0 | API-Dokumentation (KDoc) |
| Ben-Manes Versions | 0.51.0 | Dependency-Update-Check |
| KSP | 2.3.4 | Kotlin Symbol Processing |
### Build-Konfiguration
```properties
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.workers.max=8
org.gradle.configuration-cache=false # wegen JS-Test Serialisierungsproblem
org.gradle.dependency.verification=strict
```
---
## 7. Test-Stack
| Bibliothek | Version | Zweck |
|:--------------------------|:--------|:-----------------------------|
| JUnit Jupiter | 5.11.3 | Unit-Tests |
| JUnit Platform | 1.11.3 | Test-Runner |
| MockK | 1.14.7 | Kotlin Mocking |
| AssertJ | 3.27.7 | Fluent Assertions |
| Testcontainers | 2.0.3 | Integration-Tests (Docker) |
| Testcontainers Keycloak | 4.0.1 | Keycloak-Integration-Tests |
| Testcontainers PostgreSQL | 1.21.4 | DB-Integration-Tests |
| Testcontainers Kafka | 1.21.4 | Kafka-Integration-Tests |
| ArchUnit | 1.4.1 | Architektur-Compliance-Tests |
---
## 8. Architektur-Prinzipien (ADRs)
| ADR | Entscheidung | Status |
|:-----|:--------------------------------------------------|:--------|
| 0001 | Modulare Architektur (DDD, Clean Architecture) | ✅ Aktiv |
| 0003 | Microservices-Architektur | ✅ Aktiv |
| 0004 | Event-Driven Communication (Kafka Phase 3) | ✅ Aktiv |
| 001 | Backend-Infrastruktur: Hybrid JPA+Exposed, Valkey | ✅ Aktiv |
| 0013 | Tech-Stack-Stabilisierung 2026 (Versionen) | ✅ Aktiv |
**Kern-Prinzipien:**
- **Offline-First:** SQLDelight als Cross-Platform-DB, Sync-Mechanismus
- **Docs-as-Code:** `/docs` als Single Source of Truth
- **DRY-Infrastruktur:** Shared Security/Cache/EventStore-Module
- **ARM64-Native:** Alle Images für `linux/arm64` gebaut
---
## 9. Relevanz für Self-Hosted AI
### 9.1 Welche AI-Aufgaben entstehen im Projekt?
| Aufgabe | Häufigkeit | Komplexität |
|:-----------------------------------|:-------------|:------------|
| Kotlin/Spring Boot Code-Completion | Täglich | Mittel |
| Compose Multiplatform UI-Code | Täglich | Mittel |
| SQL / Exposed DSL Queries | Häufig | Mittel |
| Gradle Kotlin DSL Build-Skripte | Gelegentlich | Niedrig |
| Docker / YAML Konfigurationen | Gelegentlich | Niedrig |
| Architektur-Entscheidungen (ADR) | Selten | Hoch |
| Fachlogik FEI/ÖTO Regelwerk | Selten | Sehr hoch |
### 9.2 Anforderungen an das AI-Modell
```
MUSS:
✅ Kotlin (JVM + Multiplatform) — sehr gute Unterstützung
✅ Spring Boot / Spring Cloud — sehr gute Unterstützung
✅ Compose Multiplatform — gute Unterstützung (neuere Modelle)
✅ SQL / PostgreSQL — sehr gute Unterstützung
✅ Docker / YAML — sehr gute Unterstützung
✅ Deutsch (Fachsprache Reitsport) — für RAG-Dokumente
NICE-TO-HAVE:
⭐ Gradle Kotlin DSL
⭐ Keycloak / OAuth2 / OIDC
⭐ Microservices-Architektur-Patterns
```
### 9.3 Empfohlene Modelle für diesen Stack
| Modell | Größe | Stärke | RAM-Bedarf |
|:------------------------|:------|:----------------------------------|:-----------|
| `qwen2.5-coder:14b` | 14B | Code (Kotlin, Java, SQL) — Top | ~10 GB |
| `deepseek-coder-v2:16b` | 16B | Code-Completion, Refactoring | ~12 GB |
| `llama3.1:8b` | 8B | Allgemein + Deutsch, schnell | ~6 GB |
| `qwen2.5:32b` | 32B | Architektur, Planung, Fachlogik | ~22 GB |
| `codellama:13b` | 13B | Code-Completion (IntelliJ-Plugin) | ~9 GB |
> **Empfehlung für Zora (64 GB RAM):**
> - **Primär:** `qwen2.5-coder:14b` — bester Kotlin/Spring-Support
> - **Sekundär:** `qwen2.5:32b` — für Architektur und Fachlogik
> - **IntelliJ-Integration:** `codellama:13b` oder `qwen2.5-coder:14b`
### 9.4 RAG-Dokumente (Priorität)
Folgende Projekt-Dokumente sind besonders wertvoll als RAG-Kontext:
```
Hohe Priorität:
├── docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md
├── docs/01_Architecture/adr/ (alle ADRs)
├── docs/04_Agents/Playbooks/ (Agenten-Rollen)
├── gradle/libs.versions.toml (Versions-SSoT)
└── docs/07_Infrastructure/ (Infrastruktur-Referenz)
Mittlere Priorität:
├── docs/05_Backend/ (Backend-Guides)
├── docs/06_Frontend/ (Frontend-Guides)
└── docs/03_Domain/ (Fachlogik-Konzepte)
```
---
## 10. Zusammenfassung
```
TECH-STACK KOMPLEXITÄT
──────────────────────────────────────────────────────
Sprachen: Kotlin (JVM + KMP/JS)
Build: Gradle 9.5.0 + Kotlin DSL + libs.versions.toml
Frontend: Compose Multiplatform 1.10 + SQLDelight 2.2 + Koin 4.1
Backend: Spring Boot 3.5.9 + Spring Cloud 2025.0.1
Persistenz: PostgreSQL 16 + Exposed 1.0 + Flyway 11 + HikariCP 7
Cache: Valkey 8 + Lettuce 6.6 + Caffeine 3.2
Security: Keycloak 26.4 + Spring Security OAuth2 + JWT
Observability: Micrometer 1.16 + Zipkin 3.5 + Prometheus + Grafana 11.6
Service Mesh: Consul 1.21 + Spring Cloud Gateway
Messaging: Kafka (Phase 3) + Reactor Kafka 1.3
CI/CD: Gitea Actions + Docker Buildx (ARM64)
Hosting: Proxmox VE 8.4 + Docker Compose + Pangolin-Tunnel
```
@@ -13,7 +13,7 @@ Feature-Implementierung an der verfeinerten DDD-Struktur (ADR-0014) sowie der De
### 🟢 Technische Stabilisierung ### 🟢 Technische Stabilisierung
* **Kotlin 2.3.20:** Alle Module wurden auf Kotlin 2.3.20 migriert. Deprecation-Warnungen für `Clock` und `Instant` * **Kotlin 2.3.21:** Alle Module wurden auf Kotlin 2.3.21 migriert. Deprecation-Warnungen für `Clock` und `Instant`
wurden durch Standardisierung auf `kotlin.time.*` behoben. wurden durch Standardisierung auf `kotlin.time.*` behoben.
* **Zentralisierte Serialisierung:** Erstellung der `Serializers.kt` im `core-domain` Modul für `Uuid`, `Instant`, * **Zentralisierte Serialisierung:** Erstellung der `Serializers.kt` im `core-domain` Modul für `Uuid`, `Instant`,
`LocalDate`, `LocalDateTime` und `LocalTime`. `LocalDate`, `LocalDateTime` und `LocalTime`.
@@ -10,23 +10,27 @@ Cups/Serien.
## 1) Fokus-Themen und Deliverables (heute Nacht) ## 1) Fokus-Themen und Deliverables (heute Nacht)
1. Reporting & Output (Vorbereitung) 1. Reporting & Output (Vorbereitung)
- [Owner] Vorlagen sammeln/übermitteln: Startlisten, Ergebnislisten (PDF/Scan/Excel)
- [Owner] Spring-Protokolle: Inhalte/Felder definieren (Fehler, Zeit, Stechen) - [Owner] Vorlagen sammeln/übermitteln: Startlisten, Ergebnislisten (PDF/Scan/Excel)
- [Owner] Dressur-Protokolle: Vorlage für personalisierten Ausdruck (Kopfzeile Reiter/Pferd) - [Owner] Spring-Protokolle: Inhalte/Felder definieren (Fehler, Zeit, Stechen)
- [Arch/BE] Technik-Entscheidung PDF: KMP-Library vs. Server-Side Rendering (ADR-Entwurf) - [Owner] Dressur-Protokolle: Vorlage für personalisierten Ausdruck (Kopfzeile Reiter/Pferd)
- [FE] UI-Draft „Druckvorschau“ in V2-Screens: Platzhalter mit Beispiel-Daten - [Arch/BE] Technik-Entscheidung PDF: KMP-Library vs. Server-Side Rendering (ADR-Entwurf)
- [FE] UI-Draft „Druckvorschau“ in V2-Screens: Platzhalter mit Beispiel-Daten
2. Events/Turniere (Backend-Readiness für Neumarkt) 2. Events/Turniere (Backend-Readiness für Neumarkt)
- [BE] DB-Migrationen finalisieren: `turniere`, `ausschreibungen` (Flyway)
- [BE] Seed-Datensatz „Veranstaltung Neumarkt 2026“ (+ 12 Turniere) - [BE] DB-Migrationen finalisieren: `turniere`, `ausschreibungen` (Flyway)
- [BE] Repositories prüfen und Test-Cases anlegen (Roundtrip CRUD) - [BE] Seed-Datensatz „Veranstaltung Neumarkt 2026“ (+ 12 Turniere)
- [BE] Repositories prüfen und Test-Cases anlegen (Roundtrip CRUD)
3. Identity & Profil (Verifikation) 3. Identity & Profil (Verifikation)
- [QA] E2E-Check „ZNS-Link“: Login → Profile → Satznummer verknüpfen → Refresh
- [FE] Validation/UX-Polish im `profile-feature` - [QA] E2E-Check „ZNS-Link“: Login → Profile → Satznummer verknüpfen → Refresh
- [FE] Validation/UX-Polish im `profile-feature`
4. Live-Ergebnisse Vision (Input sammeln) 4. Live-Ergebnisse Vision (Input sammeln)
- [Owner] Skizze/Mock für mobile Web-Ansicht (Zuschauer): Bewerb → Abteilungen → Live-Board
- [Owner] Skizze/Mock für mobile Web-Ansicht (Zuschauer): Bewerb → Abteilungen → Live-Board
--- ---
@@ -11,17 +11,17 @@ last_update: 2026-01-20
Angenommen Angenommen
## Kontext ## Kontext
Das Projekt "Meldestelle" setzt auf einen sehr modernen Technologie-Stack (Java 25, Kotlin 2.3.0, Spring Boot 3.5.9). Eine Analyse im Januar 2026 hat jedoch kritische Versionskonflikte aufgedeckt, die die Stabilität des Builds und der Laufzeitumgebung gefährden. Das Projekt "Meldestelle" setzt auf einen sehr modernen Technologie-Stack (Java 25, Kotlin 2.3.21, Spring Boot 3.5.9). Eine Analyse im Januar 2026 hat jedoch kritische Versionskonflikte aufgedeckt, die die Stabilität des Builds und der Laufzeitumgebung gefährden.
1. **Spring Cloud Konflikt:** Der Release Train `2025.1.0` (Oakwood) ist für Spring Boot 4.0 konzipiert und inkompatibel mit Spring Boot 3.5.9 (führt zu `NoSuchMethodError`). 1. **Spring Cloud Konflikt:** Der Release Train `2025.1.0` (Oakwood) ist für Spring Boot 4.0 konzipiert und inkompatibel mit Spring Boot 3.5.9 (führt zu `NoSuchMethodError`).
2. **Compose Multiplatform:** Version `1.9.3` führt zu Compiler-Crashes in Verbindung mit Kotlin 2.3.0. 2. **Compose Multiplatform:** Version `1.9.3` führt zu Compiler-Crashes in Verbindung mit Kotlin 2.3.21.
3. **Exposed:** Version `0.61.0` ist veraltet und inkompatibel mit Kotlin 2.3.0. 3. **Exposed:** Version `0.61.0` ist veraltet und inkompatibel mit Kotlin 2.3.21.
## Entscheidung ## Entscheidung
Wir führen folgende Korrekturen am Tech-Stack durch, um eine stabile "Best Compatibility List" zu etablieren: Wir führen folgende Korrekturen am Tech-Stack durch, um eine stabile "Best Compatibility List" zu etablieren:
1. **Spring Cloud Downgrade:** Wechsel auf Release Train `2025.0.1` (Northfields), der offiziell für Spring Boot 3.5.x freigegeben ist. 1. **Spring Cloud Downgrade:** Wechsel auf Release Train `2025.0.1` (Northfields), der offiziell für Spring Boot 3.5.x freigegeben ist.
2. **Compose Multiplatform Upgrade:** Wechsel auf `1.10.0-rc02` (oder stable), um volle Kotlin 2.3.0 Kompatibilität zu gewährleisten. 2. **Compose Multiplatform Upgrade:** Wechsel auf `1.10.0-rc02` (oder stable), um volle Kotlin 2.3.21 Kompatibilität zu gewährleisten.
3. **Exposed Upgrade:** Wechsel auf `1.0.0-rc-4` (oder neuer), um Bytecode-Inkompatibilitäten zu beheben. 3. **Exposed Upgrade:** Wechsel auf `1.0.0-rc-4` (oder neuer), um Bytecode-Inkompatibilitäten zu beheben.
4. **Micrometer Upgrade:** Explizites Setzen von Version `1.16.1` für verbesserten Java 25 (Virtual Threads) Support. 4. **Micrometer Upgrade:** Explizites Setzen von Version `1.16.1` für verbesserten Java 25 (Virtual Threads) Support.
@@ -29,7 +29,7 @@ Wir führen folgende Korrekturen am Tech-Stack durch, um eine stabile "Best Comp
### Positiv ### Positiv
* **Stabilität:** Der Build und die Application Context Initialisierung sind wieder stabil. * **Stabilität:** Der Build und die Application Context Initialisierung sind wieder stabil.
* **Zukunftssicherheit:** Wir nutzen weiterhin die neuesten Features von Java 25 und Kotlin 2.3.0, aber in einer validierten Kombination. * **Zukunftssicherheit:** Wir nutzen weiterhin die neuesten Features von Java 25 und Kotlin 2.3.21, aber in einer validierten Kombination.
* **Wartbarkeit:** Die `libs.versions.toml` spiegelt nun eine getestete Konfiguration wider. * **Wartbarkeit:** Die `libs.versions.toml` spiegelt nun eine getestete Konfiguration wider.
### Negativ ### Negativ
@@ -1,20 +1,33 @@
# ADR-0027: Netzwerk-Discovery & Interface-Binding # ADR-0027: Netzwerk-Discovery & Interface-Binding
## Status ## Status
In Prüfung (Wartet auf PoC)
Akzeptiert & Implementiert (05.05.2026)
## Kontext ## Kontext
Desktop-Rechner auf Turnieren sind oft mit mehreren Netzwerken gleichzeitig verbunden (z.B. LAN für das Turnier-Netzwerk, WLAN für Internet-Hotspot). Automatische Discovery-Dienste (JmDNS) wählen ohne explizite Konfiguration oft das falsche Interface, wodurch sich Clients und Master nicht finden.
Desktop-Rechner auf Turnieren sind oft mit mehreren Netzwerken gleichzeitig verbunden (z.B. LAN für das
Turnier-Netzwerk, WLAN für Internet-Hotspot). Automatische Discovery-Dienste (mDNS) wählen ohne explizite Konfiguration
oft ein Interface, das für die anderen Teilnehmer nicht erreichbar ist (Bridging-Probleme zwischen LAN und WLAN). Zudem
blockieren einige Router Multicast-Pakete zwischen WLAN und LAN-Segmenten.
## Entscheidung ## Entscheidung
Wir führen ein explizites Netzwerk-Management für die Initialisierung ein.
1. **Interface-Selektion:** Der Benutzer muss bei der technischen Initialisierung explizit wählen, über welches Netzwerk-Interface (IP-Adresse/Adapter) die App kommunizieren soll. Die UI zeigt hierfür benutzerfreundliche Namen (WLAN, Ethernet) an. Wir führen ein robustes, mehrstufiges Netzwerk-Management für die Initialisierung ein:
2. **Geführte Discovery:** Sobald ein Interface gewählt ist, startet ein "Radar-Modus". Dieser scannt aktiv via JmDNS nach vorhandenen Master-Geräten.
3. **Adaptive Rolle:** Findet die Discovery einen Master, wird dem Benutzer die Rolle "Client" vorgeschlagen. Die UI bleibt jedoch flexibel für manuelle Rollenwechsel. 1. **Multi-Interface Broadcast:** Der Master registriert seinen Dienst proaktiv auf **allen** verfügbaren
4. **Fokus-Management:** Nach Auswahl der Rolle wird der Fokus automatisch in das erste relevante Eingabefeld (Gerätename) gesetzt, um einen reibungslosen Workflow zu ermöglichen. Netzwerk-Interfaces (IPv4). Dies erhöht die Chance massiv, dass Clients in verschiedenen Segmenten (WLAN/LAN) den
Master finden.
2. **Interface-Selektion:** Der Benutzer kann weiterhin ein bevorzugtes Interface wählen. Die Master-Info-Card zeigt die
Erreichbarkeit transparent an.
3. **Manueller IP-Fallback:** Wenn mDNS fehlschlägt, kann die IP des Masters manuell eingegeben werden. Dies ist der "
Ultima-Ratio"-Weg für restriktive Netzwerke.
4. **Konnektivitäts-Check (Chat & Self-Test):** Nach dem Handshake wird ein Modal geöffnet, das einen automatischen
Ping-Pong Test durchführt und einen Test-Chat bietet. Dies verifiziert die reale Datenübertragung (Serialisierung,
WebSockets) noch vor Abschluss des Setups.
## Konsequenzen ## Konsequenzen
- Verhindert "Geistersuchen" im falschen Netzwerk.
- Erhöht die Benutzerfreundlichkeit durch automatische Vorschläge. - Deutlich höhere Stabilität in heterogenen Netzwerkumgebungen.
- Erfordert Zugriff auf System-Netzwerk-APIs in der Desktop-Shell. - Transparenteres Feedback für den Anwender bei Verbindungsproblemen.
- Der Chat dient als "Connectivity-Proof" für das Support-Personal vor Ort.
@@ -1,51 +0,0 @@
# 🤖 Konzept: Status-Automat für Nennungen & Zeitplan-Synchronisation
Dieses Dokument spezifiziert die Logik des Status-Automaten für Nennungen (Sprint C-1) und dessen Auswirkungen auf den dynamischen Zeitplan.
## 1. Status-Definitionen (NennStatusE)
Basierend auf `core-domain/Enums.kt`:
| Status | Bedeutung | Auswirkung auf Zeitplan |
| :--- | :--- | :--- |
| `EINGEGANGEN` | Nennung wurde erstellt (Initialzustand) | Belegt Zeitslot (basierend auf `reitdauerMinuten`) |
| `BESTAETIGT` | Meldestelle hat Nennung geprüft | Belegt Zeitslot |
| `NACHNENNUNG` | Nennung nach Nennschluss | Belegt Zeitslot (ggf. am Ende der Liste) |
| `TRANSFERIERT` | Nennung wurde auf anderes Paar übertragen | **Inaktiv** (Original-Eintrag wird durch neuen ersetzt) |
| `ZURUECKGEZOGEN`| Reiter hat abgemeldet (vor Startlistenerstellung) | **Inaktiv** (Slot wird frei) |
| `GESTARTET` | Paar ist in die Prüfung eingeritten | Startzeitpunkt fixiert, Folgestarts ggf. anpassen |
| `NICHT_ANGETRETEN`| Paar ist zum Startzeitpunkt nicht erschienen | **Zeitslot verfällt** oder Folgestarts rücken nach |
## 2. Status-Übergänge & Validierung
### 2.1 Gültige Übergänge (Beispiele)
- `EINGEGANGEN` -> `BESTAETIGT` (Normalfall)
- `EINGEGANGEN` -> `ZURUECKGEZOGEN` (Abmeldung)
- `BESTAETIGT` -> `TRANSFERIERT` (Reitertausch)
- `BESTAETIGT` -> `GESTARTET` (Während des Turniers)
### 2.2 Side-Effects (Side-Effect-Engine)
Wenn sich der Status einer Nennung ändert, müssen folgende Systeme informiert werden:
1. **Billing-Service:** Bei `ZURUECKGEZOGEN` ggf. Stornogebühren prüfen. Bei `TRANSFERIERT` Guthaben übertragen.
2. **Startlisten-Service:** Bei `ZURUECKGEZOGEN` nach Veröffentlichung der Startliste -> Eintrag als `istGestrichen = true` markieren.
3. **Zeitplan-Optimierung:** Bei `NICHT_ANGETRETEN` -> Alle folgenden Startzeiten rücken um `reitdauerMinuten` nach vorne (sofern im Kalender-Modus "Dynamisch" aktiv ist).
## 3. Dynamische Zeitplan-Anpassung (C-1 Extension)
Der `StartlistenService` muss eine Methode `aktualisiereZeitplanNachStatusAenderung` erhalten:
- **Szenario A (Nicht angetreten):** Wenn Nennung X `NICHT_ANGETRETEN` wird, rücken alle folgenden Nennungen in der Abteilung nach vorne.
- **Szenario B (Verspätung):** Wenn Nennung X `GESTARTET` wird, aber 2 Minuten später als geplant, verschieben sich alle Folgetermine um +2 Minuten (Kettenreaktion).
### Puffer-Regel (ÖTO-Konformität)
- Eine dynamische Verschiebung nach *vorne* darf nie dazu führen, dass ein Reiter vor seiner ursprünglich kommunizierten Startzeit (oder einem definierten Puffer-Zeitraum von z.B. 15 Minuten) starten muss, ohne dass dies explizit bestätigt wurde.
## 4. Implementierungs-Leitfaden für Backend (C-1)
1. Erweiterung von `NennungUseCases.statusAendern` um Aufrufe der Side-Effect-Handler.
2. Implementierung des `NennungStatusListener` in `entries-service`.
3. Anbindung an den `StartlistenService` zur Zeitre-Kalkulation.
---
**Status:** Entwurf (Lead Architect)
**Datum:** 11. April 2026
@@ -2,11 +2,12 @@
type: Reference type: Reference
status: ACTIVE status: ACTIVE
owner: Lead Architect & ÖTO/FEI Rulebook Expert owner: Lead Architect & ÖTO/FEI Rulebook Expert
last_update: 2026-04-05 last_update: 2026-06-15
sources: sources:
- ÖTO 2026, Abschnitt A I, § 2 & § 3 & § 4 - ÖTO 2026, Abschnitt A I, § 2 & § 3 & § 4
- Domain Workshop 2026-03-17 - Domain Workshop 2026-03-17
- Session 2026-03-24 (Architektur-Diskussion) - Session 2026-03-24 (Architektur-Diskussion)
- Sanierung 2026-06-15 (Reality-Reset)
--- ---
# Ubiquitous Language Offizielle Domänen-Terminologie # Ubiquitous Language Offizielle Domänen-Terminologie
@@ -146,7 +147,7 @@ Veranstalter (OEPS-Mitgliedsverein)
| **Sparte** | Die unterschiedlichen Arten von Turnieren oder Bewerben (z.B. Dressur = CDN, Springen = CSN). Bestimmt das anzuwendende Richtverfahren und das Regelwerk. | ÖTO § 2 Abs. 9, § 3 Abs. 2 | | **Sparte** | Die unterschiedlichen Arten von Turnieren oder Bewerben (z.B. Dressur = CDN, Springen = CSN). Bestimmt das anzuwendende Richtverfahren und das Regelwerk. | ÖTO § 2 Abs. 9, § 3 Abs. 2 |
| **Sperrliste** | Vom Verband geführte Liste von Personen oder Pferden, die aktuell nicht startberechtigt sind (meist wegen offener Zahlungen). | – | | **Sperrliste** | Vom Verband geführte Liste von Personen oder Pferden, die aktuell nicht startberechtigt sind (meist wegen offener Zahlungen). | – |
| **Sportförderbeitrag** | Gebühr, die **pro Start** anfällt (nicht pro Nennung!). Relevant bei Mehrfach-Starts. | ÖTO Gebührenordnung | | **Sportförderbeitrag** | Gebühr, die **pro Start** anfällt (nicht pro Nennung!). Relevant bei Mehrfach-Starts. | ÖTO Gebührenordnung |
| **Stammdaten** | (Früher: Akteur-Context). Die zentrale Library of Truth (`master-data-context`) für alle statischen Informationen: Personen, Pferde, Vereine, sowie das ÖTO-Regelwerk (Richtverfahren, Paragraphen, Gebührensätze). | | | **Stammdaten** | Die zentrale Library of Truth (`masterdata-context`) für alle statischen Informationen: Personen, Pferde, Vereine, sowie das ÖTO-Regelwerk (Richtverfahren, Paragraphen, Gebührensätze). | |
| **Startkarte** | Nachweis, dass die Jahresgebühr für die Lizenz bezahlt wurde. Ohne aktive Startkarte ist national kein Start möglich. | ÖTO Teilnahmeberechtigung | | **Startkarte** | Nachweis, dass die Jahresgebühr für die Lizenz bezahlt wurde. Ohne aktive Startkarte ist national kein Start möglich. | ÖTO Teilnahmeberechtigung |
| **Startwunsch** | Präferenz eines Reiters bezüglich seiner Position in der Startliste (vorne/hinten). | Registration Context | | **Startwunsch** | Präferenz eines Reiters bezüglich seiner Position in der Startliste (vorne/hinten). | Registration Context |
@@ -188,7 +189,7 @@ Veranstalter (OEPS-Mitgliedsverein)
| Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` | | Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` |
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` | | Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
| Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-context` | | Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-context` |
| Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `actor-context` | | Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `masterdata-context` |
| Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` | | Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` |
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* | | Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
| Login, Rolle, Berechtigung | `identity-context` | | Login, Rolle, Berechtigung | `identity-context` |
@@ -222,7 +223,7 @@ Ein Reglement definiert typischerweise:
- Verschiedene Cups/Serien können **unterschiedliche Punktesysteme** haben → das Berechnungsmodell muss pluggable sein. - Verschiedene Cups/Serien können **unterschiedliche Punktesysteme** haben → das Berechnungsmodell muss pluggable sein.
- Die **Paar-Bindung** (Punkte an Reiter+Pferd vs. nur Reiter) ist eine kritische Designentscheidung pro Reglement. - Die **Paar-Bindung** (Punkte an Reiter+Pferd vs. nur Reiter) ist eine kritische Designentscheidung pro Reglement.
- Referenz-Dokument: [ - Referenz-Dokument: [
`docs/03_Domain/02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md`](../02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md) `docs/02_Domain/02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md`](../02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md)
--- ---
@@ -241,4 +242,4 @@ Ein Reglement definiert typischerweise:
--- ---
*Erstellt: 2026-03-24 | Autoren: Lead Architect, ÖTO/FEI Rulebook Expert, Curator* *Erstellt: 2026-03-24 | Autoren: Lead Architect, ÖTO/FEI Rulebook Expert, Curator*
*Basiert auf: ÖTO 2026 § 2, § 3, § 4 | Domain Workshop 2026-03-17 | Session 2026-03-24 | Update: 2026-04-05 (Verein-Renaming & Bereinigung)* *Basiert auf: ÖTO 2026 § 2, § 3, § 4 | Domain Workshop 2026-03-17 | Session 2026-03-24 | Update: 2026-06-15 (Reality-Reset & Alignment)*

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 325 KiB

Some files were not shown because too many files have changed in this diff Show More