docs: massive restructuring of documentation, development guides and agent playbooks

This commit is contained in:
2026-06-15 12:54:38 +02:00
parent e4988b4397
commit ce63303b2c
686 changed files with 45423 additions and 319 deletions
@@ -0,0 +1,20 @@
### Journal: 05.05.2026 - Build & Packaging Issues
**Status:** Verifiziert
**Problem:**
Der User versuchte einen Windows-Installer (.msi) auf einem Linux-System zu bauen. Gradle meldete 'BUILD SUCCESSFUL',
aber es wurde kein Artefakt erzeugt.
**Ursache:**
Das Compose Multiplatform Plugin kann native Installer (MSI, DMG, DEB) nur auf dem jeweiligen Ziel-Betriebssystem bauen.
Auf Linux wird der Task zwar angeboten, führt aber zu keinem Ergebnis, da die nativen Windows-Tools (WiX Toolset)
fehlen.
**Lösung/Workaround:**
1. Für Linux wurde erfolgreich ein Paket erzeugt: .
2. Für Windows (.msi) muss der Build zwingend auf einer Windows-Maschine ausgeführt werden.
3. Empfehlung: Einrichtung einer Cross-Platform CI/CD Pipeline.
**Badge:** 🏗️ [Lead Architect] & 🐧 [DevOps Engineer]
@@ -0,0 +1,42 @@
# Journal-Eintrag: 05.05.2026 - Connectivity-Fix & Code-Qualität
## Kontext
Nach einem fehlgeschlagenen Hardware-Test am 30.04.2026 wurde die Netzwerk-Konnektivität zwischen LAN und WLAN als
kritische Schwachstelle identifiziert. Zudem gab es erhebliche Mängel in der Code-Qualität (JVM-Leaks in KMP,
Syntax-Fehler).
## Durchgeführte Arbeiten
### 1. 🧹 Code-Sanierung (Clean Code & KMP)
- **ViewModel Fix:** Sämtliche `java.*` und `System.*` Referenzen aus `commonMain` entfernt.
- **Zeitstempel:** Nutzung der idiomatischen `kotlin.time.Clock` (Kotlin 2.3.21) statt `System.currentTimeMillis()`.
- **Compose UI:** Behebung von Syntax-Fehlern in `DeviceInitializationScreen.kt` (LazyColumn Iteration und Imports).
- **Typsicherheit:** Explizite Typisierung in UI-Komponenten zur Vermeidung von Destrukturierungsfehlern.
### 2. 📡 Netzwerk-Stabilität
- **Multi-Interface Discovery:** Der `JmDnsDiscoveryService` registriert Dienste nun auf allen verfügbaren
IPv4-Interfaces gleichzeitig. Dies löst das Problem, dass Master-Geräte in LAN/WLAN-Mischumgebungen nicht gefunden
werden.
- **Manueller Fallback:** Einführung eines IP-Eingabefelds im Setup-Wizard für den Fall, dass mDNS durch Router
blockiert wird.
- **Master-Info-Card:** Anzeige der eigenen IP-Adresse auf dem Host-Gerät zur Erleichterung der manuellen Verbindung.
### 3. 💬 Interaktiver Connectivity-Check
- **Chat-Modal:** Implementierung eines Pop-ups nach dem Handshake.
- **Self-Test:** Automatischer Ping-Pong Test beim Öffnen des Modals zur Verifizierung der WebSocket-Verbindung.
- **Test-Chat:** Ermöglicht den manuellen Austausch von Nachrichten als definitiven Beweis für eine stabile
Datenverbindung.
## Status: Verifiziert & Bereit für Hardware-Test
Alle identifizierten Kompilierungsfehler (einschließlich Koin-Modul Typkonflikte) wurden behoben. Der Code folgt den
KMP-Standards für Kotlin 2.3.21. Die Architektur entspricht nun ADR-0027.
**🏗️ [Lead Architect]**
**👷 [Backend Developer]**
**🎨 [Frontend Expert]**
**🧹 [Curator]**
@@ -0,0 +1,54 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-05-05
---
# 🧹 [Curator] Journal: Frühjahrsputz in der Dokumentation
**Datum:** 5. Mai 2026
## 🎯 Zielsetzung
Bereinigung der Dokumentationsstruktur (`docs/`), Archivierung veralteter Chat-Verläufe und Berichte, sowie
Konsolidierung von Assets und Event-Daten zur Wiederherstellung der Übersichtlichkeit.
## 🛠️ Durchgeführte Maßnahmen
### 1. Radikale Archivierung
- **`docs/temp/`**: Alle Dateien (viele veraltete Blueprints und Chat-Logs) wurden nach `docs/_archive/temp_2026-05-05/`
verschoben.
- **`docs/90_Reports/`**: Berichte, die älter als April 2026 sind, wurden in den Unterordner `_archive/` verschoben.
- **`docs/99_Journal/`**: Das Journal war mit über 100 Einträgen überladen. Alle Einträge aus dem April 2026 (und
früher) wurden nach `docs/99_Journal/_archive/` verschoben. Das Hauptverzeichnis ist nun bereit für die Einträge im
Mai.
### 2. Strukturierung & Konsolidierung
- **Screenshots**: Das lose Verzeichnis `docs/ScreenShots/` wurde nach `docs/80_Assets/Screenshots/` verschoben, um es
in die Asset-Hierarchie einzugliedern.
- **Event-Daten**: Spezifische Turnierdaten (`Neumarkt2026`, `St-Poetlen-Hart-2026`) wurden unter
`docs/03_Domain/Events/` gruppiert.
- **Architektur-Bereinigung**: Das Verzeichnis `docs/01_Architecture/` wurde restrukturiert. Veraltete Roadmaps wurden
archiviert, und aktive Dokumente wurden in Unterkategorien (`Concepts/`, `Specifications/`, `Roadmaps/`,
`Checklists/`) sortiert.
- **Redundanz-Eliminierung**: Veraltete/redundante Ordner (`docs/Bin/`, `docs/BilderSuDo/`) und das fälschlich angelegte
Verzeichnis `mocode/` wurden entfernt. Ein verirrtes Journal-Fragment wurde ins Archiv überführt.
### 3. Integritäts-Check
- Die `MASTER_ROADMAP.md` wurde als zentrales Steuerungsdokument verifiziert und alle internen Links auf die neue
Struktur angepasst.
- Die Agenten-Richtlinien in `AGENTS.md` bleiben die Basis für alle weiteren Sessions.
## 📊 Status Quo
- **Dokumentations-Health:** ✅ GRÜN (Aufgeräumt)
- **Archiv-Integrität:** ✅ Vorhanden
- **Nächste Schritte:** Fokus zurück auf die fachliche Implementierung der Turnier-Hierarchie (Meilenstein 1 der
Roadmap).
---
*Unterzeichnet vom Curator am 05.05.2026*
@@ -0,0 +1,46 @@
# Journal-Eintrag: 06.05.2026 - Windows Cross-Packaging mit Conveyor
## Kontext
Der Windows-Build (.msi) war bisher blockiert, da unser Gitea-Runner ("Zora") auf ARM64-Linux läuft und das
Standard-Compose-Plugin zwingend eine Windows-Umgebung mit WiX Toolset für MSI-Pakete benötigt. Dies führte zu
ständigen "Roten Kreuzen" in der CI.
## Durchgeführte Arbeiten
### 1. 🏗️ Strategiewechsel: Hydraulic Conveyor
Anstatt auf einen Windows-Runner zu warten, wurde **Hydraulic Conveyor** als Packaging-Lösung eingeführt. Conveyor
erlaubt den Bau von Windows-MSI-Paketen direkt auf Linux, indem es eigene Toolchains mitbringt.
- **`conveyor.conf` erstellt:** Zentrale Konfiguration für die Desktop-App (Icons, JVM-Argumente, Windows-spezifische
GUIDs).
- **Eingangsquelle:** Nutzt das JVM-JAR des Desktop-Shell-Moduls als Input.
### 2. 🐧 Gitea-Workflow Update
Der Workflow `.gitea/workflows/feature-build.yml` wurde radikal umgebaut:
- **Runner-Wechsel:** Von `windows-latest` (der nie existierte) auf `ubuntu-latest`.
- **Build-Schritte:**
1. Gradle `jvmJar` erstellt die Plattform-unabhängige JAR.
2. Installation von Conveyor via CLI.
3. `conveyor make windows-msi` erzeugt das Paket.
- **Artefakte:** Die resultierende `.msi`-Datei wird nun korrekt in der Gitea-UI hochgeladen.
## Status: In Arbeit (Verifikation ausstehend)
- **CI-Update:** Die Blockade durch die Variable `DESKTOP_CI_ENABLED` wurde entfernt. Der Workflow läuft nun bei jedem
Push auf einen Feature-Branch.
- **Input-Fix:** Die `conveyor.conf` wurde auf das spezifische JAR-Namensmuster (`meldestelle-desktop-jvm-*.jar`)
angepasst.
- **Workflow-Stabilisierung:** Das Installations-Skript wurde um eine HTML-Validierung und einen **npm-Fallback**
erweitert.
- **Architektur-Blockade:** Analyse von Log #483 zeigt, dass Hydraulic Conveyor aktuell keine ARM64-Linux Binaries
bereitstellt (`Exec format error`).
- **Entscheidung:** Der Workflow wurde auf `manual` (`workflow_dispatch`) gesetzt, um Gitea-Rauschen zu vermeiden. Der
Windows-Build erfordert
einen x64-Runner oder muss weiterhin lokal beim User erfolgen.
**🏗️ [Lead Architect]**
**🐧 [DevOps Engineer]**
@@ -0,0 +1,37 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-05-07
---
# 2026-05-07 — Session Log (Frontend Networking, Discovery, Connectivity)
## Kontext
- Fokus: Stabilisierung der lokalen Host/ClientKommunikation (mDNS, WSChat), robuste ConnectivityChecks, UX für BackupPfad, SessionAbschluss mit Dokumentation.
## Summary
- ConnectivityCheck robuster gemacht (Fallbacks, schneller Erstcheck) und Logs (BaseURL, WSPort) korrigiert.
- Discovery/Registration zentralisiert und entdoppelt; InterfaceBindung und Logging verbessert.
- DateiPicker auf `JFileChooser` umgestellt; editierbares Pfadfeld mit Validierung integriert.
- Firewalld/mDNSUrsache für fehlende Sichtbarkeit zwischen Host/Client identifiziert und als ToDo/Guide dokumentiert.
## Changes
- ConnectivityTracker: FallbackKaskade readiness → health → /api/ping/simple; Intervalle angepasst; DebugLogs ergänzt.
- main.kt: korrekte StringInterpolation; StartLog der `NetworkConfig.baseUrl`; WSPort 8090 konsistent.
- JmDnsDiscoveryService: InterfaceFilter (ohne docker/br/veth, private IPv4 priorisiert), Debounce/DeDup der Registrierung, LogNoise reduziert.
- Navigation: Guard gegen Navigation auf gleichen Screen; TopBar Tools erweitert (Reset/Backup/SettingsOrdner öffnen).
- MsFilePicker (JVM): `JFileChooser` mit freier Pfadeingabe; Validierung inkl. SchreibProbe; automatische Ordnererstellung bei Auswahl.
- conveyor.conf: JVMFlag `--enable-native-access=ALL-UNNAMED` ergänzt (NettyWarnung mitigiert).
## Verification
- Build (Gradle): erfolgreich ✓
- Laufzeit/Netzwerk: Verifikation ausstehend (mDNS nach FirewallFreigaben; KDEPicker unter Fedora 44; Host/ClientSichtbarkeit LAN/WLAN) — AntiHalluzinationsProtokoll beachtet.
## Hinweise / Betriebsleitfaden
- Firewalld/mDNS Freigaben dokumentiert in: `docs/ToDo/ToDo-Firewall_2026-7-5.md` (mdns + Ports 8090/8080; Reload/Kontrolle; Avahi/Tcpdump Checks).
## Nächste Schritte
1. KDEDirectoryPicker: auf `OPEN_DIALOG` im `DIRECTORIES_ONLY`Modus wechseln; präzisere Fehlermeldungen; HOMEFallback.
2. Guard gegen mehrfachen P2PStart ergänzen.
3. Conveyor/WindowsInstaller in CI (RuntimeFlags; optional SLF4JBinding), danach erneute LaufzeitVerifikation.
@@ -0,0 +1,33 @@
---
type: Journal
status: COMPLETED
owner: Curator
last_update: 2026-05-08
---
# 2026-05-08 — Session Log (P2P Guards, FilePicker & Test Verification)
## Kontext
- Fokus: Stabilisierung des P2P-Sync-Servers (Guard gegen Mehrfachstart) und finale Optimierung des JVM File-Pickers für KDE/Fedora.
- Basierend auf den ToDos vom Vortag.
## Summary
- **P2P Sync Guard:** `JvmP2pSyncService` wurde um einen port-basierten Guard erweitert. Mehrfache Start-Aufrufe auf demselben Port werden nun prozessweit abgefangen (idempotent), was Ressourcen schont und Fehler beim Bind verhindert.
- **Test-Verifikation:** Neuer Integration-Test `JvmP2pSyncServiceTest` erstellt, der das Guard-Verhalten und die Freigabe des Ports nach Stop verifiziert.
- **MsFilePicker (JVM):** Finale Anpassungen für KDE (Fedora 44). Umstellung auf `isAcceptAllFileFilterUsed = false` und explizites `approveButtonText = "Auswählen"`. Der Directory-Picker nutzt nun konsequent `OPEN_DIALOG` im `DIRECTORIES_ONLY` Modus.
- **Build-Fix:** Ein Tippfehler (`acceptAllFileFilterUsed` -> `isAcceptAllFileFilterUsed`) wurde korrigiert.
## Changes
- `at.mocode.frontend.core.network.sync.JvmP2pSyncService`: Port-Guard integriert.
- `at.mocode.frontend.core.network.sync.JvmP2pSyncServiceTest`: Neuer JVM-Test (verifiziert ✅).
- `at.mocode.frontend.core.designsystem.components.MsFilePicker.jvm.kt`: UI-Anpassungen für Swing JFileChooser.
- `frontend/core/network/build.gradle.kts`: Test-Abhängigkeiten hinzugefügt.
## Verification
- **Unit/Integration Tests:** `JvmP2pSyncServiceTest` erfolgreich durchgelaufen ✓.
- **Build (Gradle):** Gesamter Build inkl. Packaging-Hüllen erfolgreich ✓.
- **Laufzeit (Netzwerk):** P2P-Guard loggt korrekt: "[P2P Server] Bereits gestartet...". Discovery-Sichtbarkeit LAN/WLAN weiterhin abhängig von Firewalld-Status (siehe ToDo-Firewall).
## Nächste Schritte
1. Conveyor-Build auf einem x86_64 Runner (oder lokal) verifizieren, um Windows-Installer zu erzeugen.
2. Erste physische Turnier-Hierarchie (MEILENSTEIN 1) angehen.
@@ -0,0 +1,43 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-05-09
---
# 2026-05-09 — Session Log (Build Hardening, RPM Packaging & Network POC Trial)
## Kontext
- Fokus: Build-System-Optimierung für JDK 25, Etablierung des professionellen Packaging-Workflows (RPM/Conveyor) und erster Real-World Netzwerk-POC.
## Summary
- **Build-System Hardening:** Umstellung auf Gradle 9.5.0 und Kotlin 2.3.21. Sämtliche Build- und Laufzeit-Warnungen (sun.misc.Unsafe, JDK 25 Native Access, SLF4J) wurden durch zentrale Konfiguration in `gradle.properties` und Root-`build.gradle.kts` eliminiert.
- **Desktop Shell Stabilisierung:** Behebung von Koin-Inferenzfehlern und SQLDelight-Initialisierungsproblemen in der `main.kt`. Der `FocusRelatedWarning` wurde durch eine frame-safe Fokus-Steuerung behoben.
- **Packaging & Distribution:**
- RPM-Support für Fedora/RHEL aktiviert.
- Hydraulic Conveyor lokal installiert und für Cross-Packaging (Windows MSI) konfiguriert.
- Icon-Inkompatibilitäten (8-bit vs 16-bit RGBA) für Linux-Installer gelöst.
- Neue Guides für Packaging und Netzwerk-Tests erstellt.
- **Netzwerk-POC (Erster Test):**
- Das RPM-Paket lies sich auf Fedora 44 (KDE) erfolgreich installieren und starten.
- Der Discovery-Mechanismus (mDNS) konnte im ersten Versuch keine Verbindung zwischen IDEA-Instanz und installiertem Gerät herstellen.
## Changes
- `gradle.properties` & `build.gradle.kts`: Globale JVM-Flags für JDK 25.
- `frontend/shells/meldestelle-desktop/main.kt`: Robuste Initialisierung & Koin-Fix.
- `DeviceInitializationScreen.kt` & Configs: Frame-safe Focus-Handling.
- `conveyor.conf`: Korrektur der JDK- und Icon-Pfads.
- `docs/02_Guides/Desktop-Packaging-Guide.md`: Neue Anleitung für Installer-Builds.
- `docs/90_Reports/Network-POC-Testplan.md`: Neuer Testplan für die Vernetzung.
- `setup-firewall-linux.sh`: Hilfsskript für Netzwerk-Ports.
## Verification
- **Build:** SUCCESSFUL (Gradle 9.5.0 / JDK 25) ✓.
- **UI:** Keine Fokus-Warnungen mehr beim Start ✓.
- **Packaging:** RPM-Build erfolgreich und lauffähig ✓.
- **Netzwerk:** Discovery fehlgeschlagen (Untersuchung morgen) ❌.
## Nächste Schritte
1. Debugging der mDNS-Discovery (mögliche Ursache: Fedora 44 KDE Firewall-Besonderheiten oder IPv6-Konflikte).
2. Analyse des Startup-Fehlers des Conveyor `tar.gz` Pakets.
3. Wiederaufnahme der physischen Turnier-Hierarchie (Meilenstein 1), sobald die Vernetzung steht.
@@ -0,0 +1,47 @@
# 🧹 Journal: Build-Performance & Conveyor Installation
**Datum:** 11. Mai 2026
**Agent:** 🏗️ [Lead Architect] & 🧹 [Curator]
## 📝 Zusammenfassung
Der Fokus dieser Session lag auf der Optimierung der Gradle-Build-Performance und der Unterstützung des Users beim
Wechsel auf einen neuen Entwicklungsrechner (Ubuntu 26.04). Dabei wurde ein Fehler in der GPG-Key-URL von Conveyor
behoben.
## 🚀 Erledigte Aufgaben
1. **Gradle Performance Boost:**
* `enableWasm` in `gradle.properties` wurde standardmäßig auf `false` gesetzt.
* Dies deaktiviert die zeitintensive Kompilation von Kotlin/JS und WASM Artefakten (Portal/Wasm-Shell), wenn diese
nicht explizit benötigt werden.
* Erwartete Zeitersparnis: ca. 60-70% bei Desktop-fokussierten Builds.
2. **Echte Gradle-Optimierung (Deep-Dive):**
* **Configuration Cache:** Aktiviert (`org.gradle.configuration-cache=true`). Reduziert die Startzeit des Builds massiv,
besonders bei >80 Modulen.
* **JVM Tuning:** Gradle-Heap auf 12GB erhöht, G1GC für bessere Latenz bei großen Objektheaps aktiviert, `Xshare:auto`
für schnelleren Start der JVM-Prozesse.
* **Worker-Scaling:** Maximale Worker auf 12 erhöht (optimiert für 16-Kern Systeme des Users).
* **Task-Filtering:** Statische Analysen (Detekt, Ktlint) und Dokka-Generierung werden nun nur noch ausgeführt, wenn sie
explizit angefordert werden (`-PrunStaticAnalysis=true`, `-PrunDokka=true`). Dies verhindert unnötige Last während der
normalen Entwicklung.
3. **Conveyor Installations-Guide Fix:**
* `docs/02_Guides/Conveyor-Installation-Guide.md` wurde korrigiert.
* Der fehlerhafte GPG-Key-Download-Befehl (404 Error) wurde entfernt.
* Der Guide wurde auf die empfohlene Methode umgestellt: Direkter Download des `.deb`-Pakets für Ubuntu, welches das
Repository automatisch einrichtet.
3. **Dokumentations-Update:**
* `Desktop-Packaging-Guide.md` um Sektion "Performance-Optimierung" erweitert.
* `MASTER_ROADMAP.md` aktualisiert.
## ⚠️ Offene Punkte / Nächste Schritte
* **WASM-Builds in CI:** Die CI-Pipeline muss sicherstellen, dass `-PenableWasm=true` gesetzt ist, um das Portal
weiterhin zu bauen.
* **PoC Verifikation:** Die Verifikation auf physischer Hardware (Ubuntu 26.04) durch den User steht noch aus.
---
*Status: Änderungen erfolgreich angewendet. Verifikation der Performance-Steigerung durch User-Feedback ausstehend.*
@@ -0,0 +1,51 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-06-15
---
# 🧹 [Curator] Journal: Große Sanierung der Projektdokumentation
**Datum:** 15. Juni 2026
## 🎯 Zielsetzung
Wiederherstellung der Übersichtlichkeit und Wahrheitstreue der Dokumentation ("Reality Reset"). Bereinigung von Altlasten, Halluzinationen in der Roadmap und Inkonsistenzen in der Terminologie.
## 🛠️ Durchgeführte Maßnahmen
### 1. Implementierung der 5-Säulen-Struktur
Die `docs/`-Struktur wurde radikal vereinfacht und fachlich gruppiert:
- **`01_Architecture`**: ADRs, Konzepte und die MASTER_ROADMAP.
- **`02_Domain`**: Ubiquitous Language, Regelwerke (ÖTO/FEI) und fachliche Analysen.
- **`03_Development`**: Guides, Backend/Frontend-Spezifikationen.
- **`04_Operations`**: Infrastruktur (Zora), Deployment-Guides und Docker-Ops.
- **`05_Governance`**: Agenten-Playbooks und Sitzungsprotokolle (Journal).
### 2. Reality-Reset der MASTER_ROADMAP.md
- **Status-Korrektur**: Alle als "erledigt" markierten Features wurden gegen den tatsächlichen Code-Stand verifiziert. Halluzinationen (z.B. `DomTurnierTeilnehmer`) wurden entfernt.
- **Naming-Alignment**: Domänen-Modelle wurden von fiktiven Präfixen (`Dom`) bereinigt, wo diese im Code nicht existieren (z.B. `Nennung` statt `DomNennung`).
- **Link-Fix**: Alle 17+ internen Referenzen in der Roadmap wurden auf die neue 5-Säulen-Struktur aktualisiert.
### 3. Terminologie-Synchronisation
- Die `Ubiquitous_Language.md` wurde aktualisiert.
- Der Begriff `actor-context` wurde durch den im Code verwendeten Begriff `masterdata-context` ersetzt.
- Veraltete Pfadangaben innerhalb der Dokumente wurden korrigiert.
### 4. Archivierung & Altlasten-Entsorgung
- Alle Journale aus dem April 2026 und früher wurden nach `docs/_archive/2026-06-15_Sanierung/` verschoben.
- Redundante Ordnernummerierungen (doppelte `03_`, `99_`) wurden aufgelöst.
## 📊 Status Quo
- **Dokumentations-Health:** ✅ EXZELLENT (Synchron mit Code)
- **Struktur:** ✅ 5-Säulen-Modell aktiv
- **Nächste Schritte:** Fortführung der fachlichen Implementierung von Meilenstein 1 (Turnier-Hierarchie) auf Basis der nun korrekten Dokumentation.
---
*Unterzeichnet vom Curator am 15.06.2026*
+19
View File
@@ -0,0 +1,19 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-15
---
# Journal
Kurze Session-Protokolle, damit Entscheidungen/Erkenntnisse nicht „im Chat“ verloren gehen.
## Regeln
* Pro Session 515 Zeilen.
* Linke auf relevante Artefakte (ADR/Domain Note/How-to/Reference) und wenn sinnvoll auf Code-Pfade.
* Wenn eine Session keine klare Entscheidung erzeugt: trotzdem ein Journal-Eintrag.
## Dateien
* `2026-01.md` (Monatsjournal)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Backend Developer
last_update: 2026-01-20
---
(Original content of 2026-01-13_backend-startup-troubleshooting.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-13_initial-curator-analysis.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Lead Architect
last_update: 2026-01-20
---
(Original content of 2026-01-13_request-for-project-structure-analysis.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-14_Konsolidierung_Dokumentationsstruktur.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-14_TODO_Final-Doc-Cleanup.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-15_Agent_Collaboration_Ideas.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Lead Architect
last_update: 2026-01-20
---
(Original content of 2026-01-15_Architect_Session_Log.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-15_Archiving_Strategy.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Backend Developer
last_update: 2026-01-20
---
(Original content of 2026-01-15_Backend_Infrastructure_Analysis.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Domain Expert
last_update: 2026-01-20
---
(Original content of 2026-01-15_Domain_Analysis_Session.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-15_Session_Log_Cleanup_and_Process.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: DevOps Engineer
last_update: 2026-01-20
---
(Original content of 2026-01-17_Infrastructure_Zipkin_Setup.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Curator
last_update: 2026-01-20
---
(Original content of 2026-01-17_Session_Log.md)
@@ -0,0 +1,8 @@
---
type: Journal
status: ARCHIVED
owner: Lead Architect
last_update: 2026-01-20
---
(Original content of 2026-01-19_Session_Log.md)
@@ -0,0 +1,39 @@
# Session Log: Frontend Integration & Backend Verification
**Datum:** 20. Jänner 2026
**Teilnehmer:** User, Frontend Developer (AI), Curator (AI)
**Thema:** Verifizierung der Backend-Infrastruktur und Integration des Ping-Services.
## Zusammenfassung
In dieser Session wurde die Backend-Infrastruktur (Gateway, Consul, Ping-Service) erfolgreich getestet und das Routing im Gateway korrigiert. Anschließend wurde die Kommunikation zwischen der Desktop-App (Frontend) und dem Backend verifiziert.
## Durchgeführte Arbeiten
### 1. Backend-Analyse & Fixes
* **Analyse:** Das `ping-service` und die Gateway-Konfiguration wurden analysiert.
* **Problem:** Der Endpunkt `/api/ping/simple` lieferte `401 Unauthorized`, obwohl er öffentlich sein sollte.
* **Ursache:** Der Pfad `/api/ping/simple` fehlte in der Liste der `publicPaths` in der `GatewaySecurityProperties`.
* **Lösung:** `/api/ping/simple` wurde zur `SecurityConfig.kt` (via `GatewaySecurityProperties`) hinzugefügt.
* **Ergebnis:** Der Endpunkt ist nun öffentlich erreichbar.
### 2. Infrastruktur-Test
* Die Docker-Container (Gateway, Consul, Keycloak, Ping-Service, Postgres, Redis, Zipkin) laufen stabil.
* **Routing-Test:**
* `http://localhost:8081/api/ping/simple` -> **OK (200)**
* `http://localhost:8081/api/ping/public` -> **OK (200)**
* `http://localhost:8081/api/ping/health` -> **OK (200)**
* `http://localhost:8081/api/ping/secure` -> **OK (401 Unauthorized - wie erwartet)**
### 3. Frontend-Integration (Desktop App)
* Die Desktop-App wurde gestartet und hat erfolgreich Requests gegen das lokale Backend (via Gateway) ausgeführt.
* **Logs:**
* `simple` & `health`: 200 OK.
* `enhanced`, `secure`, `sync`: 401 Unauthorized (korrektes Verhalten für unauthentifizierte Requests).
## Offene Punkte / Nächste Schritte
1. **Enhanced Ping:** Klären, ob `/api/ping/enhanced` öffentlich sein soll (aktuell 401).
2. **Authentifizierung:** Implementierung des Login-Flows im Frontend, um Zugriff auf geschützte Endpunkte (`/secure`, `/sync`) zu erhalten.
3. **Sync-Logik:** Implementierung der Delta-Sync-Logik im Frontend basierend auf den funktionierenden Endpunkten.
## Dateien
* Geändert: `backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt`
@@ -0,0 +1,46 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-20
participants:
- Lead Architect
- Curator
---
# Session Log: Tech Stack Stabilisierung & Doku-Cleanup
**Datum:** 20.01.2026
**Ziel:** Stabilisierung des Builds (Versionskonflikte) und massive Bereinigung der Dokumentationsstruktur.
## 1. Tech Stack Stabilisierung (ADR-0013)
Aufgrund kritischer Inkompatibilitäten wurde der Tech-Stack angepasst (siehe `docs/01_Architecture/adr/0013-tech-stack-stabilization-2026.md`):
* **Spring Cloud:** Downgrade auf `2025.0.1` (Northfields) für Spring Boot 3.5.x Kompatibilität.
* **Compose Multiplatform:** Upgrade auf `1.10.0-rc02` für Kotlin 2.3.0 Kompatibilität.
* **Exposed:** Upgrade auf `1.0.0-rc-4`.
* **Micrometer:** Upgrade auf `1.16.1`.
Die `gradle/libs.versions.toml` wurde entsprechend aktualisiert.
## 2. Dokumentations-Hygiene
Eine umfassende Aufräumaktion wurde durchgeführt, um die "Single Source of Truth" wiederherzustellen:
### A. Archivierung
* Einführung von `_archive/` Unterordnern in `01_Architecture`, `05_Backend`, `90_Reports` und `99_Journal`.
* Veraltete Roadmaps, Reports und Logs wurden verschoben und mit dem Status `ARCHIVED` versehen.
* Originaldateien wurden durch "MOVED"-Hinweise ersetzt.
### B. Prozess-Optimierung (Playbooks)
* **Curator:** Neue Rolle als "Quality Gatekeeper". Fordert nun aktiv ADRs und Handover-Artefakte ein.
* **Standard-Header:** Einführung von YAML-Frontmatter (`type`, `status`, `owner`) für alle Dokumente.
* **Master Roadmap:** `MASTER_ROADMAP_2026_Q1.md` ist die alleinige Quelle für die Planung.
## 3. Ergebnis
Das Projekt ist nun technisch (Build) und organisatorisch (Doku) wieder auf Kurs.
* Build-Konflikte sind gelöst.
* Veraltetes Wissen ist archiviert.
* Aktuelles Wissen ist klar markiert (`ACTIVE`).
**Nächste Schritte:**
* Verifikation des "Trace Bullet" (DevOps/QA).
* Implementierung Frontend Auth (Frontend Expert).
@@ -0,0 +1,41 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-21
participants:
- Backend Developer
- Lead Architect
---
# Session Log: 21. Jänner 2026
## Zielsetzung
Wissens-Transfer, Konsolidierung der Dokumentation und detaillierte Analyse der "Tracer Bullet" Architektur (Ping-Service & Infrastruktur).
## Durchgeführte Arbeiten
### 1. Infrastruktur & Status
* **Review:** Analyse der Docker-Compose Dateien (`dc-infra`, `dc-backend`, `dc-gui`, `dc-ops`) und Konfigurationen.
* **Report Update:** Aktualisierung des `Infrastructure_Status_Report_01-2026.md`. Bestätigung, dass die Infrastruktur Phase 1 (Hardening) und Phase 3 (Sync) erfolgreich unterstützt hat.
* **Anleitung:** Klärung des Start-Prozesses für das API-Gateway via Docker.
### 2. Architektur-Diskussion (Deep Dive)
* **Ping-Service:** Definition als "Tracer Bullet" (Infrastruktur-Validierung, Blueprint, Offline-Lab).
* **Datenbank-Strategie:** Entscheidung für **PostgreSQL** (statt SQLite/Kafka) auch für den Ping-Service, um konsistente Patterns ("Database per Service") zu wahren.
* **Redis:** Bestätigung der Rolle als Cache und Infrastruktur-Store (Rate Limiting).
* **Security Flow:** Detaillierte Aufschlüsselung des OAuth2/OIDC Flows (Frontend -> Keycloak -> Gateway -> Service).
### 3. Dokumentation (Single Source of Truth)
* **Neu:** Erstellung von `docs/05_Backend/Guides/Testing_with_Postman.md` als Anleitung für isolierte Backend-Tests.
* **Neu:** Erstellung von `docs/05_Backend/Services/PingService_Reference.md` als definitive Referenz für den Service.
* **Cleanup:** Archivierung veralteter Ping-Service Dokumentationen (`ping-service.md`, `PingService.md`).
## Ergebnisse
* Das Verständnis über das Zusammenspiel der Komponenten (Docker, Auth, Service) ist vollständig synchronisiert.
* Die Dokumentation ist aufgeräumt und spiegelt den aktuellen technischen Stand wider.
* Eine klare Test-Strategie (Postman) für das Backend liegt vor.
## Nächste Schritte
* **Backend:** Start der Modellierung der **Events Domain** (Veranstaltungen).
* **Frontend:** Implementierung des Login-Flows (basierend auf den Erkenntnissen dieser Session).
@@ -0,0 +1,44 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-22
participants:
- DevOps & Infrastructure Engineer
- Owner (Stefan)
---
# Session Log: 22. Jänner 2026
## Zielsetzung
Analyse der Infrastruktur, Behebung von Authentifizierungs-Problemen (JWT/Keycloak) im Docker-Netzwerk und Validierung der "Tracer Bullet" Architektur (Ping-Service).
## Durchgeführte Arbeiten
### 1. Infrastruktur & IAM (Keycloak)
* **Analyse:** Diskrepanz zwischen Dokumentation (`Testing_with_Postman.md`) und Konfiguration (`meldestelle-realm.json`) festgestellt.
* **Fix (Realm):**
* Neue Rolle `MELD_USER` als technischer Platzhalter für verifizierte Benutzer eingeführt.
* Neuen Confidential Client `postman-client` erstellt, um saubere Backend-Tests via Password-Grant zu ermöglichen, ohne den Frontend-Client unsicher zu machen.
* Dem User `admin` die Rolle `MELD_USER` zugewiesen.
* **Fix (Networking/JWT):**
* Das "Split Horizon"-Problem identifiziert (Token Issuer `localhost` vs. Docker-interner Keycloak-Host).
* `.env` Datei refactored: Trennung in `KC_ISSUER_URI` (Public) und `KC_JWK_SET_URI` (Internal).
* `dc-backend.yaml` aktualisiert: `api-gateway` und `ping-service` nutzen nun diese expliziten Variablen.
### 2. Dokumentation (Single Source of Truth)
* **Update:** `docs/05_Backend/Guides/Testing_with_Postman.md` an den neuen `postman-client` angepasst.
* **Neu:** `docs/07_Infrastructure/guides/jwt-in-docker.md` erstellt. Dieses Dokument erklärt das "Split Horizon"-Problem und dient als Referenz für Frontend- und Backend-Entwickler.
### 3. Testing
* Erfolgreicher Durchlauf aller Postman-Tests (Connectivity, Health, Security Block, Auth Login, Security Access).
* Bestätigung, dass der `ping-service` nun korrekt Token validiert, die von außen (Postman) kommen, aber intern (Docker) geprüft werden.
## Ergebnisse
* Die lokale Entwicklungsumgebung ist nun **vollständig funktionsfähig** und **auth-ready**.
* Die Infrastruktur-Konfiguration ist sauberer und expliziter (Trennung von Public/Internal URLs).
* Eine solide Basis für die Frontend-Login-Implementierung ist geschaffen.
## Nächste Schritte
* **Frontend:** Implementierung des Login-Flows (Authorization Code Flow mit PKCE) unter Nutzung des `web-app` Clients.
* **Backend:** Beginn der Modellierung der **Events Domain** (Veranstaltungen).
@@ -0,0 +1,48 @@
---
type: Journal
status: COMPLETED
owner: Frontend Expert
date: 2026-01-22
participants:
- Frontend Expert
- User
---
# Session Log: Frontend Auth & Refactoring
**Datum:** 22. Jänner 2026
**Ziel:** Implementierung des Login-Flows im Frontend und Refactoring der Architektur.
## Durchgeführte Arbeiten
### 1. Architektur-Refactoring
* **Auth-Feature:** Das Modul `frontend/features/auth-feature` wurde nach `frontend/core/auth` verschoben, da es sich um eine Basisfunktionalität (Infrastruktur) handelt.
* **Design-System:** Das Package `at.mocode.clients.shared.commonui` wurde zu `at.mocode.frontend.core.designsystem` refactored.
* **Cleanup:** Alte, redundante Dateien und Module wurden bereinigt.
### 2. Authentifizierung (Login)
* **Client:** Umstellung auf `postman-client` (Confidential Client) für den Desktop-Login, da `web-app` (Public Client) keine Direct Access Grants (Password Flow) unterstützte.
* **Secret:** Das Client Secret (`postman-secret-123`) wurde temporär in `AppConstants` hinterlegt (DEV-Only).
* **AuthApiClient:** Implementierung von Basic Auth Header für den Token-Request.
* **LoginViewModel:** Fix des State-Managements beim Logout (automatischer Reset von `isAuthenticated`).
### 3. UI & Navigation
* **MainApp:** Einführung von `AppScaffold` und Scroll-Support für Landing/Welcome Screens.
* **Navigation:** Hinzufügen von "Zurück"-Buttons in `LoginScreen` und `PingScreen`.
* **Usability:** Entfernung verwirrender Browser-Login-Buttons.
### 4. Backend-Integration
* **Secure Ping:** Erfolgreich getestet (200 OK mit Token).
* **Sync:** Erfolgreich getestet (200 OK mit Token). URL-Fix (`/api/pings/sync` -> `/api/ping/sync`).
## Ergebnisse
* Die Desktop-App ist nun voll funktionsfähig: Login, Logout, Secure API Calls und Sync funktionieren.
* Die Code-Struktur ist sauberer und folgt der Trennung zwischen Core (Infra) und Features (Domain).
## Offene Punkte
* **Browser-Login:** PKCE Flow für Web-Target muss noch sauber implementiert werden.
* **User-Info:** Das Profil zeigt noch "unbekannt", da der Username nicht korrekt aus dem Token geparst wird.
* **Secret Management:** Das Client Secret darf nicht im Code bleiben (für Prod).
---
**Status:** ✅ Erfolgreich abgeschlossen.
@@ -0,0 +1,42 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-23
participants:
- Lead Architect
- Backend Developer
- Curator
---
# Session Log: 23. Jänner 2026
## Zielsetzung
Abschluss der "Tracer Bullet" Phase durch Härtung des Backends (Flyway) und Professionalisierung der Zusammenarbeit (Agent Protocol).
## Durchgeführte Arbeiten
### 1. Backend Hardening (Production Readiness)
* **Flyway:** Aktivierung von Flyway Migrationen für den `ping-service`.
* `V1__init_ping.sql`: Schema-Definition.
* `V2__seed_data.sql`: Initiale Testdaten für Sync-Tests.
* **Hibernate:** Umstellung von `ddl-auto` auf `validate`. Damit ist sichergestellt, dass die Anwendung nur startet, wenn das DB-Schema exakt zum Code passt.
### 2. Agent Protocol & Organisation
* **AGENTS.md:** Definition eines strikten Protokolls für die Interaktion zwischen User und KI-Agenten.
* Einführung von Badges (z.B. `🏗️ [Lead Architect]`) zur Kontext-Setzung.
* Verlinkung aller Playbooks.
* **UI/UX Designer:** Einführung einer neuen Rolle für "High-Density Enterprise Design". Playbook erstellt.
### 3. Dokumentation
* **Cleanup:** Aktualisierung der `docs/README.md` als zentraler Einstiegspunkt.
* **Status:** Erstellung des `docs/90_Reports/2026-01-23_Weekend_Status_Report.md`.
## Ergebnisse
* Der `ping-service` ist nun technisch bereit für den produktiven Einsatz (kein `ddl-auto` mehr).
* Die Zusammenarbeit ist durch klare Rollen und Protokolle effizienter gestaltet.
* Der Status des Projekts ist "Grün" in allen Bereichen (außer Web-Auth, das für nächste Woche geplant ist).
## Nächste Schritte (Montag)
* **Integration Test:** Vollständiger Durchstich (Frontend -> Gateway -> Service -> DB) mit dem gehärteten Stack.
* **Web Auth:** Implementierung PKCE Flow.
@@ -0,0 +1,39 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-23
participants:
- DevOps Engineer
- Frontend Expert
- Curator
---
# Session Log: Auth & Build Fixes
**Datum:** 23. Jänner 2026
**Ziel:** Behebung von Build-Fehlern im Docker-Stack und Stabilisierung des Auth-Flows (Login/Logout) im Frontend.
## Durchgeführte Arbeiten
### 1. Docker Build Fix (DevOps)
* **Problem:** Der Build von `api-gateway` und `ping-service` schlug fehl, weil Gradle das Modul `:frontend:core:auth` konfigurieren wollte, dessen Pfad im Docker-Container fehlte.
* **Lösung:** Die `Dockerfile`s beider Services wurden aktualisiert, um die neue Frontend-Struktur (`frontend/core/auth` statt `frontend/features/auth-feature`) widerzuspiegeln.
### 2. Frontend Auth Stabilisierung (Frontend Expert)
* **Problem 1 (Login 401):** Der `AuthApiClient` nutzte den globalen `apiClient`, der für das Gateway konfiguriert war (`DefaultRequest` mit Base URL). Dies führte zu Konflikten bei Requests gegen Keycloak.
* **Lösung:** Einführung eines `baseHttpClient` (named) im `NetworkModule`, der "nackt" ist. Der `AuthApiClient` nutzt nun diesen Client.
* **Problem 2 (Logout ineffektiv):** Das Ktor `Auth` Plugin cachete den Token intern, sodass ein Logout (`AuthTokenManager.clearToken()`) erst beim Neustart wirksam wurde.
* **Lösung:** Entfernung des `Auth` Plugins aus dem `apiClient`. Stattdessen wird der `Authorization` Header nun via `install(DefaultRequest)` dynamisch bei jedem Request aus dem `TokenProvider` gelesen.
### 3. Keycloak Konfiguration
* **Problem:** Der Admin-User musste beim ersten Login das Passwort ändern (`temporary: true`), was den API-Login blockierte.
* **Lösung:** In `meldestelle-realm.json` wurde `temporary: false` gesetzt.
## Ergebnisse
* Der Docker-Build läuft fehlerfrei durch.
* Login funktioniert stabil.
* Logout funktioniert sofort (nachfolgende Requests liefern korrekt 401).
* Die Architektur im Frontend ist durch die Trennung der HttpClients sauberer.
**Status:** 🟢 **System Fully Operational**
@@ -0,0 +1,57 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-26
participants:
- Lead Architect
- DevOps Engineer
- QA Specialist
- Curator
---
# Session Log: 26. Jänner 2026
## Zielsetzung
Stabilisierung der Web-Applikation (Wasm/JS) und Behebung von Datenbank-Initialisierungsfehlern (`WebWorkerException`) im Browser.
## Durchgeführte Arbeiten
### 1. Web-App Datenbank (SQLDelight & Wasm)
* **Problem:** Die Web-App startete nicht mit einer `WebWorkerException`. Ursache war, dass der Web Worker (`sqlite.worker.js`) und die zugehörige WASM-Datei (`sqlite3.wasm`) vom Browser nicht gefunden oder falsch geladen wurden.
* **Lösungsversuche:**
* Aktivierung des Wasm-Targets (revertiert, da zu viele Folgefehler).
* Anpassung der Gradle-Tasks (`copySqliteAssetsToWebpackSource`, `copySqliteAssetsToDist`), um Assets korrekt zu kopieren.
* Anpassung des Workers (`sqlite.worker.js`) für manuelles Laden der WASM-Datei via `fetch`.
* **Webpack-Hacks:** Umfangreiche Anpassungen in `webpack.config.d/ignore-sqlite-wasm.js`, um Webpack daran zu hindern, `sqlite3.wasm` als Modul zu parsen (was fehlschlug) und stattdessen auf ein `dummy.js` umzuleiten.
* **Aktueller Stand:**
* Der Build schlägt noch fehl mit `export 'default' ... was not found`.
* Die Strategie ist: Webpack sieht `dummy.js` (als Ersatz für `sqlite3.mjs` und `sqlite3.wasm`), während der Worker zur Laufzeit die echte `sqlite3.wasm` Datei manuell lädt.
* `dummy.js` muss so angepasst werden, dass es einen korrekten Default-Export bereitstellt.
### 2. Unit Tests (Ping Feature)
* **Problem:** `PingViewModelTest` schlug fehl, da Fehlerzustände nicht korrekt im UI-State gesetzt wurden.
* **Lösung:** `PingViewModel` angepasst, um `errorMessage` im State bei Exceptions korrekt zu setzen. Tests sind wieder grün.
### 3. Gradle Build Optimierung
* **Problem:** Zirkuläre Abhängigkeiten zwischen Copy-Tasks und Webpack-Tasks.
* **Lösung:** Task-Reihenfolge in `build.gradle.kts` korrigiert (`mustRunAfter` statt `dependsOn` wo nötig).
## Offene Punkte & Nächste Schritte
1. **Web-App Build Fix:**
* `dummy.js` muss einen Default-Export (`export default function...`) bereitstellen, um den Import in `sqlite.worker.js` zu befriedigen.
* Danach sollte der Webpack-Build durchlaufen.
* Laufzeit-Test im Browser: Prüfen, ob der manuelle `fetch` im Worker funktioniert und die DB initialisiert wird.
2. **Wasm-Strategie:**
* Langfristig sollte auf natives Wasm-Target umgestellt werden, sobald die Toolchain (Kotlin/Wasm + SQLDelight) stabiler ist. Aktuell ist der JS-Interop-Weg mit Webpack-Hacks notwendig.
3. **Integration Test:**
* Sobald die Web-App läuft: Vollständiger Durchstich (Login -> Ping -> DB Sync) im Browser testen.
## Technische Erkenntnisse
* **Webpack & Wasm:** Webpack 5 tut sich schwer mit dynamischen `require`-Aufrufen in Libraries wie `sqlite-wasm`, wenn diese nicht explizit als `externals` oder via `NormalModuleReplacementPlugin` behandelt werden.
* **SQLDelight im Browser:** Die Kombination aus OPFS (Origin Private File System), Web Workern und Wasm erfordert präzise Kontrolle über das Laden der Assets, die Webpack oft "wegabstrahieren" will.
**Status:** 🟡 **Build Failing (Web)** / 🟢 **Tests Passing (JVM)**
@@ -0,0 +1,52 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-27
participants:
- Lead Architect
- Frontend Expert
- Curator
---
# Session Log: 27. Jänner 2026
## Zielsetzung
Stabilisierung der Web-Applikation (JS/Wasm), Behebung von Build-Fehlern und Inbetriebnahme des Delta-Syncs.
## Durchgeführte Arbeiten
### 1. Web-App Build & Runtime Fixes
* **Problem:** Webpack-Build schlug fehl wegen `sqlite3.wasm` Handling.
* **Lösung:** Revertierung komplexer Webpack-Hacks. Der Build funktioniert nun standardmäßig, da die Abhängigkeiten korrekt konfiguriert sind.
* **Problem:** Login schlug fehl mit 404 auf `/members/sync`.
* **Lösung:** Veralteten Aufruf im `LoginViewModel` entfernt (Members-Modul existiert nicht mehr).
### 2. SQLDelight Async Driver Issues (JS/Wasm)
* **Problem:** Laufzeitfehler `The driver used with SQLDelight is asynchronous, so SQLDelight should be configured for asynchronous usage` beim Aufruf von `getLatestSince` (Select).
* **Analyse:** Trotz `generateAsync = true` in `build.gradle.kts` scheint der generierte Code für `executeAsOneOrNull()` oder `executeAsList()` im Browser-Kontext Probleme zu machen, wenn er synchron aufgerufen wird (was bei `suspend` eigentlich nicht passieren sollte, aber evtl. durch fehlende Coroutine-Extensions im Classpath verursacht wurde).
* **Versuche:**
* Transaktion entfernt/hinzugefügt -> Kein Effekt.
* `executeAsList()` statt `executeAsOneOrNull()` -> Kein Effekt.
* Explizites `await()` -> Kompilierfehler (da `upsert` bereits `suspend Unit` ist).
* Hinzufügen von `libs.sqldelight.coroutines` zu `ping-feature` -> Kein Effekt auf den Laufzeitfehler.
* **Lösung (Workaround):** Bypass in `PingEventRepositoryImpl.getLatestSince()`. Die Methode gibt nun immer `null` zurück, was einen **Full-Sync** erzwingt.
* **Ergebnis:** Der Sync (`upsert`) läuft nun erfolgreich durch! Das Schreiben in die DB funktioniert asynchron und transaktional.
### 3. UI/UX
* Das Ping-Service Dashboard zeigt nun im Event-Log erfolgreich "Sync completed successfully" an.
## Offene Punkte & Nächste Schritte
1. **SQLDelight Async Select Fix:**
* Tiefere Analyse, warum `select` Queries im JS-Target den Fehler werfen, während `insert` Queries funktionieren. Eventuell ein Bug in SQLDelight 2.0.2 in Kombination mit Kotlin 2.1.0 oder WebWorkerDriver Konfiguration.
* Langfristig sollte der Bypass entfernt werden, um echten Delta-Sync zu ermöglichen.
2. **Daten-Visualisierung:**
* Erweiterung des Dashboards um eine Ansicht der lokal gespeicherten Ping-Events, um den Sync auch visuell zu verifizieren (nicht nur via Logs).
## Technische Erkenntnisse
* **SQLDelight & JS:** Die Kombination aus `generateAsync=true`, `WebWorkerDriver` und Multiplatform-Modulen ist fragil. Schreiboperationen (`suspend Unit`) scheinen robuster zu sein als Leseoperationen (`ExecutableQuery`), bei denen die asynchrone Ausführung explizit sichergestellt werden muss.
* **Tracer Bullet:** Der Ansatz, erst die Infrastruktur (Ping Service) komplett durchzustechen, hat sich bewährt. Wir haben fundamentale Probleme im Frontend-Stack (Wasm/DB) identifiziert und gelöst (bzw. mitigiert), bevor wir komplexe Fachlichkeit implementieren.
**Status:** 🟢 **Web-App Running** / 🟡 **Sync (Full-Sync Workaround)**
@@ -0,0 +1,38 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-28
participants:
- Lead Architect
- Frontend Expert
---
# Session Log: 28. Jänner 2026 - Lösung des SQLDelight-Sync-Problems
## Zielsetzung
Systematische Analyse und Behebung des kritischen SQLDelight-Bugs in der Web-App (JS/Wasm), der einen echten Delta-Sync verhinderte.
## Durchgeführte Arbeiten
### 1. Analyse & Fehlerreproduktion
* **Ausgangslage:** Der `PingEventRepositoryImpl` enthielt einen Workaround, der `getLatestSince()` immer `null` zurückgeben ließ, um einen Full-Sync zu erzwingen.
* **Reproduktion:** Der Workaround wurde entfernt und durch den ursprünglichen Code (`db.appDatabaseQueries.selectLatestPingEventId().executeAsOneOrNull()`) ersetzt.
* **Ergebnis:** Der Fehler `The driver used with SQLDelight is asynchronous...` wurde wie erwartet in der Browser-Konsole reproduziert.
### 2. Systematische Ursachenforschung
* **Hypothese 1 (Konfiguration):** Die Build-Konfiguration (`frontend/core/local-db/build.gradle.kts`) wurde überprüft. `generateAsync.set(true)` war korrekt gesetzt. Die Fehlermeldung war also eine falsche Fährte.
* **Hypothese 2 (API-Nutzung):** Die Analyse ergab, dass `.executeAsOneOrNull()` eine **blockierende** API ist, die mit dem asynchronen Web-Worker-Treiber in Konflikt steht.
* **Lösung:** Die korrekte, **nicht-blockierende** API aus der SQLDelight-Coroutines-Erweiterung muss verwendet werden.
### 3. Implementierung des Fixes
* Der Aufruf in `PingEventRepositoryImpl` wurde von `executeAsOneOrNull()` auf `awaitAsOneOrNull()` geändert.
* Der korrekte Import-Pfad `app.cash.sqldelight.async.coroutines.awaitAsOneOrNull` wurde hinzugefügt.
## Ergebnis & Status
* **Erfolg:** Das SQLDelight-Sync-Problem ist **gelöst**.
* Die Web-App führt nun einen korrekten **Delta-Sync** durch, was durch den Aufruf des `/api/ping/sync?since=...` Endpunkts im Netzwerk-Log bestätigt wurde.
* Die wichtigste technische Schuld im Frontend wurde beseitigt.
## Nächste Schritte (Diskutiert)
* **Docker-Integration:** Das Frontend (Build & Deployment) soll in die bestehende Docker-Konstruktion des Projekts integriert werden.
@@ -0,0 +1,48 @@
---
type: Journal
status: COMPLETED
owner: Curator
date: 2026-01-29
participants:
- Lead Architect
- DevOps Engineer
- Curator
---
# Session Log: 29. Jänner 2026 - Etablierung robuster Architektur-Guards mit ArchUnit
## Zielsetzung
Etablierung eines robusten, wartbaren und zentralisierten Systems zur Überprüfung und Erzwingung der Projekt-Architekturregeln, insbesondere der Trennung zwischen Modulen (Features, Services).
## Durchgeführte Arbeiten
### 1. Strategische Entscheidung
* **Problem:** Die Notwendigkeit, die modulare Trennung (z.B. zwischen Frontend-Features und Backend-Services) technisch zu erzwingen, wurde als kritisch für die Langlebigkeit des Projekts identifiziert.
* **Analyse:** Die bestehenden, skriptbasierten Gradle-Tasks (`archGuard...`) wurden als clever, aber fragil und nicht universell genug bewertet.
* **Entscheidung:** Es wurde beschlossen, auf **ArchUnit** als zentrales, typsicheres Werkzeug für die Architektur-Verifizierung zu migrieren.
### 2. Implementierung (Iterativer Prozess & Fehlerbehebung)
Die Implementierung war ein mehrstufiger Prozess, der mehrere Herausforderungen aufdeckte:
1. **Modul-Erstellung:** Ein neues Modul `:platform:architecture-tests` wurde erstellt und die ArchUnit-Abhängigkeiten (Version `1.4.1`) wurden im zentralen Versionskatalog `gradle/libs.versions.toml` deklariert.
2. **Abhängigkeits-Problem:** Der erste Versuch, die Abhängigkeiten dynamisch zu sammeln (`rootProject.subprojects.filter`), schlug fehl, da er versuchte, nicht-baubare Verzeichnis-Module (z.B. `:backend`) einzubinden.
* **Lösung:** Umstellung auf eine explizite, manuelle Liste von `implementation(project(":..."))`-Abhängigkeiten in der `build.gradle.kts` des Test-Moduls.
3. **Klassen-Auffindungs-Problem:** Die ersten Test-Implementierungen schlugen mit der Meldung `Rule '...' failed to check any classes` fehl. Dies lag an einer Kombination aus falschen Paket-Mustern und einer inkorrekten Konfiguration des ArchUnit-Klassen-Imports.
* **Lösung:** Die finale, robuste Lösung besteht darin, die `@AnalyzeClasses`-Annotation in den Testklassen zu verwenden und den `packages`-Parameter auf das Root-Package (`at.mocode`) zu setzen. Dies stellt sicher, dass ArchUnit den gesamten relevanten Classpath scannt, der von Gradle durch die expliziten Abhängigkeiten bereitgestellt wird.
4. **Syntax-Korrekturen:** Mehrere Iterationen waren nötig, um die korrekte Syntax für die ArchUnit-Regeln (insbesondere `slices().matching(...)` und die Paket-Identifier) zu finden.
### 3. Finale Konfiguration
* **`build.gradle.kts` (`:platform:architecture-tests`):** Enthält eine explizite, manuell gepflegte Liste von Abhängigkeiten zu allen Modulen, die Code enthalten.
* **`FrontendArchitectureTest.kt`:** Verwendet `@AnalyzeClasses(packages = ["at.mocode.frontend"])` und die Regel `slices().matching("..frontend.features.(*)..").should().notDependOnEachOther()`.
* **`BackendArchitectureTest.kt`:** Verwendet `@AnalyzeClasses(packages = ["at.mocode.backend"])` und eine explizite `noClasses()..`-Regel, da die Backend-Services keine einheitliche Paketstruktur haben.
* **`README.md`:** Eine neue `README.md` wurde im Modul erstellt, um dessen Zweck und Verwendung zu dokumentieren.
## Ergebnis & Status
* **BUILD SUCCESSFUL:** Die Architektur-Tests kompilieren und laufen erfolgreich durch.
* **Keine Verletzungen gefunden:** Die bestehende Codebasis ist sauber und verstößt nicht gegen die neu aufgestellten Regeln.
* Das Projekt verfügt nun über ein zentrales, robustes und erweiterbares System zur Durchsetzung von Architektur-Regeln, das in der CI-Pipeline ausgeführt wird.
* Die alten `archGuard`-Tasks wurden aus der Root-Build-Datei entfernt.
@@ -0,0 +1,41 @@
---
type: Journal
status: COMPLETED
owner: Lead Architect
date: 2026-01-29
participants:
- Lead Architect
---
# Session Log: 29. Jänner 2026 - Roadmap Update & Phase 4 Kickoff
## Zielsetzung
Aktualisierung der MASTER ROADMAP nach erfolgreichem Abschluss der "Tracer Bullet" Phase und Vorbereitung auf den Start der fachlichen Implementierung (Phase 4).
## Durchgeführte Arbeiten
### 1. Status-Review
* Der "Tracer Bullet" (Ping-Service) ist erfolgreich durch den gesamten Stack implementiert.
* Kritische technische Hürden (SQLDelight Async, Docker Networking, ArchUnit) sind genommen.
* Das Projekt ist bereit für die Skalierung auf echte Fach-Domänen.
### 2. Roadmap Update
* **Phase 1-3:** Als "ABGESCHLOSSEN" markiert.
* **Phase 4 (Production Packaging & Domain Start):** Als "AKTUELL" definiert.
* **Neue Aufgaben:**
* **DevOps:** Dockerisierung des Frontends.
* **Backend:** Erstellung des `event-service`.
* **Frontend:** Erstellung des `events`-Features.
* **Architecture:** Sicherstellung der ArchUnit-Abdeckung für neue Module.
### 3. Architecture Review Vorbereitung
* Die bestehenden ArchUnit-Tests (`BackendArchitectureTest`, `FrontendArchitectureTest`) wurden analysiert.
* **Erkenntnis:**
* Backend-Tests erfordern manuelle Erweiterung der Package-Liste (`at.mocode.events..`).
* Frontend-Tests erfordern strikte Einhaltung der Package-Struktur (`at.mocode.<domain>.feature`).
* Diese Anforderungen wurden explizit in die Roadmap-Tasks aufgenommen.
## Ergebnis & Status
* Die Roadmap ist aktuell und spiegelt den Projektfortschritt wider.
* Die Aufgaben für die spezialisierten Agenten sind klar definiert.
* Der Fokus liegt nun auf der Erstellung der ersten echten Fachlichkeit ("Events").
@@ -0,0 +1,38 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-01-30
participants:
- Lead Architect
last_update: 2026-01-30
---
# Session Log: 30. Jänner 2026 - Refactoring Exposed & Ktor
## Zielsetzung
Durchführung der strategischen Migration auf Exposed 1.0.0 (Stable) und Ktor 3.4.0, basierend auf den technischen Analyseberichten.
## Durchgeführte Arbeiten
### 1. Versions-Update (`libs.versions.toml`)
* **Exposed:** Aktualisiert von `1.0.0-rc-4` auf `1.0.0`.
* **Ktor:** Aktualisiert von `3.3.3` auf `3.4.0`.
* **Neue Dependency:** `ktor-server-routing-openapi` hinzugefügt (für Backend OpenAPI Fix).
### 2. Exposed Migration (Backend)
* **Problem:** `DatabaseUtils.kt` enthielt veraltete/falsche Imports (`org.jetbrains.exposed.v1...`), die nicht mit Exposed 1.0.0 kompatibel sind.
* **Lösung:** Die Imports wurden auf die Standard-Exposed-Packages (`org.jetbrains.exposed.sql...`) korrigiert.
* **UUID-Thematik:** Die Tabellen-Definitionen (`VeranstaltungTable`, etc.) nutzen weiterhin `UUIDTable`. Es besteht das Risiko, dass Exposed 1.0.0 hier auf `kotlin.uuid.Uuid` gewechselt hat. Dies muss beim nächsten Build verifiziert werden. Falls Kompilierfehler auftreten, müssen die Tabellen auf `javaUUID` bzw. `JavaUUIDTable` (falls existent) migriert werden.
### 3. Ktor Migration (Frontend & Backend)
* **Frontend:** Das Build-Skript `frontend/core/network/build.gradle.kts` nutzt separate `js` und `wasmJs` Blöcke, daher war keine Umbenennung von `jsAndWasmShared` notwendig.
* **Backend:** Die Dependency `ktor-server-routing-openapi` wurde im Katalog bereitgestellt. Da die Backend-Module (Events, Horses, Masterdata) Ktor Server nutzen, aber keine explizite OpenAPI-Nutzung im Code gefunden wurde (wahrscheinlich SpringDoc), wurde hier kein Code geändert.
## Offene Punkte / Risiken
* **UUID Kompatibilität:** Die Verwendung von `UUIDTable` im Backend muss gegen Exposed 1.0.0 getestet werden. Es ist möglich, dass hier Breaking Changes zur Laufzeit oder Compile-Zeit auftreten.
* **Ktor JS Target:** Die separate Konfiguration von `js` und `wasmJs` ist funktional, aber das neue `web` Target wäre zukunftssicherer.
## Nächste Schritte
1. **Build & Test:** Ausführen des kompletten Builds (`./gradlew build`), um Kompilierfehler (insb. UUIDs) zu identifizieren.
2. **Runtime Test:** Starten des Backends und Prüfung der Datenbank-Interaktion.
@@ -0,0 +1,33 @@
---
type: Journal
status: ACTIVE
owner: Curator
date: 2026-01-31
participants:
- Lead Architect
- DevOps Engineer
last_update: 2026-01-31
---
# Session Log: 31. Jänner 2026 E2E Smoke (Exposed 1.0.0, Ktor 3.4.0)
Zielsetzung
- End-to-End-Smoke nach den zentralen Versionsanhebungen (Exposed/Ktor); Verifikation der Bootbarkeit und der Basis-Routen/Health/Metriken im Docker-Stack.
Durchführung & Ergebnis
- Stack gestartet mit `docker compose --profile all up --build -d`.
- Gateway: Health/Readiness/Prometheus erreichbar, 200 OK.
- Ping-Service: Health/Readiness/Prometheus stabil, 200 OK.
- Web-App (Nginx): Health 200, Fallback-Assets aktiv. Favicon hinzugefügt (404 eliminiert).
- Desktop-App: Xvfb, XFCE, x11vnc, noVNC aktiv, Zugriff über http://localhost:6080/.
Auffälligkeiten
- FE KMP/JS-Build im Builder derzeit rot (fehlende JS-Implementierungen in Auth/Ping-Data). Nginx liefert Fallback, daher Smoke nicht blockiert.
Artefakte
- Report: `docs/90_Reports/2026-01-31_E2E_Smoke_Migration_Exposed_Ktor.md`
Nächste Schritte
1. Frontend KMP „web“-Target Migration & Build-Fix.
2. Erneuter E2E-Smoketest nach FE-Fix; Report ergänzen.
3. Referenzdokumente finalisieren (Diagramme/Checklisten/Rollback).
@@ -0,0 +1,19 @@
# Journal: Jänner 2026
Dieses Dokument fasst die wichtigsten Ereignisse und Entscheidungen des Monats zusammen.
## Woche 1-2: Initialisierung & Analyse
* **13.01.:** Start der Analyse. Identifikation von Strukturproblemen im Backend.
* **14.01.:** Konsolidierung der Dokumentationsstruktur.
* **15.01.:** Festlegung der "Docs-as-Code" Strategie und Agenten-Rollen.
## Woche 3: "Tracer Bullet" (Ping Service)
* **17.01.:** Implementierung des Delta-Syncs im Backend (`/ping/sync`).
* **19.01.:** Frontend Refactoring auf Clean Architecture. Erfolgreicher Build.
* **20.01.:** Stabilisierung des Tech-Stacks (ADR-0013). Downgrade Spring Cloud, Upgrade Compose.
* **22.01.:** Frontend Auth Integration (Keycloak).
* **26.01.:** Web-App (JS/Wasm) Build Fixes (SQLite Wasm).
* **27.01.:** Web-App Sync Integration (Full-Sync Workaround für Async-Driver).
---
*Details siehe archivierte Session-Logs in `_archive/`.*
@@ -0,0 +1,63 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-03
---
# Session Log: Diagnose Docker Build Issues (IsolatedKotlinClasspathClassCastException)
**Datum:** 03.02.2026
**Teilnehmer:** User, DevOps Engineer
**Fokus:** Behebung des `IsolatedKotlinClasspathClassCastException` Fehlers im Docker-Build des Frontends.
## 🎯 Ziel
Den Docker-Build für den `web-app` Service reparieren, der mit einem `IsolatedKotlinClasspathClassCastException` fehlschlägt, während der lokale Build erfolgreich ist.
## 📝 Protokoll
### 1. Ausgangslage
* **Fehler:** `IsolatedKotlinClasspathClassCastException: The Kotlin Gradle plugin was loaded multiple times in different subprojects...`
* **Kontext:** Tritt nur im Docker-Container auf (Gradle 9.3.1, Java 25, KMP 2.3.0).
* **Lokaler Build:** Funktioniert einwandfrei (`./gradlew clean build`).
### 2. Durchgeführte Maßnahmen & Analysen
#### A. Caching-Hypothese
* **Vermutung:** Docker Build-Cache (`--mount=type=cache`) verursacht Inkonsistenzen.
* **Aktion:** Cache-Mounts im Dockerfile deaktiviert.
* **Ergebnis:** ❌ Build schlägt weiterhin fehl.
#### B. Plugin-Konfiguration (Subprojekte)
* **Vermutung:** `frontend:core:auth` wendet Plugins falsch an oder hat Konflikte durch `browser()` Target.
* **Aktion 1:** `browser()` durch `nodejs()` ersetzt. -> ❌ Fehlschlag.
* **Aktion 2:** `js` Target komplett entfernt (temporär). -> ❌ Fehlschlag (Kompilierfehler, aber Plugin-Fehler weg -> Compose als Verdächtiger).
* **Aktion 3:** Legacy `apply(plugin = ...)` Syntax versucht. -> ❌ Fehlschlag (DSL Accessors fehlen).
#### C. Root-Projekt Konfiguration
* **Vermutung:** `NodeJsRootPlugin` wird nicht zentral geladen.
* **Aktion 1:** `js { browser(); nodejs() }` im Root `build.gradle.kts` hinzugefügt. -> ❌ Fehlschlag.
* **Aktion 2:** `apply<NodeJsRootPlugin>()` explizit im Root ausgeführt. -> ❌ Fehlschlag.
* **Aktion 3:** `buildscript { dependencies { classpath("kotlin-gradle-plugin") } }` Hack angewendet, um Plugin in Root-Classloader zu zwingen. -> ❌ Fehlschlag.
#### D. Umgebungsvariablen & Daemon
* **Vermutung:** Gradle Daemon oder parallele Ausführung im Docker verursacht Race Conditions.
* **Aktion:** `--no-daemon` und `org.gradle.parallel=false` gesetzt. `GRADLE_USER_HOME` auf `/workspace/.gradle` geändert.
* **Ergebnis:** ❌ Fehlschlag.
#### E. Downgrade-Versuch
* **Aktion:** Versuch, auf Gradle 8.12 downzugraden.
* **Ergebnis:** ❌ Gescheitert, da Gradle 8.12 Java 25 nicht unterstützt (`IllegalArgumentException: 25.0.2`).
### 3. Ergebnis & Fazit
* Das Problem ist ein **Bug in der Interaktion zwischen Gradle 9.x, Kotlin 2.3.0 und Docker**.
* Es manifestiert sich als Classloader-Isolation-Problem, bei dem das `NodeJsRootPlugin` mehrfach geladen wird, obwohl es das nicht sollte.
* Alle gängigen Workarounds (Cache, Daemon, explizites Laden) haben versagt.
* Ein Downgrade ist aufgrund der Java 25 Abhängigkeit nicht trivial möglich.
### 4. Nächste Schritte (Empfehlung)
1. **Warten auf Upstream-Fix:** Das Problem liegt bei JetBrains/Gradle.
2. **Temporärer Workaround (nicht implementiert):** Java-Version auf 21 senken und Gradle auf 8.10 downgraden (würde aber Code-Änderungen erfordern, da Java 25 Features genutzt werden).
3. **Lokal bauen, Docker nur für Runtime:** Als Übergangslösung könnte das Artefakt lokal gebaut und in den Container kopiert werden, statt im Container zu bauen.
## 🧹 Cleanup
Alle experimentellen Änderungen an `build.gradle.kts`, `gradle.properties` und `Dockerfile` wurden rückgängig gemacht, um den Codebase sauber zu halten.
@@ -0,0 +1,68 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-03
---
# 🧹 Session Log: Gradle Build-Optimierung & Refactoring
**Datum:** 03.02.2026
**Teilnehmer:** Lead Architect, User
**Thema:** Umfassende Analyse, Bereinigung und Optimierung der Gradle Build-Skripte (Frontend, Backend, Platform).
## 📝 Zusammenfassung
In dieser Session wurde die gesamte Build-Infrastruktur des Projekts "Meldestelle" analysiert und refaktorisiert. Ziel war es, Redundanzen zu eliminieren (DRY), die Konsistenz zwischen Modulen zu erhöhen und die strikte Nutzung des Version Catalogs (`libs.versions.toml`) durchzusetzen. Ein kritischer Fehler im `monitoring-server` (Logback `NoClassDefFoundError`) wurde durch Korrekturen in der Dependency-Hierarchie behoben.
## 🛠️ Durchgeführte Änderungen
### 1. Version Catalog (`libs.versions.toml`)
* **Fix:** Syntaxfehler bei `npm-copy-webpack` behoben (NPM-Pakete müssen in `[versions]` definiert und via `devNpm` referenziert werden).
* **Neu:** `sqliteWasm` Version hinzugefügt.
* **Neu:** `logback-core` hinzugefügt, um Versionskonflikte mit Spring Boot zu vermeiden.
### 2. Root & Settings
* **`settings.gradle.kts`**: Hardcodierte Plugin-Versionen entfernt (soweit technisch möglich). Ausnahme: `foojay-resolver` muss aufgrund des Build-Lifecycles hardcodiert bleiben.
* **`build.gradle.kts` (Root)**:
* Zentralisierung der Kotlin Compiler-Optionen (JVM 25, `-Xexpect-actual-classes`).
* Globale Konfiguration für `tasks.test` (JUnit Platform, Heap Size).
* Reduzierung von "Noise" bei JS-Builds (Duplicate Strategy).
### 3. Frontend (KMP)
* **`frontend/core/*`**:
* Entfernung redundanter `compilerOptions` und `jvmToolchain` Konfigurationen.
* Vereinheitlichung der JS-Target Konfiguration (`browser()`, `binaries.library()`).
* Bereinigung von `auth`, `design-system`, `local-db`, `navigation`, `network`, `sync`.
* **`frontend/features/ping-feature`**: Anpassung an Core-Standards.
* **`frontend/shells/meldestelle-portal`**:
* Korrektur der Webpack-Konfiguration (`copy-webpack-plugin` via Catalog).
* Vereinfachung der Build-Logik.
### 4. Platform
* **`platform-bom`**:
* Aufnahme von `logback-core` in die Constraints, um Synchronität mit `logback-classic` zu erzwingen.
* Bereinigung von auskommentiertem Code.
* **`platform-testing`**:
* Explizites Hinzufügen von `logback-classic` und `logback-core`, um Laufzeitfehler in Tests zu verhindern.
* Entfernung redundanter Test-Konfigurationen.
### 5. Backend Infrastructure
* Bereinigung aller Module (`cache`, `event-store`, `gateway`, `messaging`, `persistence`, `security`) von redundanten Konfigurationen (DRY).
* **Bugfix `monitoring-server`**:
* Problem: `java.lang.NoClassDefFoundError` bei `JoranConfigurator` (Logback).
* Ursache: Versionskonflikt bzw. fehlendes `logback-core` im Test-Classpath durch Spring Boot BOM Interferenz.
* Lösung: Explizites Hinzufügen von `logback-core` und `logback-classic` im `monitoring-server` sowie Anpassung der `platform-bom`.
### 6. Contracts
* **`contracts/ping-api`**: Bereinigung und Konsistenzprüfung.
## ⚠️ Technische Highlights & Learnings
* **Settings Plugins & Version Catalog**: Der Zugriff auf `libs.*` im `plugins {}` Block der `settings.gradle.kts` ist limitiert. Workaround: Version hardcodieren oder `pluginManagement` nutzen.
* **Logback & Spring Boot**: Spring Boot managed Logback-Versionen aggressiv. Wenn man eine neuere Version (1.5.x) nutzen will als Spring Boot (1.4.x), muss man sowohl `classic` als auch `core` in der BOM erzwingen, sonst drohen `NoClassDefFoundError` zur Laufzeit.
* **KMP JS Targets**: Die Konfiguration von `js(IR)` vs. `js` und `browser()` vs. `nodejs()` sollte projektweit konsistent sein, um Build-Probleme zu vermeiden.
## ✅ Status
* Build: **SUCCESSFUL** (`./gradlew clean build`)
* Code Quality: Build-Skripte sind massiv entschlackt und wartbarer.
---
*Eintrag erstellt durch Curator Agent.*
@@ -0,0 +1,149 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-04
---
# 🏗️ Journal: Infrastructure Setup & CI/CD Planning
**Datum:** 04.02.2026
**Autor:** DevOps Engineer & Curator (AI)
**Status:** 🚧 In Progress (Paused due to technical issues)
## Zusammenfassung
Nach der erfolgreichen Verifikation des `ping-service` wurde mit der Planung und Einrichtung der CI/CD-Infrastruktur begonnen. Die Entscheidung fiel auf eine **Self-Hosted Lösung** (Gitea + Gitea Runner) auf dem vorhandenen Proxmox-Server, angebunden via **Cloudflare Tunnel** für sicheren Zugriff ohne Portfreigaben.
## 1. Cloudflare Bereinigung (Erledigt ✅)
Ziel war es, die Domain `mo-code.at` für den Tunnel vorzubereiten, ohne den Mail-Empfang zu stören.
**Durchgeführte Schritte:**
1. **Login:** Cloudflare Dashboard -> Domain `mo-code.at` -> DNS -> Records.
2. **Gelöscht:**
* `A | mo-code.at | 81.19.145.155`
* `A | www | 81.19.145.155`
* `A | ftp | 81.19.145.155`
3. **Behalten & Korrigiert (Mail):**
* `A | mail | 81.19.149.91` -> **Proxy Status auf "DNS Only" (Grau) gesetzt.**
* `CNAME | imap | imap.world4you.com` -> **Proxy Status auf "DNS Only" (Grau) gesetzt.**
* `MX` und `TXT` Records wurden unverändert gelassen.
---
## 2. Proxmox Docker-Host Setup (Anleitung)
Diese Anleitung dient zur Wiederherstellung/Neuinstallation der VM, falls Probleme auftreten.
### Vorbereitung: ISO Download
1. Proxmox GUI -> `local` Storage -> `ISO Images`.
2. **Download from URL:** `https://releases.ubuntu.com/24.04.1/ubuntu-24.04.1-live-server-amd64.iso`
3. Warten bis Download fertig.
### Schritt A: VM Erstellen (Klick-für-Klick)
1. **Create VM** (Button oben rechts).
2. **General:**
* Name: `docker-host`
* VM ID: (Standard lassen, z.B. 100)
3. **OS:**
* ISO image: `ubuntu-24.04.1...iso`
* Type: Linux / 6.x - 2.6 Kernel
4. **System:**
* Graphics/Machine/BIOS: Standard lassen.
* **Qemu Agent:** ✅ Aktivieren (Häkchen setzen).
5. **Disks:**
* Storage: `local-lvm`
* Disk size: **100 GiB**
* **SSD emulation:** ✅ Aktivieren.
* **Discard:** ✅ Aktivieren.
6. **CPU:**
* Sockets: 1
* Cores: **4**
* Type: **host** (Wichtig für Performance!).
7. **Memory:**
* Memory: **8192** (8 GB).
* Ballooning: ✅ Aktivieren.
8. **Network:**
* Bridge: `vmbr0`
* Model: `VirtIO`
9. **Confirm** -> Finish.
### Schritt B: Ubuntu Installation
1. VM starten -> **Console**.
2. Sprache: English.
3. Installer Update: "Update to the new installer" (falls gefragt).
4. Keyboard: German.
5. **Base:** Ubuntu Server (minimized optional, Standard empfohlen).
6. **Network:** DHCP lassen.
7. **Storage:** "Use an entire disk" -> Standard lassen -> Done.
8. **Profile:**
* Name: `Stefan`
* Server name: `docker-host`
* Username: `stefan`
* Password: (Merken!)
9. **SSH Setup:** **[X] Install OpenSSH server** (Mit Leertaste auswählen).
10. **Snaps:** **NICHTS** auswählen (kein Docker, kein MicroK8s).
11. Installieren & Reboot.
### Schritt C: Docker Installation (via Terminal/SSH)
Verbinde dich von deinem PC aus: `ssh stefan@<VM-IP>`
```bash
# 1. System aktualisieren & QEMU Agent sicherstellen
sudo apt update && sudo apt upgrade -y
sudo apt install -y qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
# 2. Docker Installations-Script laden & ausführen
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 3. User zur Docker-Gruppe hinzufügen (Wichtig!)
sudo usermod -aG docker $USER
# 4. Neustart, damit Rechte greifen
sudo reboot
```
### Schritt D: Test
Nach dem Neustart wieder einloggen:
```bash
docker run hello-world
```
Sollte "Hello from Docker!" ausgeben.
---
## 3. Ausblick: Nächste Schritte (DevOps Stack)
Sobald der Docker-Host läuft, werden wir folgende `docker-compose.yml` (Entwurf) verwenden, um Gitea und Cloudflare Tunnel zu starten:
```yaml
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- ./gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
restart: always
tunnel:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: always
command: tunnel run
environment:
- TUNNEL_TOKEN=<WIRD_GENERIERT>
```
## Troubleshooting Tipps (Installation bricht ab)
* **ISO Check:** Prüfe die Checksumme des ISOs oder lade es neu herunter.
* **RAM:** Versuche es testweise mit 4 GB statt 8 GB.
* **Disk:** Prüfe im Proxmox Storage, ob wirklich genug Platz auf `local-lvm` frei ist.
* **Console:** Beobachte die Fehlermeldung in der Proxmox-Konsole genau (oft I/O Errors).
@@ -0,0 +1,37 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-04
---
# 🏗️ Journal: Ping Service Verification
**Datum:** 04.02.2026
**Autor:** Lead Architect (AI)
**Status:** ✅ Verified
## Zusammenfassung
Vor dem Start der CI/CD-Pipeline Implementierung wurde der `ping-service` einer umfassenden Prüfung unterzogen. Ziel war es, die Konsistenz von Code, Tests, Docker-Konfiguration und Security-Einstellungen sicherzustellen.
## Prüfergebnisse
### 1. Code & API Konsistenz
* **Sync API:** Der Parameter `since` wird konsistent in `PingApi` (Contract) und `PingController` (Backend) verwendet.
* **UUID:** Die Verwendung der experimentellen Kotlin UUID API (`v7`) ist durch `@OptIn` Annotationen und Compiler-Args korrekt konfiguriert.
* **Tests:** Unit- und Integrationstests (`PingControllerTest`, `PingControllerIntegrationTest`) sind aktuell und decken die API-Änderungen ab.
### 2. Docker Konfiguration
* **Base Image:** Alpine-basiertes JRE für minimale Größe und Sicherheit.
* **Security:** Non-root User `appuser` wird verwendet.
* **Healthcheck:** Korrekt auf `/actuator/health/readiness` konfiguriert. `curl` ist im Image vorhanden.
* **Entrypoint:** `tini` wird für korrektes Signal-Handling genutzt.
### 3. Security Konfiguration
* **Actuator:** `/actuator/**` ist via `GlobalSecurityConfig` öffentlich zugänglich (notwendig für Docker Healthcheck).
* **Endpoints:**
* Public: `/ping/simple`, `/ping/enhanced`, `/ping/public`, `/ping/health`
* Protected: `/ping/secure`, `/ping/sync` (implizit durch `anyRequest().authenticated()`)
* **CORS:** Global aktiviert für Frontend-Zugriff.
## Fazit
Der `ping-service` ist **Ready for Deployment**. Die Architektur ist sauber, sicher und testbar. Wir können nun mit der Einrichtung der CI/CD-Pipeline (Cloudflare, Selfhosted Proxmox) fortfahren.
@@ -0,0 +1,70 @@
---
type: Journal
status: ACTIVE
owner: DevOps Engineer
last_update: 2026-02-04
---
# Session Log: Docker Hybrid Build & Build Optimization
**Datum:** 04.02.2026
**Teilnehmer:** User, DevOps Engineer
**Fokus:** Stabilisierung des Frontend-Builds im Docker-Container und Optimierung der Build-Performance.
## 🎯 Ziel
Den Docker-Build für den `web-app` Service reparieren, der aufgrund von Gradle/Kotlin-Plugin-Konflikten (`IsolatedKotlinClasspathClassCastException`) fehlschlug, und die Build-Zeiten optimieren.
## 📝 Protokoll
### 1. Problem: Gradle Plugin Konflikte im Docker
* **Symptom:** `IsolatedKotlinClasspathClassCastException` beim Build im Docker-Container.
* **Ursache:** Konflikt zwischen Gradle 9.x, Kotlin 2.3.0 und dem `NodeJsRootPlugin`, wenn das Root-Projekt versucht, die Node.js-Umgebung zu initialisieren, während Subprojekte dies ebenfalls tun.
* **Lösung:**
1. **Root `build.gradle.kts` bereinigt:** KMP-Plugin nur noch mit `apply false` eingebunden. `kotlin { ... }` Block im Root entfernt. Root ist nun reiner Konfigurations-Container.
2. **Hybrid-Build Strategie:** Statt im Docker-Container zu bauen (was instabil war), bauen wir das Frontend lokal (`./gradlew ...jsBrowserDistribution`) und kopieren die fertigen Artefakte in den Container.
### 2. Problem: `.dockerignore` blockiert Artefakte
* **Symptom:** `COPY failed: ... not found`.
* **Ursache:** `.dockerignore` schloss `**/build/` pauschal aus.
* **Lösung:** Explizite Ausnahme für den Pfad `!frontend/shells/meldestelle-portal/build/dist/js/productionExecutable/` (inklusive aller Eltern-Ordner) hinzugefügt.
### 3. Problem: Build-Performance (Webpack Timeout)
* **Symptom:** Webpack-Task lief >12 Minuten oder hing.
* **Ursache:** Zu wenig Speicher für den Gradle Daemon und Node.js Prozess bei großen Builds.
* **Lösung:** `gradle.properties` angepasst:
* `org.gradle.jvmargs`: 4GB (vorher 3GB)
* `kotlin.daemon.jvmargs`: 4GB (vorher 3GB)
### 4. Problem: Caddy Config & Runtime
* **Symptom:** 500er Fehler beim Abruf von `/config.json`.
* **Ursache:** Syntax-Fehler im Caddy-Template (Escaping von Anführungszeichen).
* **Lösung:** Template auf einfache Syntax zurückgesetzt: `{{env "API_BASE_URL" ...}}`.
* **Playbook Update:** DevOps Engineer übernimmt explizit die Verantwortung für Caddy/Webserver-Konfiguration.
### 5. Problem: Ping-Service Erreichbarkeit (CORS/Routing)
* **Symptom:** Frontend erhielt HTML (SPA Fallback) statt JSON vom Backend.
* **Ursache:** Caddy leitete `/api/*` nicht an den `api-gateway` weiter, sondern lieferte die `index.html` aus.
* **Lösung:**
1. **Caddyfile:** `reverse_proxy /api/* api-gateway:8081` hinzugefügt.
2. **config.json:** `apiBaseUrl` auf leer (`""`) gesetzt, damit Frontend relative Pfade nutzt.
3. **Security:** Caddyfile um Security Headers (`Permissions-Policy`, `Referrer-Policy`) und Logging erweitert.
## ✅ Ergebnisse
1. **Web-App läuft:** Der Container `meldestelle-web-app` startet erfolgreich und ist unter `http://localhost:4000` erreichbar.
2. **API-Zugriff funktioniert:** Ping-Service liefert JSON (`200 OK`) an das Frontend.
3. **Build-Prozess:** Stabilisiert durch Hybrid-Ansatz (Lokal bauen -> Docker kopieren).
4. **Infrastruktur:** `build.gradle.kts` (Root) ist sauberer und performanter.
## ⏭️ Nächste Schritte (Open Points)
* **CI/CD:** Für die CI-Pipeline muss der Hybrid-Build berücksichtigt werden (Build-Step vor Docker-Build).
* **WebGL Warnungen:** Im Browser-Log tauchen WebGL-Warnungen auf (vermutlich Compose/Skiko related), die aber die Funktion nicht beeinträchtigen.
## 📂 Betroffene Dateien
* `build.gradle.kts` (Root)
* `gradle.properties`
* `config/docker/caddy/web-app/Dockerfile`
* `config/docker/caddy/web-app/Caddyfile`
* `.dockerignore`
* `config/docker/caddy/web-app/config.json`
* `dc-gui.yaml`
* `docs/04_Agents/Playbooks/DevOpsEngineer.md`
@@ -0,0 +1,56 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-06
---
# Session Log: Infrastructure Planning & Reporting Requirements
**Datum:** 06.02.2026
**Teilnehmer:** User (Owner), Lead Architect, DevOps Engineer
## 1. Zusammenfassung
In dieser Session wurde die zukünftige Infrastruktur für den Home-Server (Minisforum MS-R1) detailliert geplant und korrigiert. Zudem wurden Anforderungen für Reporting und Offline-Fähigkeit präzisiert.
## 2. Reporting / Printing (Vorgemerkt)
Der User benötigt eine Lösung zum Generieren von personalisierten PDFs (Startlisten, Ergebnislisten, Protokolle).
* **Status:** Als "Next Step" in die Roadmap aufgenommen.
* **Architektur:** Dezentraler Microservice (um Resource-Bursts vom Core-System fernzuhalten).
* **Aktion:** Wurde in `MASTER_ROADMAP_2026_Q1.md` dokumentiert.
## 3. Infrastructure Setup (Minisforum MS-R1)
**Hardware Specs:**
* Model: Minisforum MS-R1
* CPU: 12 Kerne ARM (CP8180)
* RAM: bis 64GB LPDDR5
* Network: 2x 10G LAN
* Storage: NVMe + USB-SSD (Backup)
**Software Stack (Final Decision):**
1. **Base OS:** Debian 12 (Vendor Variant, vorinstalliert/angepasst für Treiber).
2. **Hypervisor:** **Incus** (Community Fork von LXD).
3. **Virtualization Strategy:**
* `infra-gitea` (LXC Container): Gitea + Actions Runner.
* *Vorteil:* Leichtgewichtig, Native ARM Builds via Runner.
* `docker-host-prod` (**VM**): Debian VM als Docker Host.
* *Grund:* Bessere Isolation, Kernel-Unabhängigkeit vom Host, keine "Nesting"-Probleme (OverlayFS/ZFS).
4. **CI/CD & Build Strategy:**
* **Tool:** `docker buildx` auf dem Gitea Runner.
* **ARM64 Images:** Werden **nativ** gebaut (rasend schnell, da Host = ARM).
* **x86_64 Images:** Werden via **QEMU-Emulation** gebaut (langsamer, aber funktional).
## 4. Networking & Offline-First
* **Remote Access:** Cloudflare Tunnel.
* **Local LAN (Offline):**
* Die "Main-Native-Desktop-App" (Meldestelle) fungiert als lokaler Anchor/Server im LAN.
* Clients (Zeitnehmer) verbinden sich via LAN.
* **Discovery:** Lokale DNS-Strategie oder Service Discovery (mDNS) notwendig, damit Clients den Server auch ohne Internet finden.
## 5. Backup
* **Strategie:** Automatisierte Snapshots/Backups auf externe **USB-SSD**.
* **Motto:** "Kein Backup, kein Mitleid."
## 6. Nächste Schritte
* Warten auf Hardware-Lieferung.
* Installation & Setup gemäß korrigiertem Plan (VM statt LXC für Docker).
* Vorbereitung der CI/CD Pipelines auf Multi-Architektur (Buildx/QEMU).
@@ -0,0 +1,35 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-02-13
---
# Journal - 2026-02-13
## 📝 Zusammenfassung
Heute wurden Inkonsistenzen in der Konfiguration der Backend-Services behoben, die zu Verbindungsproblemen führten. Zudem wurde der Build-Prozess für das Frontend optimiert.
## 🛠️ Änderungen
### 1. Backend Konfiguration (Fix 503 Service Unavailable)
* **Problem:** Der `ping-service` war über das Gateway nicht erreichbar (503), da die Route im Gateway hart auf `http://ping-service:8082` kodiert war. Dies funktionierte im Docker-Netzwerk, aber nicht beim lokalen Start (Localhost).
* **Lösung:**
* `GatewayConfig.kt`: Die URI für den Ping-Service wurde dynamisch gemacht (`${ping.service.url}`).
* `application.yaml` (Gateway): Default-Wert für `ping.service.url` auf `http://localhost:8082` gesetzt (für lokale Entwicklung).
* `dc-backend.yaml`: Environment-Variable `PING_SERVICE_URL` auf `http://ping-service:8082` gesetzt (für Docker).
* Zusätzlich wurden Inkonsistenzen bei Port-Variablennamen (`PING_SERVER_PORT` vs `PING_SERVICE_PORT`) zwischen `.env` und `application.yaml` bereinigt.
### 2. Frontend Build Optimierung
* **Problem:** Der Build `jsBrowserDistribution -Pproduction=true` dauerte extrem lange (>15 min) und hing.
* **Ursache:** Generierung von Source Maps im Production-Mode bei großen Kotlin/JS Projekten.
* **Lösung:**
* `build.gradle.kts` (meldestelle-portal): Logik angepasst, sodass Source Maps im Production-Mode standardmäßig deaktiviert sind (`sourceMaps = false`), es sei denn, sie werden explizit angefordert.
* Ergebnis: Build-Zeit auf ~9 Sekunden reduziert.
## 📚 Gelerntes
* **Source Maps:** Sind essenziell für Debugging, aber extrem teuer im Build. Für Production-Builds (Docker Images) sollten sie deaktiviert werden, um Build-Zeiten und Image-Größe zu optimieren.
* **Hybrid-Betrieb:** Services sollten so konfiguriert sein, dass sie sowohl "fully dockerized" als auch "lokal + Docker-Infra" laufen können, ohne Code-Änderungen (Nutzung von Properties/Env-Vars für Hostnames).
## 🔜 Nächste Schritte
* Lokalen Test des gesamten Stacks (Frontend im Docker Container + Backend lokal/Docker) abschließen.
* Verifizierung der Keycloak-Integration im Frontend.
@@ -0,0 +1,79 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-06
---
# Journal - 2026-03-06 (Session 2)
## 📝 Zusammenfassung
Strategische Planungssession mit dem Lead Architect. Drei konkrete Bugs aus der Tiefenanalyse behoben (Valkey-Inkonsistenz, Dependency Verification, backup.sh Hardcodes). Vollständige Schritt-für-Schritt-Anleitung für das heutige Meldestellen-Host-Setup erstellt. Architektur-Entscheidung für einen lokalen AI-Stack (Ollama + Open WebUI) als separaten Proxmox LXC-Container (CT 111) auf Zora getroffen und Installations-Anleitung dokumentiert. Korrektur: Zora läuft auf Proxmox 8.4.10 (nicht Incus); IPs im Netz 10.0.0.0/24.
---
## 🛠️ Änderungen
### 1. Bug-Fixes aus Tiefenanalyse
* **`dc-backend.yaml`:** ping-service von veralteten `SPRING_DATA_REDIS_*` auf `SPRING_DATA_VALKEY_*` umgestellt — konsistent mit api-gateway.
* **`gradle.properties`:** `org.gradle.dependency.verification=lenient``strict` — Sicherheits-Level angehoben, da eigene Gitea-Registry vorhanden.
* **`config/scripts/backup.sh`:** `.env` via `source` geladen, `grandmo`-Hardcode entfernt, `DB_USER` liest `${POSTGRES_USER}` aus `.env`, `BACKUP_DIR` und `BACKUP_RETENTION_DAYS` konfigurierbar.
* **`.env` + `.env.example`:** `BACKUP_DIR` und `BACKUP_RETENTION_DAYS` als neue SSoT-Variablen ergänzt.
### 2. Neue Dokumentation
* **`docs/01_Architecture/Minisforum-MS-R1/AI_Stack_Ollama_Setup.md`:** Vollständige Installations-Anleitung für Ollama + Open WebUI auf Zora als Proxmox LXC-Container (CT 111, IP 10.0.0.60). Enthält Hardware-Profil (CIX P1 / CP8180), CPU-Governor-Tuning auf Proxmox-Node, `pct create`-Befehle, Modell-Matrix, Open-WebUI-RAG-Setup, Pangolin-Routing und IntelliJ IDEA Continue.dev-Integration.
---
## 🏗️ Architektur-Entscheidungen
### AI-Stack: Separater Proxmox LXC-Container (nicht im App-Repo)
**Entscheidung:** Ollama + Open WebUI laufen in einem eigenen Proxmox LXC-Container `ai-stack` (CT 111, IP 10.0.0.60), **nicht** als Docker-Service im Meldestelle-Repo.
**Begründung:**
* Modelle (540 GB pro Modell) wachsen unkontrolliert — Isolation schützt den App-Stack.
* Unabhängige Updates ohne Risiko für den Meldestelle-Produktivbetrieb.
* RAM/CPU-Hunger der KI-Inference beeinflusst nicht die Keycloak/Gateway/DB-Verfügbarkeit.
### Datenschutz: Vollständig lokal via Ollama
* Kein Byte verlässt das Heimnetz — alle Inferenz läuft auf Zora CPU (CIX P1, 12 Cores).
* IDEA-Integration via **Continue.dev Plugin** mit `http://10.0.0.60:11434` als Endpoint.
* Pangolin-Route `ai.mo-code.at` → nur intern / VPN exponieren.
### NPU: Noch nicht nutzbar
* CIX P1 NPU aktuell **kein** Ollama/llama.cpp-Support.
* Immortalis-G720 (Vulkan 1.3) — experimentell, nachrüsten sobald stabil.
* Primärer Pfad: CPU-Inferenz mit NEON/SVE2-Optimierungen (ARM64-native Ollama).
---
## 📚 Gelerntes
* **CIX P1 (CP8180) = Tri-Cluster ARM:** 4x Cortex-X4 (fast) + 4x A720 (medium) + 4x A520 (slow) — alle 12 Kerne Ollama zuweisen, CPU-Governor auf `performance` setzen.
* **64 GB RAM = 70B-Modelle möglich:** `llama3.1:70b` (~40 GB) läuft vollständig im RAM — einzigartige Stärke dieser Hardware.
* **Proxmox vmbr0:** Routing und NAT werden von Proxmox via `vmbr0` automatisch verwaltet — keine manuelle iptables-Regel nötig.
* **Kafka-Entscheidung bestätigt:** Bleibt im Build für Phase 3 (Outbox-Pattern / Event-Driven).
* **Ghost Services bleiben ON HOLD:** Bewusste Entscheidung — erst Fachexperten-Session (FEI/ÖTO Regelwerk) bevor fachliche Implementierung beginnt.
---
## 🔜 Nächste Schritte
### Heute Abend (Priorität)
1. Meldestellen-Host aufsetzen nach Anleitung (siehe Haupt-Session-Log)
2. `.env` auf Zora mit Server-IP konfigurieren (`KC_HOSTNAME`, `JWT_ISSUER_URI`)
3. Docker-Stack starten (Infra → Backend → Ops)
4. Ping-Service + Login verifizieren
5. `ai-stack` Proxmox LXC-Container (CT 111) aufsetzen, Ollama + Open WebUI installieren
6. Continue.dev in IDEA konfigurieren
### Nächste Sessions
* **Session 2:** Grafana Dashboards einrichten + Pangolin-URLs finalisieren
* **Session 3:** Willkommensseite + Design-System (Tokens, Farben, Typografie)
* **Session 4:** Fachexperten-Session — FEI/ÖTO Regelwerk, Anforderungen, Rollen definieren
* **Session 5:** Admin-Dashboard (Backend) + Rollen-Management in Keycloak
@@ -0,0 +1,75 @@
---
type: Journal
status: ACTIVE
owner: Curator
date: 2026-03-06
session: Immich & Pangolin — Konfiguration dokumentiert
last_update: 2026-03-06
---
# Session Log — 2026-03-06: Immich & Pangolin Konfiguration
## 📋 Kontext
Ergänzungssession zur Proxmox-Korrektursession vom selben Tag.
10 neue Screenshots wurden geliefert, die die vollständige Konfiguration von
CT 100 (pangolin-client) und CT 103 (immich) sowie die detaillierten Hardware-Specs
von VM 102 (gitea-runner) dokumentieren.
---
## 🛠️ Änderungen
### `SSoT_Konfigurations-Masterplan_Zora.md`
**Neue Daten aus Screenshots (06.03.2026, 13:2513:27):**
#### CT 100 — pangolin-client (LXC)
- IP ergänzt: `10.0.0.21/24`
- Ressourcen dokumentiert: 4 Cores, 512 MiB RAM, 512 MiB Swap, 8 GB Disk
- OS: Ubuntu arm64, Unprivileged, nesting=1
- Autostart: order=1, up=30
#### CT 101 — gitea (LXC)
- Ressourcen ergänzt: 4 Cores, 1 GiB RAM, 512 MiB Swap, 20 GB Disk
- OS: Ubuntu arm64, Unprivileged, nesting=1
- Autostart: order=2, up=30
#### CT 103 — immich (LXC) ← NEU vollständig dokumentiert
- IP: `10.0.0.24/24`
- Ressourcen: 8 Cores, 10 GiB RAM, 512 MiB Swap
- Root Disk: 200 GB (`local:103/vm-103-disk-0.raw`)
- Mount Point mp0: `/mnt/immich_gross``/mnt/fotos` (externe Foto-Bibliothek)
- OS: Ubuntu arm64, Unprivileged
- Features: `nesting=1, keyctl=1, fuse=1` (Docker-in-LXC kompatibel)
- Autostart: order=3, up=30
#### VM 102 — gitea-runner (QEMU/KVM) ← Hardware-Details ergänzt
- IP: `10.0.0.23/24` (bestätigt)
- BIOS: OVMF (UEFI), Machine: virt (ARM64)
- CPU: 8 Cores, 1 Socket, host-type, numa=1
- RAM: 16 GiB (balloon=0 — kein Dynamic Memory)
- Disk: 50 GB SSD (aio=io_uring, iothread=1 — maximale I/O-Performance)
- EFI Disk: 64 MB, efitype=4m
- Netzwerk: virtio, vmbr0, Firewall aktiv
- SCSI: VirtIO SCSI single
#### Pangolin Tunnel Routing erweitert
- Route `photos.mo-code.at` → CT 103 Immich (`10.0.0.24:2283`) ergänzt (intern/VPN)
- Pangolin-Kontext-Hinweis: CT 100 (10.0.0.21) ist der Tunnel-Client
---
## 📚 Gelernt
- **Immich Features:** `keyctl=1` und `fuse=1` sind für Docker-in-LXC und Immich-Thumbnail-Verarbeitung notwendig.
- **io_uring:** Der Gitea-Runner nutzt modernes async I/O für maximale Build-Performance auf NVMe.
- **Start-Reihenfolge:** Pangolin (order=1) → Gitea (order=2) → Immich (order=3) — sinnvolle Abhängigkeitskette.
- **balloon=0 beim Runner:** Festes RAM verhindert Memory-Ballooning-Latenzen bei intensiven CI-Builds.
---
## 🔜 Nächste Schritte
1. Pangolin-Route `photos.mo-code.at` im Pangolin-Dashboard anlegen (sobald Immich-Setup abgeschlossen).
2. Immich-Setup-Anleitung erstellen (optional, eigene Session).
@@ -0,0 +1,43 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-06
---
# Journal - 2026-03-06
## 📝 Zusammenfassung
Keycloak funktionierte lokal einwandfrei, aber auf dem Meldestellen-Host war das Admin-Dashboard (`:8180`) nicht erreichbar und der Login schlug fehl — obwohl der Health-Port (`:9000`) grün war. Root Cause: Das pre-built Registry-Image wurde mit `start-dev` gestartet (Konflikt) und `KC_HOSTNAME=localhost` war auf dem Server falsch.
## 🛠️ Änderungen
### 1. `dc-infra.yaml` — Keycloak-Service bereinigt
* **Command:** `start-dev --import-realm``start --optimized --import-realm` (nutzt das pre-built Image korrekt).
* **Neu:** `KC_HOSTNAME_STRICT=false` und `KC_HOSTNAME_STRICT_HTTPS=false` — erlaubt HTTP-Betrieb ohne TLS-Zwang.
* **Neu:** `KC_HTTP_MANAGEMENT_PORT=9000` — Management-Interface explizit konfiguriert.
* **Fix:** `KC_DEBUG_PORT``KC_MANAGEMENT_PORT` umbenannt (war falsch benannt).
* **Fix:** Image-Pfad von `grandmo``mocode-software` korrigiert.
* **Neu:** Healthcheck auf `http://localhost:9000/health/ready` ergänzt.
### 2. `.env` — Keycloak-Block erweitert
* `KC_HOSTNAME_STRICT=false`, `KC_HOSTNAME_STRICT_HTTPS=false`, `KC_MANAGEMENT_PORT=9000:9000` hinzugefügt.
* Erklärende Kommentare: LOKAL vs. SERVER für `KC_COMMAND` und `KC_HOSTNAME`.
### 3. `.env.example` — Als Server-Vorlage optimiert
* Default `KC_COMMAND=start --optimized --import-realm` (Server-Default).
* `<PLACEHOLDER>`-Werte für alle Secrets (`KC_ADMIN_PASSWORD`, `KC_DB_PASSWORD`) und `KC_HOSTNAME`.
* `SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI` mit `<SERVER_IP_ODER_DOMAIN>`-Platzhalter.
* Klare LOKAL/SERVER-Kommentare bei allen kritischen Variablen.
## 📚 Gelerntes
* **`kc.sh build` + `start-dev` = Konflikt:** Ein mit `kc.sh build` optimiertes Image muss mit `start --optimized` gestartet werden. `start-dev` ignoriert den Pre-Build und startet im Dev-Modus — das bricht das Registry-Image auf dem Server.
* **`KC_HOSTNAME` steuert den HTTP-Port, nicht den Management-Port:** Port `9000` (Health) ist immer auf `0.0.0.0` gebunden. Port `8080/8180` (HTTP) wird durch `KC_HOSTNAME` gesteuert — daher war Health grün, aber Admin-Dashboard nicht erreichbar.
* **`KC_HOSTNAME_STRICT=false` ist Pflicht für HTTP-only Server:** Ohne dieses Flag lehnt Keycloak alle Requests ab, deren Host-Header nicht exakt mit `KC_HOSTNAME` übereinstimmt.
## 🔜 Nächste Schritte
* Auf dem Meldestellen-Host die `.env` anpassen:
* `KC_HOSTNAME=<SERVER_IP>`
* `KC_COMMAND=start --optimized --import-realm`
* `SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://<SERVER_IP>:8180/realms/meldestelle`
* Container neu starten und Admin-Dashboard + Login verifizieren.
* Langfristig: TLS/HTTPS einrichten, dann `KC_HOSTNAME_STRICT_HTTPS=true` setzen.
@@ -0,0 +1,69 @@
---
type: Journal
status: ACTIVE
owner: DevOps
date: 2026-03-06
last_update: 2026-03-06
---
# Session Log — Pipeline 502 Bad Gateway Fix
## Problem
Der Gitea-Runner (VM 102, `10.0.0.23`) brach beim Docker-Push mit `502 Bad Gateway` ab:
```
ERROR: failed to push git.mo-code.at/.../ping-service:latest:
failed to authorize: failed to fetch oauth token:
unexpected status from POST request to https://git.mo-code.at/v2/token: 502 Bad Gateway
```
Der Build lief durch (alle Layers gebaut), aber der Push schlug nach ~70 Sekunden fehl.
## Root Cause
Der Runner routete den Registry-Push über Pangolin (CT 100, `10.0.0.21`) → `git.mo-code.at` → Gitea (CT 101, `10.0.0.22`). Bei großen Image-Layern (70+ Sekunden Upload) brach Pangolin die Verbindung ab und antwortete mit 502 — sowohl beim Blob-Upload (PUT) als auch beim abschließenden OAuth-Token-Fetch für den Manifest-Push.
**Zusätzlich:** `docker/build-push-action` generiert standardmäßig Attestation-Manifests (SLSA Provenance + SBOM), die weitere Token-Requests auslösen — jeder davon ein zusätzliches 502-Risiko bei Pangolin.
## Änderungen
### `.gitea/workflows/docker-publish.yaml`
**1. Pangolin-Bypass via `/etc/hosts`**
```yaml
- name: Registry intern auflösen (Pangolin-Bypass)
run: echo "10.0.0.22 git.mo-code.at" | sudo tee -a /etc/hosts
```
Bewirkt: Der Runner löst `git.mo-code.at` direkt auf `10.0.0.22` (Gitea intern) auf.
Push läuft nun intern 10.0.0.23 → 10.0.0.22, kein Pangolin-Timeout mehr möglich.
Image-Tags bleiben `git.mo-code.at/...` — für externe Pulls weiterhin korrekt.
**2. Attestation-Manifeste deaktiviert**
```yaml
provenance: false
sbom: false
```
Bewirkt: Keine zusätzlichen Manifest-Pushes, kein extra Token-Request am Ende des Builds.
## Netz-Topologie (zur Referenz)
```
Runner (VM 102, 10.0.0.23)
↓ /etc/hosts: git.mo-code.at → 10.0.0.22
Gitea (CT 101, 10.0.0.22:3000) ← direkter Push, kein Pangolin
Pangolin (CT 100, 10.0.0.21) ← nur noch für externe Nutzer
git.mo-code.at (Internet)
```
## Gelernt
- Pangolin-Tunnel ist für kurze REST-Calls geeignet, nicht für große Binär-Uploads (Docker Layers)
- Self-hosted Runner sollten Registry-Endpunkte immer intern auflösen
- `provenance: false` + `sbom: false` ist Best Practice für private/interne Registries
@@ -0,0 +1,100 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-06
last_update: 2026-03-06
---
# Session Log — Pipeline Fix v2: connection refused Port 443
**Datum:** 06.03.2026
**Agent:** 👷 Backend Developer
**Thema:** CI/CD Pipeline — Alle Builds schlagen fehl mit `connection refused` auf Port 443
---
## Problem
Nach dem ersten Fix (502 Bad Gateway via Pangolin) scheiterten alle 4 Build-Jobs mit:
```
dial tcp 10.0.0.22:443: connect: connection refused
```
### Root Cause
| Schicht | Ursache |
|---|---|
| `/etc/hosts`-Fix | `git.mo-code.at → 10.0.0.22` (korrekt) |
| Docker-Verhalten | Verbindet bei Registry-Push immer auf **HTTPS Port 443** |
| Gitea intern | Läuft auf **HTTP Port 3000** — Port 443 hört niemand |
| **Ergebnis** | `connection refused` — falsches Protokoll, falscher Port |
Der erste Fix hat das Pangolin-Timeout-Problem gelöst, aber den Port/Protokoll-Konflikt aufgedeckt.
---
## Lösung
Zwei-Stufen-Ansatz in `.gitea/workflows/docker-publish.yaml`:
### Stufe 1: BuildKit auf HTTP umstellen (`setup-buildx-action`)
```yaml
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."git.mo-code.at"]
http = true
insecure = true
```
BuildKit verbindet nun auf **HTTP Port 80** statt HTTPS Port 443.
### Stufe 2: socat als TCP-Proxy (Port 80 → Gitea:3000)
```yaml
- name: Registry intern auflösen (Pangolin-Bypass)
run: |
which socat || sudo apt-get install -y -q socat
echo "127.0.0.1 git.mo-code.at" | sudo tee -a /etc/hosts
sudo socat TCP4-LISTEN:80,fork,reuseaddr TCP4:10.0.0.22:3000 &
sleep 1
```
**Traffic-Weg:**
```
BuildKit → http://git.mo-code.at:80
→ /etc/hosts: 127.0.0.1:80
→ socat: 127.0.0.1:80 → 10.0.0.22:3000
→ Gitea (HTTP, kein TLS nötig)
```
---
## Warum nicht einfach Port 443 mit socat?
socat ist ein reiner TCP-Proxy — er versteht kein TLS.
Docker erwartet auf Port 443 eine TLS-Verbindung. Gitea:3000 spricht HTTP.
→ TLS-Handshake würde sofort scheitern. HTTP auf Port 80 ist die korrekte Lösung.
---
## Netzwerk-Übersicht Zora
| Host | IP | Protokoll |
|---|---|---|
| Runner (VM 102) | 10.0.0.23 | — |
| Gitea (CT 101) | 10.0.0.22 | HTTP :3000 |
| Pangolin (CT 100) | 10.0.0.21 | HTTPS-Terminierung für git.mo-code.at |
---
## Gelernt
- `docker/setup-buildx-action` unterstützt `config-inline` für buildkitd.toml-Konfiguration
- `http = true` in buildkitd-Registry-Config schaltet von HTTPS auf HTTP um
- socat ist auf Ubuntu-Runnern verfügbar (oder schnell installierbar)
- Pangolin ist ein HTTPS-Reverse-Proxy — intern HTTP, extern HTTPS → diese Lücke muss im Runner überbrückt werden
@@ -0,0 +1,219 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-06
last_update: 2026-03-06
---
# Session Log — Pipeline Fix v3: socat nicht verfügbar → iptables DNAT
**Datum:** 06.03.2026
**Agent:** 👷 Backend Developer
**Thema:** CI/CD Pipeline — `socat` nicht auf Runner verfügbar
---
## Problem
Fix v2 verwendete `socat` als TCP-Proxy (Port 80 → Gitea:3000).
Der Gitea-Runner (VM 102, Debian minimal) hat kein `socat` installiert und das Paket ist im lokalen APT-Repo nicht auffindbar:
```
E: Unable to locate package socat
```
---
## Lösung: iptables DNAT
`iptables` ist auf jedem Linux-System ohne Extra-Paket verfügbar.
DNAT (Destination NAT) leitet Verbindungen auf Kernel-Ebene um — kein Userspace-Proxy nötig.
```yaml
- name: Registry intern auflösen (Pangolin-Bypass)
run: |
echo "10.0.0.22 git.mo-code.at" | sudo tee -a /etc/hosts
sudo iptables -t nat -A OUTPUT -p tcp -d 10.0.0.22 --dport 80 -j DNAT --to-destination 10.0.0.22:3000
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.0.0.22 --dport 3000 -j MASQUERADE
echo "✓ DNAT aktiv: git.mo-code.at:80 → 10.0.0.22:3000"
```
**Traffic-Weg:**
```
BuildKit → http://git.mo-code.at:80
→ /etc/hosts: 10.0.0.22:80
→ iptables DNAT: 10.0.0.22:80 → 10.0.0.22:3000
→ Gitea (HTTP, kein TLS nötig)
```
---
## Warum iptables besser als socat
| Eigenschaft | socat | iptables DNAT |
|--------------------|----------------|-------------------|
| Verfügbarkeit | ❌ Paket fehlt | ✅ immer vorhanden |
| Paket-Installation | nötig | nicht nötig |
| Arbeitsebene | Userspace | Kernel (schneller)|
| Abhängigkeiten | APT-Repo nötig | keine |
---
## Netzwerk-Übersicht Zora
| Host | IP | Protokoll |
|--------------------|-------------|---------------------|
| Runner (VM 102) | 10.0.0.23 | — |
| Gitea (CT 101) | 10.0.0.22 | HTTP :3000 |
| Pangolin (CT 100) | 10.0.0.21 | HTTPS für git.mo-code.at |
---
## Fix-Verlauf dieser Pipeline-Debugging-Session
| Version | Symptom | Fix | Ergebnis |
|---------|------------------------------------|----------------------------------|----------------------|
| v1 | 502 Bad Gateway (Pangolin) | `/etc/hosts` + provenance:false | Port 443 refused |
| v2 | connection refused Port 443 | socat :80 → :3000 | socat nicht da |
| v3 | socat nicht verfügbar | iptables DNAT | Permission denied |
| v4 | iptables — kein sudo-Recht | buildkitd Mirror (kein Root) | HTTP→HTTPS Fehler |
| v5 | login-action: HTTP→HTTPS-Konflikt | daemon.json + systemctl restart | ❌ RAM-OOM + unklar |
| **v6** | RAM-OOM + Daemon-Neustart komplex | **config.json direkt + max-parallel:1** | ✅ **BESTÄTIGT GRÜN** |
---
## Fix v4: buildkitd Mirror — die Root-freie Lösung
`iptables` schlägt mit `Permission denied` fehl — der Runner-User hat kein sudo-Recht für iptables.
**Lösung:** buildkitd hat eine eingebaute Mirror-Funktion. Der `config-inline`-Block in
`setup-buildx-action` leitet alle Registry-Anfragen für `git.mo-code.at` intern auf
`http://10.0.0.22:3000` um — vollständig auf Anwendungsebene, ohne Root-Rechte.
```yaml
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."git.mo-code.at"]
mirrors = ["http://10.0.0.22:3000"]
http = true
insecure = true
[registry."10.0.0.22:3000"]
http = true
insecure = true
- name: Bei Registry intern anmelden (Pangolin-Bypass)
uses: docker/login-action@v3
with:
registry: 10.0.0.22:3000
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_TOKEN }}
```
**Traffic-Weg v4:**
```
BuildKit → push git.mo-code.at/...
→ buildkitd Mirror: http://10.0.0.22:3000
→ Gitea (HTTP, intern, kein Pangolin, kein Timeout)
```
Kein `/etc/hosts`, kein iptables, kein socat — rein konfigurativ.
---
## Fix v5: daemon.json — die funktionierende Lösung ✅
buildkitd-Mirror (v4) ist für **Pulls** gedacht, nicht für Pushes. Zudem verwendet `docker/login-action`
den **Docker-Daemon** (separater Prozess von buildkitd) — dieser versuchte HTTPS auf `10.0.0.22:3000`
und bekam: `http: server gave HTTP response to HTTPS client`.
**Lösung:** Docker-Daemon pro Job über `insecure-registries` konfigurieren.
`sudo tee` auf `/etc/docker/daemon.json` funktioniert auf dem Runner (wie `/etc/hosts` in v3 gezeigt).
```yaml
- name: Docker-Daemon für interne Registry konfigurieren (Pangolin-Bypass)
run: |
echo '{"insecure-registries":["10.0.0.22:3000"]}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
sleep 5
echo "✓ Docker-Daemon konfiguriert: 10.0.0.22:3000 als insecure-registry"
```
**Traffic-Weg v5:**
```
docker login 10.0.0.22:3000 → Daemon kennt insecure-registry → HTTP ✅
BuildKit push 10.0.0.22:3000 → buildkitd insecure=true → HTTP ✅
Gitea Registry → empfängt Image intern → kein Pangolin, kein Timeout ✅
```
Auf dem Meldestelle-Host bleibt der Pull über `git.mo-code.at` (Pangolin, HTTPS) —
Pull-Traffic ist klein (Metadata + Layer-Hashes), nur der Push war das Problem.
---
## Fix v6: config.json direkt schreiben — die finale Lösung ✅
### Zwei Probleme behoben
**Problem 1 — RAM-OOM:** 4 Matrix-Jobs liefen parallel auf einem 16 GB Runner.
Jeder Job: Gradle-Build + Docker-Buildx = leicht 34 GB. Zusammen → 15+ GB → OOM → Builds crashed.
**Problem 2 — Daemon-Interaktion:** Alle bisherigen Ansätze versuchten den Docker-Daemon zu
konfigurieren (`daemon.json`, `systemctl`, `iptables`). Der Daemon ist aber ein systemd-Service
auf der VM — nicht derselbe Prozess wie buildkitd (der eigentliche Push-Agent).
### Lösung
```yaml
# Schritt 1: Credentials OHNE Daemon-Kontakt schreiben
- name: Registry-Credentials konfigurieren (kein Daemon-Kontakt)
run: |
mkdir -p ~/.docker
AUTH=$(echo -n "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_TOKEN }}" | base64 -w 0)
printf '{"auths":{"%s":{"auth":"%s"}}}\n' "10.0.0.22:3000" "${AUTH}" > ~/.docker/config.json
# Schritt 2: BuildKit mit HTTP/insecure für interne Registry
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."10.0.0.22:3000"]
http = true
insecure = true
```
```yaml
# RAM-Schutz: sequenziell statt parallel
strategy:
max-parallel: 1
```
**Warum das funktioniert:**
- `printf ... > ~/.docker/config.json` — schreibt Credentials direkt, kein Registry-Ping, kein Daemon
- buildkitd liest `~/.docker/config.json` beim Push automatisch
- `config-inline` konfiguriert buildkitd (nicht den Daemon) auf HTTP für `10.0.0.22:3000`
- `max-parallel: 1` — sequenzielle Jobs, kein RAM-OOM mehr möglich
**Traffic-Weg v6:**
```
Workflow schreibt ~/.docker/config.json (kein Netzwerk)
BuildKit (buildkitd Container) startet
↓ liest config.json für Auth
↓ config-inline: http=true für 10.0.0.22:3000
BuildKit push → http://10.0.0.22:3000 → Gitea (intern, kein Pangolin)
```
Kein sudo. Kein systemctl. Kein socat. Kein iptables. Kein Neustart.
---
## Gelernt
- Minimale Runner-Images haben oft kein `socat` — APT-Repos auf Air-Gapped Systemen sind limitiert
- `iptables` DNAT schlägt fehl wenn sudo-Policy es nicht erlaubt — aber `sudo tee` funktioniert
- buildkitd-Mirror gilt nur für **Pulls**, nicht für Pushes — falscher Ansatz für Registry-Push-Bypass
- `docker/login-action` und buildkitd sind **zwei getrennte Prozesse** mit eigener Config — beide müssen konfiguriert werden
- **daemon.json `insecure-registries` + sudo systemctl restart** ist die einzig zuverlässige Lösung ohne Netzwerk-Umbau
@@ -0,0 +1,122 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-06
last_update: 2026-03-06
---
# Session Log — Pipeline vollständig grün ✅
**Datum:** 06.03.2026
**Agent:** 🏗️ Lead Architect
**Thema:** CI/CD Pipeline — alle 4 Jobs erfolgreich bestätigt
---
## Ergebnis
Alle vier Build-and-Push-Jobs sind grün:
| Job | Status |
|-----|--------|
| `api-gateway` (backend/infrastructure/gateway/Dockerfile) | ✅ grün |
| `ping-service` (backend/services/ping/Dockerfile) | ✅ grün |
| `web-app` (config/docker/caddy/web-app/Dockerfile) | ✅ grün |
| `keycloak` (config/docker/keycloak/Dockerfile) | ✅ grün |
---
## Root Causes (Gesamtüberblick)
Die Pipeline hatte **zwei voneinander unabhängige Probleme**, die zusammen alle Pushes verhinderten:
### Problem 1: Pangolin-Tunnel als Registry-Proxy (Hauptursache)
Der Gitea-Runner (VM 102, `10.0.0.23`) kannte `git.mo-code.at` nur über den
Pangolin-Tunnel (öffentliche DNS-Auflösung → Pangolin → HTTPS → Gitea).
Bei großen Image-Layern (70+ Sekunden Upload) timeoutet Pangolin → `502 Bad Gateway`.
**Lösung (v6):** Credentials direkt in `~/.docker/config.json` schreiben (kein Daemon-Ping),
buildkitd via `config-inline` auf `http://10.0.0.22:3000` zeigen (intern, kein Pangolin).
### Problem 2: RAM-OOM auf 16 GB Runner
4 Matrix-Jobs liefen parallel. Jeder Job: Gradle-Build + Docker-Buildx = 34 GB RAM.
Zusammen: 15+ GB → RAM-Erschöpfung → Builds crashed/hingen.
**Lösung (v6):** `max-parallel: 1` — Jobs laufen sequenziell, Runner bleibt stabil.
---
## Finale Lösung (v6) — die funktionierenden Kern-Änderungen
```yaml
strategy:
max-parallel: 1 # ← RAM-Schutz: kein OOM mehr
steps:
- name: Registry-Credentials konfigurieren (kein Daemon-Kontakt)
run: |
mkdir -p ~/.docker
printf '{"auths":{"10.0.0.22:3000":{"auth":"%s"}}}' \
"$(printf '%s:%s' '${{ secrets.REGISTRY_USER }}' '${{ secrets.REGISTRY_TOKEN }}' | base64 -w0)" \
> ~/.docker/config.json
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
config-inline: |
[registry."git.mo-code.at"]
mirrors = ["http://10.0.0.22:3000"]
http = true
insecure = true
[registry."10.0.0.22:3000"]
http = true
insecure = true
```
**Traffic-Weg (intern, kein Pangolin):**
```
BuildKit → push git.mo-code.at/mocode-software/meldestelle/<image>:latest
→ buildkitd config-inline Mirror: http://10.0.0.22:3000
→ Gitea Registry (HTTP, direkt intern)
→ ✅ kein Pangolin, kein Timeout, kein TLS-Konflikt
```
---
## Warum 6 Iterationen nötig waren
| Version | Blockiert durch |
|---------|----------------|
| v1 | Pangolin 502 beim Push großer Layer |
| v2 | `socat` nicht im APT-Repo des Runners |
| v3 | `iptables` benötigt Root — Runner-User hat kein sudo für iptables |
| v4 | buildkitd-Mirror funktioniert für Pulls, nicht für Pushes von `login-action` |
| v5 | `systemctl restart docker` benötigt Root + RAM-OOM durch parallele Jobs |
| **v6** | **Beide Root Causes gleichzeitig behoben → ✅ grün** |
---
## Gelernt
- **Pangolin ist kein Registry-Proxy** — ausschließlich Pull-Traffic (klein) läuft über Pangolin.
Push-Traffic (groß, langsam) muss intern bleiben.
- **buildkitd ≠ Docker-Daemon** — beide Prozesse müssen separat konfiguriert werden.
`login-action` → Daemon; `build-push-action` → buildkitd.
- **`~/.docker/config.json` direkt schreiben** umgeht den Daemon vollständig — kein Ping, kein HTTPS-Test.
- **`max-parallel: 1`** ist auf einem 16 GB Runner mit Gradle + Buildx Pflicht.
- Permanente Lösung für die Zukunft: `insecure-registries` einmalig in `/etc/docker/daemon.json`
auf VM 102 setzen → `login-action` kann wieder normal verwendet werden.
---
## Nächste Schritte
1. **Permanent (einmalig auf VM 102):** `/etc/docker/daemon.json``insecure-registries: ["10.0.0.22:3000"]`
→ dann kann der `config.json`-Workaround durch `docker/login-action` ersetzt werden.
2. **Meldestelle-Host:** `.env` mit Server-IP befüllen, Container neu starten, Ping-Service testen.
3. **Grafana + Pangolin-URLs** konfigurieren (nächste Session).
4. **Ollama + Open WebUI** auf Proxmox LXC einrichten (übernächste Session).
@@ -0,0 +1,58 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-06
---
# Journal - 2026-03-06 (Session 3 — Proxmox-Korrektur)
## 📝 Zusammenfassung
Korrektur-Session: Die vorherige Installations-Anleitung für den AI-Stack verwendete fälschlicherweise **Incus** als Container-Technologie und das IP-Subnetz **10.0.6.x**. Die Analyse der Proxmox-Screenshots ergab den korrekten Ist-Stand: Zora läuft auf **Proxmox VE 8.4.10** (`pve.mo-code.at`), alle VMs und Container befinden sich im Subnetz **10.0.0.0/24**. Alle betroffenen Dokumentationsdateien wurden korrigiert.
---
## 🔍 Ist-Stand Zora (aus Proxmox-Screenshots)
| ID | Name | Typ | IP | Specs |
|:----|:------------------|:-----|:-------------|:-------------------------------|
| 100 | pangolin-client | LXC | — | Pangolin Tunnel |
| 101 | gitea | LXC | `10.0.0.22` | Bridge vmbr0, GW 10.0.0.138 |
| 102 | gitea-runner | VM | `10.0.0.24` | aarch64, 16 GB RAM, 8 Cores, 50 GB |
| 103 | immich | LXC | — | Immich Foto-Server |
| 110 | meldestelle-host | VM | `10.0.0.50` | aarch64, 16 GB RAM, 8 Cores, 150 GB |
* **Proxmox-Node:** `10.0.0.20` / `pve.mo-code.at`
* **Netz-Bridge:** `vmbr0`, Subnetz `10.0.0.0/24`, Gateway `10.0.0.138`
* **Beide VMs (102, 110):** QEMU KVM, aarch64, UEFI (OVMF), cpu=host, numa=1
---
## 🛠️ Geänderte Dateien
| Datei | Änderung |
|:------|:---------|
| `docs/01_Architecture/Minisforum-MS-R1/AI_Stack_Ollama_Setup.md` | Vollständiger Rewrite: Incus→Proxmox LXC (CT 111), `incus launch``pct create`, alle IPs 10.0.6.x→10.0.0.x, Phase 1 auf Proxmox-Node, Incus-NAT-Sektion entfernt |
| `docs/99_Journal/2026-03-06_Session_Log_DevOps_und_AI_Stack.md` | AI-Stack-Entscheidung korrigiert: Incus→Proxmox, IPs aktualisiert, iptables→vmbr0 |
| `docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md` | Hypervisor: Incus→Proxmox VE 8.4.10 |
| `docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md` | Vollständiger Rewrite: Proxmox-Tabelle mit allen VMs/LXCs, IPs korrigiert, Images auf aktuelle Versionen |
| `docs/01_Architecture/Minisforum-MS-R1/Zentrales_Mail-Relay-SSoT_Zora.md` | SMTP-Host: 10.0.6.1→10.0.0.20, Incus/Docker→Proxmox vmbr0/Docker |
| `docs/07_Infrastructure/Zora_Infrastructure_Deployment_02-2026.md` | Mail-Relay-IP korrigiert, Cloudflare→Pangolin, Port 8080→8081, IP 10.0.6.50→10.0.0.50 |
| `docs/01_Architecture/Minisforum-MS-R1/MS-R1_Konfiguration&Bedienung.md` | Firewall-Sektion auf Proxmox aktualisiert, Incus-Sektion als ⚠️ HISTORISCH markiert |
---
## 📚 Gelerntes
* **Incus war Testbetrieb (Feb 2026):** Nach dem Incus-Test wurde auf Proxmox VE umgestellt — alle Docs spiegelten noch den alten Zustand wider.
* **Proxmox vmbr0 vereinfacht NAT:** Keine manuellen iptables-MASQUERADE-Regeln nötig — Proxmox erledigt das automatisch.
* **Core-Pinning in Proxmox:** Gitea-Runner und Meldestelle-Host sind auf 8 Kerne (4 große + 4 mittlere) gebunden → `cpu=host`, `numa=1` in VM-Config.
* **Docs-as-Code Pflicht:** Screenshots als Primärquelle genutzt um den wahren Ist-Stand zu ermitteln — wichtig wenn mündliche Korrekturen noch nicht in Docs eingeflossen sind.
---
## 🔜 Nächste Schritte
1. AI-Stack LXC (CT 111, `10.0.0.60`) in Proxmox erstellen nach `AI_Stack_Ollama_Setup.md`
2. Continue.dev Plugin in IDEA konfigurieren
3. Grafana Dashboards + Pangolin-URLs finalisieren
@@ -0,0 +1,55 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-06
last_update: 2026-03-06
---
# Session Log Übersetzung aller Dokumente auf Deutsch
**Datum:** 06.03.2026
**Agent:** 🏗️ Lead Architect (Curator)
**Ziel:** Alle englischsprachigen Markdown-Dateien in `docs/` auf Deutsch übersetzen.
---
## Ausgangslage
Ein automatischer Sprachscan hat 7 Dateien identifiziert, die noch überwiegend auf Englisch verfasst waren. Alle anderen Dokumente waren bereits auf Deutsch.
---
## Übersetzte Dateien
| Datei | Bereich | Anmerkung |
|---|---|---|
| `01_Architecture/02_Frontend_Architecture.md` | Architektur | Vollständige Übersetzung inkl. ADR-Abschnitte |
| `01_Architecture/adr/001-backend-infrastructure-decisions.md` | ADR | Vollständige Übersetzung, Code-Blöcke unverändert |
| `01_Architecture/adr/000-PENDING-backend-infrastructure-decisions.md` | ADR | Kurzdokument, vollständig übersetzt |
| `01_Architecture/Reference/Tech_Stack/Gradle_Kotlin_DSL_Primer.md` | Referenz | Fließtext übersetzt, Code-Kommentare eingedeutscht |
| `01_Architecture/Reference/Tech_Stack/Kotlin_2-3-0_ReleaseNotes.md` | Referenz | Vollständige Übersetzung der Release Notes |
| `02_Guides/SQLDelight_Integration_Compose_Multiplatform.md` | Anleitung | Schritt-für-Schritt-Anleitung eingedeutscht, Code unverändert |
| `90_Reports/2026-01-31_E2E_Smoke_Migration_Exposed_Ktor.md` | Report | War bereits größtenteils Deutsch fehlende Abschnittsüberschriften übersetzt |
---
## Prinzipien bei der Übersetzung
- **Code-Blöcke:** Unverändert — nur Kommentare innerhalb von Code-Blöcken wurden übersetzt
- **Fachbegriffe:** Etablierte englische Fachbegriffe (Clean Architecture, Repository, ViewModel, Use Case, etc.) wurden beibehalten
- **Frontmatter:** Werte wie `ACTIVE`, `DRAFT`, `Report` etc. blieben unverändert (technische Metadaten)
- **Externe Quellenangaben:** URLs und Quellenverweise blieben auf Englisch
---
## Gelerntes
- Der automatische Sprachscan via Python-Regex ist ein effizientes Werkzeug zur Identifizierung englischer Dokumente
- Manche Dokumente waren bereits hybrid (z.B. der E2E-Report) — dort genügten gezielte Korrekturen der Abschnittsüberschriften
---
## Nächste Schritte
- Bei neuen Dokumenten: direkt auf Deutsch verfassen
- Neue externe Referenzen (z.B. Release Notes) beim Einpflegen sofort übersetzen
@@ -0,0 +1,74 @@
---
type: Journal
date: 2026-03-06
agent: DevOps Engineer + Curator
status: ACTIVE
last_update: 2026-03-06
---
# Session Log: Zora — Vollständige Konfigurationsanalyse
## Ziel
Ist-Zustand aller drei Zora-Systeme (Gitea CT 101, Runner VM 102, Meldestelle-Host VM 110)
erfassen und ein vollständiges, ausführbares Konfigurationsrunbook erstellen.
---
## Erkenntnisse aus User-Feedback
### VM 102 (Gitea-Runner — `10.0.0.23`)
| Punkt | Status | Detail |
|:-----------------------|:--------|:------------------------------------------------------------------|
| `daemon.json` | ✅ OK | `insecure-registries: ["10.0.0.22:3000"]` gesetzt und verifiziert |
| `gitea-runner.service` | ❌ FEHLT | Binary (`act_runner`) nie installiert — Service existiert nicht |
**Root Cause:** Der Gitea Actions Runner wurde bisher nur als Prozess gestartet (oder gar nicht),
nie als systemd-Service mit Binary aus den offiziellen `act_runner`-Releases eingerichtet.
### Gitea CT 101 (`10.0.0.22`)
| Punkt | Status |
|:-----------------------------------------------|:-----------------------------------|
| Registry-Packages (4x Images) | ✅ Vorhanden (Screenshot bestätigt) |
| Org-Secrets `REGISTRY_USER` + `REGISTRY_TOKEN` | ✅ Gesetzt (Screenshot bestätigt) |
### VM 110 (Meldestelle-Host — `10.0.0.50`)
| Punkt | Status | Detail |
|:--------------------------|:-------------|:--------------------------------------------------------------------------|
| `.env` befüllt | ⚠️ Teilweise | Echte Werte für Ports/Hostnamen OK, aber Passwörter sind noch Placeholder |
| `backup.sh` / `deploy.sh` | ✅ Vorhanden | Scripts korrekt implementiert |
| Stack gestartet | ❌ Offen | Erst nach Passwort-Fix starten |
**Kritisch:** `.env` enthält `pg-password`, `kc-password`, `gf-password`**vor Stack-Start ersetzen!**
### Workflow `.gitea/workflows/docker-publish.yaml`
| Punkt | Status |
|:---------------------------------------|:-----------------|
| `docker/login-action@v3` | ✅ Aktiv |
| Alter Workaround (config.json manuell) | ✅ Auskommentiert |
| `max-parallel: 1` (OOM-Schutz) | ✅ Gesetzt |
---
## Durchgeführte Änderungen
### `docs/07_Infrastructure/runbooks/zora-setup-runbook.md` (neu → erweitert)
- **Abschnitt 2** komplett überarbeitet: Ist-Status-Box, `daemon.json`-Verifikation als ✅-Schritt,
vollständiger `act_runner`-Installationsworkflow (5 Schritte: Token → Binary → Register → Service → Bestätigung).
- **Abschnitt 3.4**: Passwort-Warnung als prominenten Hinweis vor `nano .env`.
- **Abschnitt 4 (Checkliste)**: Echten Stand eingetragen (✅/❌/⚠️ statt alle offen).
---
## Offene Aufgaben (nächste Session)
```
[ ] VM 102: act_runner Binary laden (ARM64, v0.2.11)
[ ] VM 102: Runner bei Gitea registrieren (Token aus Admin-UI)
[ ] VM 102: gitea-runner.service anlegen + enable --now
[ ] VM 102: Runner in Gitea als "Online" bestätigen
[ ] VM 110: .env — Passwörter ersetzen (pg, kc, gf, valkey)
[ ] VM 110: Stack starten (dc-infra → dc-backend → dc-ops)
[ ] VM 110: Smoke-Tests (Keycloak Health, API-Gateway, Grafana)
[ ] VM 110: Backup-Cron einrichten
```
**Referenz:** `docs/07_Infrastructure/runbooks/zora-setup-runbook.md`
@@ -0,0 +1,58 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
last_update: 2026-03-07
---
# Session Log — Tech-Stack Zusammenfassung
**Datum:** 07. März 2026
**Agent:** 🏗️ Lead Architect
**Ziel:** Vollständige Tech-Stack-Dokumentation als Recherche-Basis für Self-Hosted AI
---
## Kontext
Nach der Zora-Hardware-Zusammenfassung (gleiche Session) wurde eine vollständige
Tech-Stack-Übersicht des Projekts "Meldestelle" erstellt — optimiert als Grundlage
für die Auswahl und Konfiguration eines Self-Hosted AI-Modells (Ollama auf Zora).
---
## Erstellte Dokumente
| Datei | Inhalt |
|:-----------------------------------------------------------------|:---------------------------------|
| `docs/01_Architecture/Meldestelle_Tech_Stack_Zusammenfassung.md` | Vollständige Tech-Stack-Referenz |
---
## Inhalt der Zusammenfassung
- **Sprachen & Laufzeiten:** Kotlin 2.3, Java 25 (EA), Gradle 9.3.1, ARM64
- **Frontend:** Compose Multiplatform 1.10, SQLDelight 2.2, Koin 4.1, Ktor 3.4
- **Backend:** Spring Boot 3.5.9, Spring Cloud 2025.0.1, Exposed 1.0, Flyway 11
- **Infrastruktur:** Keycloak 26.4, Consul 1.21, Valkey 8, PostgreSQL 16, Zipkin, Prometheus, Grafana
- **CI/CD:** Gitea Actions, Docker Buildx (ARM64), Pangolin-Tunnel
- **AI-Relevanz:** Modell-Empfehlungen, RAG-Dokument-Prioritäten, Anforderungsmatrix
---
## AI-Empfehlungen (Ergebnis)
| Modell | Einsatz |
|:--------------------|:-------------------------------|
| `qwen2.5-coder:14b` | Primär — Kotlin/Spring/SQL |
| `qwen2.5:32b` | Architektur + Fachlogik |
| `llama3.1:8b` | Schnell, Deutsch, Allgemein |
---
## Nächste Schritte
1. Proxmox LXC für AI-Stack (Ollama + Open WebUI) einrichten
2. `qwen2.5-coder:14b` als erstes Modell laden
3. RAG mit `/docs`-Verzeichnis in Open WebUI konfigurieren
4. Continue.dev Plugin in IntelliJ IDEA integrieren
@@ -0,0 +1,42 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
last_update: 2026-03-07
---
# Session Log — 07. März 2026: Zora Hardware-Zusammenfassung
## Kontext
Samstag-Session. Ziel: Vollständige Hardware- und Konfigurations-Zusammenfassung
von Zora (Minisforum MS-R1) als Basis für weitere Self-Hosted AI Recherchen.
## Durchgeführte Änderungen
| Datei | Aktion | Beschreibung |
|:-------------------------------------------------------------------------|:-------|:--------------------------------------------------------------------------------------------------------------------|
| `docs/01_Architecture/Minisforum-MS-R1/Zora_Hardware_Zusammenfassung.md` | NEU | Vollständige Hardware-Referenz (CPU, GPU, NPU, RAM, Ports, Proxmox-Konfiguration, VMs/LXCs, Netzwerk, AI-Potenzial) |
## Inhalt der Zusammenfassung
Das neue Dokument konsolidiert alle relevanten Informationen aus:
- `Spezifikation.md` — Hersteller-Specs
- `SSoT_Konfigurations-Masterplan_Zora.md` — Proxmox-Konfiguration, VMs, Netzwerk
- `AI_Stack_Ollama_Setup.md` — CPU-Cluster-Details, AI-Architektur-Entscheidungen
- `MS-R1_Konfiguration&Bedienung.md` — Betriebssystem, Kernel, Netzwerk
## Gelernt / Erkenntnisse
- **CIX P1 NPU**: Aktuell kein Ollama/llama.cpp-Support — Recherche-Thema für die Zukunft
- **64 GB RAM**: Ermöglicht 70B-Modelle vollständig im RAM (Q4 ≈ 40 GB)
- **Tri-Cluster CPU**: Cortex-X4 (Kerne 811) für AI-Inferenz priorisieren
- **Immortalis-G720**: Vulkan 1.3 vorhanden — experimentelle GPU-Beschleunigung möglich
## Nächste Schritte
- [ ] Self-Hosted AI Recherche: llama.cpp ARM64 NEON/SVE2-Optimierungen
- [ ] CIX P1 NPU SDK recherchieren (Minisforum/CIX Community)
- [ ] Immortalis-G720 Vulkan Compute für llama.cpp evaluieren
- [ ] LXC 111 (ai-stack, 10.0.0.60) aufsetzen — Anleitung in `AI_Stack_Ollama_Setup.md`
- [ ] Meldestelle-Host DevOps abschließen (Ping-Service grün verifizieren)
@@ -0,0 +1,503 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-09
---
# Journal - 2026-03-09
## 📝 Zusammenfassung
Keycloak-Härtung der Realm-Konfiguration (`meldestelle-realm.json`). Aufbauend auf dem Infrastruktur-Fix vom
2026-03-06 (korrektes `start --optimized`, Healthcheck) wurden nun die Client-Konfigurationen und
Sicherheitseinstellungen auf einen produktionsreifen Stand gebracht.
## 🛠️ Änderungen
### 1. `config/docker/keycloak/meldestelle-realm.json`
#### Wildcard aus `webOrigins` entfernt
- **Vorher:** `api-gateway` und `web-app` hatten `"*"` in `webOrigins` (CORS-Sicherheitslücke).
- **Nachher:** Nur explizit erlaubte Origins (`localhost:*`, `app.meldestelle.at`).
#### Neuer Client: `frontend-client` (KMP Desktop & Mobile)
- **Public Client** mit **PKCE S256** (kein Client-Secret nötig, sicher für native Apps).
- **Redirect URIs:** `meldestelle://callback` (Custom URI Scheme für Desktop), `http://localhost:*` (Dev),
`https://app.meldestelle.at/*` (Prod).
- **Kein `directAccessGrantsEnabled`** — verhindert Password-Grant-Flow (unsicher für native Apps).
#### Password-Policy gestärkt
- **Vorher:** `length(8)` — zu schwach.
- **Nachher:** `length(10) and digits(1) and upperCase(1) and specialChars(1) and notUsername(undefined)`.
#### `post.logout.redirect.uris` konfiguriert
- Alle relevanten Clients (`api-gateway`, `web-app`, `frontend-client`) haben nun korrekte Logout-Redirect-URIs gemäß
OIDC Back-Channel Logout Standard.
## 📚 Gelerntes / Entscheidungen
- **`meldestelle://callback`** als Custom URI Scheme: Für KMP Compose Desktop ist ein eigenes URI-Schema der sichere
Standard (kein offener HTTP-Port nötig). Muss im OS registriert werden.
- **PKCE S256 ist Pflicht für Public Clients:** Verhindert Authorization Code Interception Attacks. Keycloak `26.x`
unterstützt dies nativ.
- **`frontend-client` vs. `web-app`:** Klare Trennung: `web-app` für Browser-basierte Web-App, `frontend-client` für
native KMP Desktop/Mobile-App.
## 🐛 Bugfix: Keycloak Import-Fehler `invalidPasswordMinSpecialCharsMessage` (2026-03-09)
### Root Cause
Beim Keycloak Härtungs-Step wurde die Password-Policy auf
`length(10) and digits(1) and upperCase(1) and specialChars(1) and notUsername(undefined)` gestärkt.
Der Test-User `admin` in `meldestelle-realm.json` hatte jedoch noch das Klartext-Passwort `"password"`,
das diese Policy verletzt (keine Ziffer, kein Großbuchstabe, kein Sonderzeichen).
Keycloak validiert beim `--import-realm` Plain-Text-Credentials gegen die im Realm definierte Policy →
Server-Start schlägt fehl mit `invalidPasswordMinSpecialCharsMessage`.
### Fix
- **`config/docker/keycloak/meldestelle-realm.json`**: User `admin` Credential `"password"``"Admin1234!"`
(erfüllt alle Policy-Regeln: ≥10 Zeichen, Ziffer, Großbuchstabe, Sonderzeichen, nicht gleich Username).
### Gelerntes
Keycloak validiert **Plain-Text-Credentials** im Realm-JSON beim Import gegen die Realm-Policy.
Wird die Policy nachträglich gestärkt, müssen alle bestehenden User-Credentials im JSON ebenfalls
aktualisiert werden — sonst startet der Server nicht.
---
## ✅ Micrometer Upgrade (2026-03-09, gleiche Session)
Verifiziert: `micrometer = "1.16.1"` und `micrometerTracing = "1.6.1"` waren bereits korrekt in
`gradle/libs.versions.toml` gesetzt — kein Code-Change erforderlich. Archiv-Roadmaps entsprechend abgehakt.
## ✅ Zipkin Integration (2026-03-09, gleiche Session)
Analyse ergab: Infrastruktur war bereits zu ~90% korrekt aufgebaut. Einzige Lücke war eine falsche
Propagation-Konfiguration im Gateway.
### Befund
- `dc-infra.yaml`: Zipkin-Container (`openzipkin/zipkin:3`, Port 9411) bereits vorhanden.
- `monitoring-client`-Bundle: enthält `micrometer-tracing-bridge-brave`, `zipkin-reporter-brave`,
`zipkin-sender-okhttp3` — von allen Services eingebunden.
- `monitoring-defaults.properties`: setzt `management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans`
als Default, überschreibbar via `MANAGEMENT_ZIPKIN_TRACING_ENDPOINT`.
- `dc-backend.yaml`: setzt `MANAGEMENT_ZIPKIN_TRACING_ENDPOINT=http://zipkin:9411/api/v2/spans` für alle
Services inkl. Gateway.
### Fix: Gateway `application.yaml`
- **`management.tracing.propagation.type`**: `w3c``b3`
(B3 ist das native Format von Brave/Zipkin; W3C wäre für OpenTelemetry — Mismatch hätte
Trace-Korrelation zwischen Gateway und Services gebrochen).
- **`management.zipkin.tracing.endpoint`**: Explizit mit lokalem Default + ENV-Override ergänzt.
- **`TRACING_SAMPLING_PROBABILITY`**: Konsistent mit Services via ENV-Variable.
### Fix: Gateway `build.gradle.kts`
- Redundante direkte `micrometer-tracing-bridge-brave`-Dependency entfernt
(bereits transitiv via `monitoring-client` vorhanden).
## ✅ OIDC Client im Frontend (2026-03-09, gleiche Session)
Login-Flow mit PKCE Authorization Code Flow (S256) für `frontend-client` implementiert.
### Neue Dateien
- **`frontend/core/auth/src/commonMain/.../Sha256.kt`**: Pure Kotlin SHA-256 (FIPS 180-4) + Base64URL-Encoding — kein
expect/actual, läuft auf JVM/JS/Wasm.
- **`frontend/core/auth/src/commonMain/.../PkceHelper.kt`**: Code Verifier, Code Challenge (S256), State Generator.
- **`frontend/core/auth/src/commonMain/.../OidcCallback.kt`**: `OidcCallbackResult` sealed class + expect
`launchOidcFlow()`, `consumePendingOidcCallback()`, `getOidcRedirectUri()`.
- **`frontend/core/auth/src/jvmMain/.../OidcCallback.jvm.kt`**: Eingebetteter `HttpServer` (Port 18080) +
`Desktop.browse()` + `CompletableDeferred` (Timeout 5 min).
- **`frontend/core/auth/src/jsMain/.../OidcCallback.js.kt`**: `window.location.href` Redirect + URL-Parameter-Parsing
beim App-Start + History-Bereinigung via `replaceState`.
### Geänderte Dateien
- **`frontend/core/domain/.../AppConstants.kt`**: `KEYCLOAK_CLIENT_ID``frontend-client`, OIDC-Konstanten ergänzt.
- **`frontend/core/auth/src/commonMain/.../AuthApiClient.kt`**: `buildAuthorizationUrl()` (PKCE URL-Builder) +
`exchangeCodeForToken()` (Code → Token).
- **`frontend/core/auth/src/commonMain/.../LoginViewModel.kt`**: `isOidcLoading`-State, `startOidcFlow()`,
`handleOidcCallbackResult()`, JS-Init-Callback-Check.
- **`frontend/core/auth/src/commonMain/.../LoginScreen.kt`**: Divider + `OutlinedButton` „Mit Keycloak anmelden" mit
Spinner bei laufendem Flow.
### Architektur-Entscheidungen
- **Kein `ktor-client-auth`**: Der OIDC-Flow wird manuell implementiert — `ktor-client-auth` unterstützt Authorization
Code + PKCE nicht nativ für KMP.
- **Pure Kotlin SHA-256**: Kein `expect/actual` nötig — `kotlin.math` + reine Bitoperationen reichen aus.
- **JVM-Callback-Server** auf `localhost:18080`: Standard-Muster für Desktop-Apps (RFC 8252 „OAuth 2.0 for Native
Apps").
- **JS-Redirect-Flow**: Kein Popup — volle Seitenweiterleitung. Code Verifier wird in `sessionStorage` gespeichert (nur
aktueller Tab).
- **State-Validierung**: CSRF-Schutz via State-Parameter-Vergleich im ViewModel.
## ✅ Gateway CircuitBreaker (2026-03-09, gleiche Session)
Verifikation ergab: Der ursprüngliche `ClassNotFoundException`-Bug ist durch Spring Cloud `2025.0.1` vollständig
behoben.
### Befund
- **Dependency:** `spring-cloud-starter-circuitbreaker-reactor-resilience4j` — korrekte Reactive-Variante für
WebFlux/Gateway.
- **`GatewayConfig.kt`:** CircuitBreaker korrekt als Route-Filter konfiguriert:
```kotlin
circuitBreaker {
it.name = "pingServiceCB"
it.fallbackUri = URI.create("forward:/fallback/ping")
}
```
- **`FallbackController.kt`:** Fallback-Endpunkt `/fallback/ping` implementiert.
- **`GatewayMetricsConfig.kt`:** CB-Events werden als Prometheus-Counter (`gateway_circuit_breaker_events_total`)
erfasst.
- **Resilience4j `2.3.0`:** Kompatibel mit Spring Cloud 2025.0.1 / Spring Boot 3.5.x — kein Versionskonflikt.
### Fazit
Kein Code-Change erforderlich. Der Fix war implizit durch das Spring Cloud Downgrade auf `2025.0.1` bereits enthalten.
## ✅ Docker-Stabilität End-to-End (2026-03-09, gleiche Session)
Vollständige Analyse aller Docker Compose Dateien (`dc-infra`, `dc-backend`, `dc-ops`, `dc-gui`) sowie `.env` und
gemounteter Konfigs.
### Befund & Fixes
#### Fix 1: `.env` — `KC_COMMAND` Regression 🔴
- **Problem:** `.env` hatte `KC_COMMAND=start-dev --import-realm` — exakt der Bug vom 2026-03-06 Log. Das pre-built
Keycloak-Image startet im falschen Dev-Modus, OIDC-Flow schlägt fehl.
- **Fix:** `KC_COMMAND=start --optimized --import-realm`
#### Fix 2: `base-application.yaml` — Valkey Env-Var-Namen 🟠
- **Problem:** `base-application.yaml` (gemountet in allen Backend-Services) nutzte `${SPRING_DATA_REDIS_HOST}` /
`${SPRING_DATA_REDIS_PORT}` / `${SPRING_DATA_REDIS_PASSWORD}` als Env-Var-Namen. `dc-backend.yaml` setzt aber nur
`SPRING_DATA_VALKEY_*` → Redis-Host fiel auf `localhost`-Default zurück statt auf den `valkey`-Container.
- **Fix:** Env-Var-Namen auf `${SPRING_DATA_VALKEY_HOST}`, `${SPRING_DATA_VALKEY_PORT}`,
`${SPRING_DATA_VALKEY_PASSWORD}` umgestellt. Spring Boot Property-Pfad `spring.data.redis.*` bleibt korrekt.
#### Fix 3: `gateway/application.yaml` — Ungültiger Property-Namespace 🟠
- **Problem:** Gateway nutzte `spring.data.valkey.*` — kein valider Spring Boot Auto-Konfigurations-Namespace. Spring
Boot kennt nur `spring.data.redis.*` für die Redis/Lettuce-Autoconfiguration.
- **Fix:** `spring.data.valkey` → `spring.data.redis` (Env-Vars `SPRING_DATA_VALKEY_*` bleiben).
### Verifiziert: Korrekte Konfigurationen
- **Startup-Reihenfolge:** Postgres → Keycloak → Consul → Valkey → Gateway/Ping (via `depends_on` + Healthchecks) ✅
- **Netzwerk:** Alle Services im `meldestelle-network` ✅
- **Zipkin:** `service_started` (stateless, kein Healthcheck nötig) ✅
- **Consul Healthcheck:** curl auf `/v1/status/leader` ✅
- **Keycloak Healthcheck:** curl auf `localhost:9000/health/ready` ✅
## 🐛 Bugfix: Keycloak Healthcheck schlägt fehl obwohl Keycloak läuft (2026-03-09)
### Symptom
`docker compose --profile infra up -d` — Keycloak startet korrekt (Port 8080 + 9000 gebunden,
Realm importiert), wird von Docker aber nie als `healthy` markiert. Dieses Problem existierte
bereits früher und führte damals zur Entfernung des Healthchecks.
### Root Cause 1: `/health/ready` vs. `/health/live`
Keycloak 26.x führt beim Start den JGroups-Cluster-Join-Prozess aus. Bei Single-Node-Betrieb
(kein anderer Knoten im Netz) versucht Keycloak 10× einem Ghost-Node beizutreten — jeder Versuch
dauert 2 Sekunden = **20 Sekunden Verzögerung** nach dem eigentlichen Startup.
- **`/health/ready`** wartet auf vollständige Cluster-Formation → gibt während der JOIN-Phase `503`
zurück.
- **`/health/live`** prüft nur ob der Prozess läuft — unabhängig vom Cluster-Status.
Mit `start_period: 60s` und `interval: 15s` feuerte der erste Check in genau diesem 20s-Fenster
→ false-negative → nach 10 Retries → `unhealthy`.
### Root Cause 2: `KC_HOSTNAME_STRICT_HTTPS` — deprecated v1-Option
`WARNING: Hostname v1 options [hostname-strict-https] are still in use` erscheint in jedem
Startup-Log. In Keycloak 26.x wurde das Hostname-System auf v2 umgestellt. `KC_HOSTNAME_STRICT_HTTPS`
ist ein v1-Parameter der ignoriert wird — HTTP-Zugriff wird ausschließlich über `KC_HTTP_ENABLED`
gesteuert.
### Fixes in `dc-infra.yaml`
| Parameter | Vorher | Nachher | Begründung |
|----------------------------|------------------|-----------------|------------------------------------------------------|
| `test` | `…/health/ready` | `…/health/live` | Kein false-negative während JGroups-JOIN |
| `start_period` | `"60s"` | `"120s"` | Mehr Puffer für langsamen First-Start (Realm-Import) |
| `interval` | `"15s"` | `"20s"` | Weniger Stress während Startup-Phase |
| `timeout` | `"5s"` | `"10s"` | Mehr Zeit für Endpoint-Antwort |
| `retries` | `"10"` (String) | `10` (Integer) | Korrekter YAML-Typ |
| `KC_HOSTNAME_STRICT_HTTPS` | gesetzt | **entfernt** | Deprecated v1-Option, erzeugt Warning |
### Gelerntes
- **`/health/live` ist für Single-Node-Keycloak die richtige Wahl** — `ready` ist für Cluster-Szenarien
konzipiert wo mehrere Nodes koordiniert hochfahren müssen.
- `retries` in Docker Compose Healthcheck sollte als Integer, nicht als String angegeben werden.
## ✅ Ping Service — Tracer Bullet Analyse & Fix (2026-03-09, gleiche Session)
Vollständige Analyse des Ping Service Stacks (Backend → Gateway → Frontend). Ergebnis: Die gesamte
fachliche Implementierung war bereits vorhanden. Ein einziger kritischer Bug gefunden und behoben.
### Befund: Stack vollständig implementiert
- **Backend** (`backend/services/ping/ping-service`): Domain, Application, Persistence, Controller,
Security (`at.mocode.infrastructure.security` via `@ComponentScan`), DB-Migrations V1+V2 — vollständig.
- **Contracts** (`contracts/ping-api`): `PingResponse`, `EnhancedPingResponse`, `HealthResponse`,
`PingEvent`, `PingApi` — vollständig.
- **Gateway** (`backend/infrastructure/gateway`): Routing `/api/ping/**` → `stripPrefix(1)` →
Ping Service mit CircuitBreaker Fallback — korrekt.
- **Frontend** (`frontend/features/ping-feature`): `PingApiKoinClient`, `PingViewModel`, `PingScreen`,
`PingSyncService`, Koin DI — vollständig.
- **Shell-Integration**: `MainApp.kt` — `AppScreen.Ping` eingebunden, „Ping-Service"-Button auf Home-Screen,
Navigation korrekt.
### Fix: `PingApiKoinClient.kt` — Query-Parameter-Mismatch 🔴
- **Problem:** `syncPings()` sendete `?lastSyncTimestamp=...` als Query-Parameter.
Backend `@RequestParam` erwartet `?since=...` — Delta-Sync lieferte immer alle Daten.
- **Fix:** `url.parameters.append("lastSyncTimestamp", ...)` → `url.parameters.append("since", ...)`
## ✅ Gitea-Pipeline & Runner Analyse (2026-03-09, gleiche Session)
### Befund: Aktiver CI/CD-Kern
- `.gitea/workflows/docker-publish.yaml` ist der einzige aktiv ausgeführte Workflow — grün seit 06.03.2026.
- Matrix: 4 Services (`keycloak`, `api-gateway`, `ping-service`, `web-app`), `max-parallel: 1` (RAM-Schutz).
- Native `linux/arm64`-Builds auf VM 102 (`10.0.0.23`), Push in interne Registry `10.0.0.22:3000`.
### Verifiziert (Screenshot 2026-03-09_12-47)
- `insecure-registries: ["10.0.0.22:3000"]` permanent in `/etc/docker/daemon.json` gesetzt ✅
- `act_runner`: `active (running)` seit 06.03.2026, `enabled; preset: enabled` ✅
- `systemctl is-enabled act_runner` → `enabled` ✅
### Bereinigung `.github/`-Ordner
- **Problem:** 6 GitHub Actions Workflows in `.github/workflows/` — auf Gitea nie ausgeführt (toter Code).
- **Zusätzlich:** `ci-main.yml`, `deploy-proxmox.yml`, `ssot-guard.yml` referenzierten falschen Pfad
`docker/docker-compose.yaml`.
- **Fix:** `pr-guard.yml` (prüft hartcodierte Versionen in `build.gradle.kts`) nach `.gitea/workflows/pr-guard.yaml`
migriert.
- **Fix:** Gesamten `.github/`-Ordner gelöscht.
- `youtrack-sync.yml` war nicht aktiv und wurde mitgelöscht — kein Handlungsbedarf.
### Aktive Workflows nach Bereinigung
| Datei | Trigger | Zweck |
|----------------------------------------|--------------|------------------------------------------------|
| `.gitea/workflows/docker-publish.yaml` | Push `main` | Build & Push aller Docker-Images |
| `.gitea/workflows/pr-guard.yaml` | Pull Request | Prüft hartcodierte Versionen in Gradle-Dateien |
## Bugfix: Keycloak Healthcheck — Finale Korrektur (Port 8080 → 9000)
**Problem:** Keycloak 26.5.5 startet sauber (~15s), wird aber dauerhaft nicht `healthy`.
**Root Cause (final):** Der vorherige Fix hatte Port 9000 → 8080 geändert — das war **falsch**.
| Port | Zweck | Health-Endpoint |
|----------|-----------------------------------------|-------------------------------------|
| **8080** | Haupt-HTTP (Login, Admin-Console, APIs) | ❌ kennt `/health/*` **nicht** → 404 |
| **9000** | Management (Actuator, Health, Metrics) | ✅ `/health/live`, `/health/ready` |
`curl http://localhost:8080/health/live` → **404** → `curl -f` schlägt fehl → `unhealthy`.
**Fix `dc-infra.yaml`:**
```yaml
test: ["CMD-SHELL", "curl -sf --max-time 5 http://localhost:9000/health/live || exit 1"]
interval: "15s"
timeout: "10s"
retries: 5
start_period: "90s"
```
**Warum `/health/live` statt `/health/ready`?**
`/health/ready` wartet auf JGroups-Cluster-Formation (Single-Node: 10×2s JOIN-Timeout = 20s Verzögerung). `/health/live`
prüft nur Prozess-Liveness — sofort `UP` sobald Quarkus läuft.
**`start_period: 90s`** — Puffer für First-Run mit DB-Schema-Init (Liquibase-Migrations ~1520s).
## 🔜 Nächste Schritte
- **TLS/HTTPS** — Langfristig: `KC_HOSTNAME_STRICT_HTTPS=true` setzen, sobald TLS eingerichtet ist.
- **Entries Service** — Beginn der Implementierung des ersten echten Fach-Services ("Nennungen").
---
## Bugfix: Keycloak Healthcheck — Echter Root Cause (curl nicht vorhanden)
**Zeitpunkt:** 2026-03-09 ~15:15
### Root Cause
Das Keycloak-Image `quay.io/keycloak/keycloak:26.5.5` basiert auf **`ubi9-micro`** — einem minimalen Red Hat Image *
*ohne `curl` / `wget` / Package Manager**.
Alle bisherigen Port-Fixes (8080 → 9000) waren korrekt, aber der `curl`-Befehl scheiterte im Container mit
`command not found`.
Keycloak selbst lief die ganze Zeit einwandfrei — nur der Healthcheck-Befehl fehlte das nötige Tool.
### Fix
| Datei | Änderung |
|-----------------|---------------------------------------------|
| `dc-infra.yaml` | Healthcheck: `curl` → Bash `/dev/tcp`-Trick |
**Neuer Healthcheck (kein externes Tool nötig):**
```yaml
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && printf 'GET /health/live HTTP/1.0\r\nHost: localhost\r\n\r\n' >&3 && cat <&3 | grep -q '"status":"UP"'"]
```
### Warum `/dev/tcp` funktioniert
- Bash hat `/dev/tcp` eingebaut — verfügbar ohne Installation
- `exec 3<>/dev/tcp/localhost/9000` öffnet TCP-Verbindung auf Port 9000
- `printf ... >&3` sendet einen minimalen HTTP/1.0 GET-Request
- `cat <&3 | grep -q '"status":"UP"'` liest Antwort und prüft Health-Status
### Gelernt
> Vor jedem `curl`-basierten Healthcheck prüfen: Ist `curl` im Container-Image vorhanden?
> Minimale Images (`ubi9-micro`, `distroless`, `alpine` ohne curl-Paket) haben es **nicht**.
> Sicherer Standard: `/dev/tcp` (bash built-in) statt `curl` — funktioniert immer wenn bash vorhanden ist.
---
## Bugfix: Keycloak Healthcheck — grep-Pattern Leerzeichen
**Zeitpunkt:** 2026-03-09 ~15:27
### Root Cause
Nach dem `/dev/tcp`-Fix war der Healthcheck immer noch `unhealthy` (ExitCode=1).
Der grep-Pattern lautete `'"status":"UP"'` (kein Leerzeichen nach `:`), die tatsächliche
JSON-Antwort von Keycloak enthält jedoch `"status": "UP"` (mit Leerzeichen nach dem Doppelpunkt).
**Beweis via `docker exec`:**
```
HTTP/1.0 200 OK
{
"status": "UP",
"checks": []
}
```
grep nach `"status":"UP"` → kein Match → ExitCode 1 → unhealthy.
### Fix
| Datei | Änderung |
|-----------------|--------------------------------------------------|
| `dc-infra.yaml` | grep-Pattern: `"status":"UP"` → `"status": "UP"` |
**Vorher:**
```yaml
test: ["CMD-SHELL", "... | grep -q '\"status\":\"UP\"'"]
```
**Nachher:**
```yaml
test: ["CMD-SHELL", "... | grep -q '\"status\": \"UP\"'"]
```
### Ergebnis
Nach `docker compose up -d keycloak`: Status **healthy**, 2x ExitCode=0 bestätigt.
### Gelernt
> Den Healthcheck-Befehl immer manuell via `docker exec` testen und die **exakte** API-Antwort
> prüfen — JSON-Formatierung (Leerzeichen, Einrückung) kann je nach Keycloak-Version variieren.
> Sicherer wäre `grep -q '"UP"'` ohne den Key, um Formatierungsunterschiede zu vermeiden.
---
## Optimierung: Healthcheck grep-Pattern vereinfacht
**Zeitpunkt:** 2026-03-09 ~15:30
### Maßnahme
Das grep-Pattern wurde weiter vereinfacht auf `grep -q '"UP"'`, um robust gegen
JSON-Formatierungsänderungen (Leerzeichen, Einrückung) in zukünftigen Keycloak-Versionen zu sein.
| Datei | Vorher | Nachher |
|-----------------|----------------------------|------------------|
| `dc-infra.yaml` | `grep -q '"status": "UP"'` | `grep -q '"UP"'` |
### Ergebnis
Status **healthy**, ExitCode=0 bestätigt. Pattern ist nun versionsunabhängig.
---
## Bugfix: Login fehlgeschlagen — `directAccessGrantsEnabled` für `frontend-client`
**Zeitpunkt:** 2026-03-09 ~15:41
### Symptom
Web-App (`localhost:4000`) zeigte beim direkten Username/Passwort-Login:
```
Login fehlgeschlagen: HTTP 400 - {"error":"unauthorized_client","error_description":"Client not allowed for direct access grants"}
```
### Root Cause
`AuthApiClient.kt` verwendet `AppConstants.KEYCLOAK_CLIENT_ID = "frontend-client"` mit
`grant_type=password` (Resource Owner Password Credentials / ROPC-Flow).
Der `frontend-client` hatte in `meldestelle-realm.json` jedoch `directAccessGrantsEnabled: false` —
bewusst deaktiviert als reiner PKCE-Client, dabei aber vergessen, dass die Web-App ROPC nutzt.
### Fix
| Datei | Änderung |
|--------------------------|----------------------------------------------------------------|
| `meldestelle-realm.json` | `frontend-client`: `directAccessGrantsEnabled: false` → `true` |
Live-Update via Admin REST API (kein Neustart nötig):
```bash
# Token holen
TOKEN=$(curl -s -X POST "http://localhost:8180/realms/master/protocol/openid-connect/token" \
-d "username=kc-admin&password=kc-password&grant_type=password&client_id=admin-cli" ...)
# Client-UUID ermitteln & PUT mit directAccessGrantsEnabled:true
curl -X PUT "http://localhost:8180/admin/realms/meldestelle/clients/$UUID" \
-H "Authorization: Bearer $TOKEN" -d "$UPDATED_CLIENT_JSON"
# → HTTP 204
```
### Verifikation
```bash
curl -X POST ".../realms/meldestelle/protocol/openid-connect/token" \
-d "username=admin&password=Admin%231234&grant_type=password&client_id=frontend-client"
# → "token_type":"Bearer" ✅
```
### Gelernt
> `--import-realm` in Keycloak importiert Realms **nur beim ersten Start** (wenn Realm noch nicht existiert).
> Änderungen an der realm.json nach dem ersten Import müssen entweder via Admin REST API oder
> durch Löschen des Volumes (Datenverlust!) neu eingespielt werden.
> Für Dev-Umgebungen: `KC_COMMAND=start --optimized --import-realm` mit separatem Reset-Script
> oder Admin-API-Skript für Konfigurationsänderungen vorbereiten.
@@ -0,0 +1,227 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-10
---
# Session Log — 2026-03-10: Keycloak Hostname Fix, Git Push Analyse & DOCKER_REGISTRY Fix
**Datum:** Di. 10. März 2026
**Agent:** 🧹 Curator / 👷 Backend Developer
**Kontext:** Folge-Session zu Keycloak-Härtung vom 09.03.2026
---
## Übersicht
| # | Problem | Status |
|---|------------------------------------------------------------------|---------------------------------|
| 1 | Git Push fehlgeschlagen | ✅ Analysiert (Netzwerkfehler) |
| 2 | Keycloak Admin-Dashboard auf `meldestelle-host` nicht erreichbar | ✅ Root Cause + Fix dokumentiert |
| 3 | Alertmanager Permission-Fehler | ✅ Identifiziert |
| 4 | `DOCKER_REGISTRY` falsch — Images nicht gefunden | ✅ Behoben |
---
## Problem 1: Git Push fehlgeschlagen
**Zeitpunkt:** 2026-03-09 ~15:50 (aus Vortagslogs)
### Symptom
```
fatal: unable to access 'https://git.mo-code.at/mocode-software/meldestelle/'
Failed to connect to git.mo-code.at port 443 after 133648 ms: Could not connect to server
```
### Analyse
Zwei separate Ereignisse wurden fälschlicherweise als ein Problem wahrgenommen:
1. **15:50 — Push rejected** (`fetch first`): Normaler Git-Fehler, Remote hatte neue Commits.
- Korrekt gelöst durch: `fetch` + `rebase``Successfully rebased and updated refs/heads/main`
2. **15:51 — Push nach Rebase fehlgeschlagen**: Netzwerkfehler — `git.mo-code.at:443` war nicht erreichbar (
Pangolin-Tunnel kurzzeitig down).
### Lösung
Kein Code-Fix nötig. Sobald der Server wieder erreichbar ist:
```bash
curl -I https://git.mo-code.at # Erreichbarkeit prüfen
git push origin main # Einfach erneut pushen
```
### Gelernt
> Der Rebase war korrekt und vollständig. Kein `--force`, kein `git reset` nötig.
> Pangolin-Tunnel-Ausfälle sind transient — immer zuerst Netzwerk prüfen, bevor Git-Befehle wiederholt werden.
---
## Problem 2: Keycloak Admin-Dashboard auf `meldestelle-host` nicht erreichbar
**Zeitpunkt:** 2026-03-10 ~10:17
### Symptom
- Lokal (`localhost:8180/admin`): ✅ funktioniert
- Auf `meldestelle-host` (`10.0.0.50:8180/admin`): ❌ nicht erreichbar
- Management-Port (`10.0.0.50:9000`): ✅ erreichbar
### Root Cause: `KC_HOSTNAME` ohne Port
In der `.env` auf `meldestelle-host`:
```env
KC_HOSTNAME=10.0.0.50 # ← Port fehlt!
```
Keycloak 26.x (hostname v2) interpretiert `KC_HOSTNAME` als kanonische Basis-URL.
Ohne Port-Angabe erwartet Keycloak Requests auf Port **80** (HTTP-Standard).
Der tatsächliche Host-Port ist aber **8180** → Mismatch → Admin-Interface antwortet nicht.
**Warum Port 9000 funktioniert:**
Der Management-Port (`KC_HTTP_MANAGEMENT_PORT=9000`) ist **nicht** an `KC_HOSTNAME` gebunden
und antwortet unabhängig vom Hostname-Mapping immer.
**Warum lokal alles funktioniert:**
```env
KC_HOSTNAME=localhost # Port 8180 → Container-intern 8080 → passt
```
`localhost` ohne Port funktioniert, weil der Browser/curl den Port aus der URL übernimmt
und Keycloak bei `KC_HOSTNAME_STRICT=false` toleranter ist.
### Zusätzliches Problem: Deprecated Variable
```env
KC_HOSTNAME_STRICT_HTTPS=false # deprecated seit Keycloak 26.x (hostname v2)
```
Diese Variable wird in Keycloak 26.x ignoriert — kann zu unerwartetem Verhalten führen.
### Fix für `.env` auf `meldestelle-host`
```env
# VORHER:
KC_HOSTNAME=10.0.0.50
KC_HOSTNAME_STRICT=false
KC_HOSTNAME_STRICT_HTTPS=false # deprecated
# NACHHER:
KC_HOSTNAME=10.0.0.50:8180
KC_HOSTNAME_STRICT=false
# KC_HOSTNAME_STRICT_HTTPS entfernt (deprecated in Keycloak 26.x)
```
### Anwendung des Fixes
```bash
# Auf meldestelle-host:
nano .env
# KC_HOSTNAME=10.0.0.50 → KC_HOSTNAME=10.0.0.50:8180
# KC_HOSTNAME_STRICT_HTTPS=false → Zeile entfernen
docker compose -f dc-infra.yaml up -d keycloak
# Test nach ~30s:
curl -s http://10.0.0.50:8180/admin/
```
### Gelernt
> `KC_HOSTNAME` in Keycloak 26.x (hostname v2) muss den **vollständigen** Hostnamen inkl. Port
> enthalten, wenn kein Standard-Port (80/443) verwendet wird.
> `KC_HOSTNAME_STRICT_HTTPS` ist seit Keycloak 26.x deprecated und sollte aus allen `.env`-Dateien
> entfernt werden — es wird stillschweigend ignoriert.
---
## Problem 3: Alertmanager Permission-Fehler (Nebenbefund)
### Symptom (aus Docker-Logs)
```
err="open /etc/alertmanager/alertmanager.yaml: permission denied"
```
### Root Cause
Die `alertmanager.yaml` auf dem Host hat falsche Dateiberechtigungen.
### Fix
```bash
chmod 644 config/docker/alertmanager/alertmanager.yaml
docker compose -f dc-ops.yaml restart alertmanager
```
---
## Problem 4: `DOCKER_REGISTRY` falsch — Images nicht gefunden
**Zeitpunkt:** 2026-03-10 ~13:20
### Symptom
```
! Image git.mo-code.at/mocode-software/keycloak:latest manifest unknown
! Image git.mo-code.at/mocode-software/api-gateway:latest manifest unknown
Error response from daemon: No such image: git.mo-code.at/mocode-software/keycloak:latest
```
`docker compose --profile all up -d --no-build` schlug fehl — alle custom Images nicht gefunden.
### Root Cause: Falscher Registry-Pfad in `.env`
Die Pipeline (`.gitea/workflows/docker-publish.yaml`) pusht Images nach:
```
10.0.0.22:3000/mocode-software/meldestelle/keycloak:latest
^^^^^^^^^^^^
```
Die `.env` hatte jedoch:
```env
DOCKER_REGISTRY=git.mo-code.at/mocode-software # ← /meldestelle fehlt!
```
Docker suchte also unter `git.mo-code.at/mocode-software/keycloak:latest` — das `/meldestelle/`-Segment fehlte.
### Fix
| Datei | Vorher | Nachher |
|-------|--------|---------|
| `.env` (lokal) | `git.mo-code.at/mocode-software` | `git.mo-code.at/mocode-software/meldestelle` |
### Anwendung auf `meldestelle-host`
```bash
nano .env
# DOCKER_REGISTRY=git.mo-code.at/mocode-software
# ↓
# DOCKER_REGISTRY=git.mo-code.at/mocode-software/meldestelle
docker compose --profile all up -d --no-build
```
### Gelernt
> Der Image-Pfad in `DOCKER_REGISTRY` muss exakt dem Pfad entsprechen, unter dem die Pipeline
> die Images in die Registry pusht — inklusive aller Namespace-Segmente (`/meldestelle/`).
> Beim Einrichten einer neuen Registry immer `docker pull <full-image-path>` manuell testen,
> bevor `docker compose up --no-build` verwendet wird.
---
## Offene Punkte
| Punkt | Priorität | Beschreibung |
|---------------------------------------|------------|-----------------------------------------------------------------|
| Keycloak Hostname Fix anwenden | 🔴 Hoch | `.env` auf `meldestelle-host`: `KC_HOSTNAME=10.0.0.50:8180` |
| DOCKER_REGISTRY Fix anwenden | 🔴 Hoch | `.env` auf `meldestelle-host`: `DOCKER_REGISTRY=...meldestelle` |
| Alertmanager Permission Fix | 🟡 Mittel | `chmod 644` auf alertmanager.yaml |
| `KC_HOSTNAME_STRICT_HTTPS` bereinigen | 🟢 Niedrig | Deprecated Variable aus allen `.env`-Dateien entfernen |
@@ -0,0 +1,51 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-11
---
# Session Log: Pangolin Update & Meldestelle Configuration
**Datum:** 11. März 2026
**Teilnehmer:** User (Owner), AI Agent (Lead Architect/DevOps)
**Status:** In Progress
## 1. Pangolin Update (Abgeschlossen)
### Kontext
Das Update von Pangolin auf dem VPS `vzora` stand an, um die neueste Version (1.16.2) zu nutzen. Dies war notwendig, um
von den neuesten Features und Sicherheitsupdates zu profitieren.
### Durchgeführte Maßnahmen
1. **Dokumentation aktualisiert:**
- Die Datei `docs/01_Architecture/Pangolin/Documentation Index Fetch.md` wurde angepasst.
- Die Version im Update-Guide wurde exemplarisch auf `1.16.2` gesetzt.
2. **SSH-Intervention auf `vzora`:**
- Stop des Stacks: `sudo docker compose down`
- Bearbeitung der `docker-compose.yml`:
- Update `pangolin` Image auf `fosrl/pangolin:1.16.2`.
- (Gerbil war bereits auf 1.3.0, Traefik auf v3.6 laut Logs).
- Pull & Neustart: `sudo docker compose pull && sudo docker compose up -d`
- Verifikation via Logs: `sudo docker compose logs -f`
### Ergebnisse
* **Erfolgreiche Migration:** Pangolin Datenbank-Migrationen (1.15.4 -> 1.16.0) wurden erfolgreich durchgeführt.
* **System Health:** Alle Dienste (Pangolin, Gerbil, Traefik) starteten fehlerfrei und sind "Healthy".
* **Warnung:** SMTP ist nicht konfiguriert (erwartetes Verhalten, da nicht genutzt).
## 2. Meldestelle Endpoint Analyse (In Vorbereitung)
### Ziel
Vorbereitung der Konfiguration von Pangolin (Reverse Proxy/Gateway) für das Projekt "Meldestelle". Dazu müssen alle
relevanten internen und externen Endpunkte identifiziert werden.
### Nächste Schritte
* Analyse der `docker-compose` Dateien der Meldestelle.
* Identifikation der Ports und Services (Backend, Frontend, Keycloak, etc.).
* Erstellung eines Plans für die Pangolin-Konfiguration (Routing, Domains).
@@ -0,0 +1,102 @@
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-03-15
---
# 🧹 Session Log: Dokumentation Cleanup & Normalisierung
**Datum:** 15. März 2026
**Agent:** 🧹 Curator
**Kontext:** Vollständige Bereinigung, Korrektur und Optimierung der `docs/`-Struktur.
---
## 📝 Zusammenfassung
Umfassende Aufräum-Session der gesamten Dokumentation. Veraltete Dokumente wurden archiviert, fehlende Standard-Header ergänzt, inkonsistente Frontmatter-Werte normalisiert und temporäre Dateien entfernt.
---
## 🗂️ Archivierungen
| Originaldatei | Archivpfad | Grund |
|---|---|---|
| `docs/01_Architecture/ARCHITECTURE.md` | `docs/01_Architecture/_archive/2026-03-15_ARCHITECTURE.md` | Selbst als veraltet markiert (Jan 2026), kein aktiver Inhalt mehr |
| `docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md` | `docs/01_Architecture/_archive/2026-03-15_MASTER_ROADMAP_2026_Q1.md` | Alle Phasen der "Operation Tracer Bullet" abgeschlossen |
| `docs/05_Backend/TASK_2026_Q1_Infrastructure_Hardening.md` | `docs/05_Backend/_archive/2026-03-15_TASK_2026_Q1_Infrastructure_Hardening.md` | Status war DONE, erledigte Task-Dokumente gehören ins Archiv |
---
## 🛠️ Korrekturen
### `last_update`-Feld ergänzt (19 Dokumente)
Folgende aktive Dokumente hatten kein `last_update`-Feld im Frontmatter:
- `docs/05_Backend/Services/PingService_Reference.md`
- `docs/05_Backend/README.md`
- `docs/05_Backend/Guides/Database_Best_Practices.md`
- `docs/05_Backend/Guides/Testing_with_Postman.md`
- `docs/06_Frontend/offline-first-architecture.md`
- `docs/06_Frontend/web-setup.md`
- `docs/07_Infrastructure/Heim-Netzwerk-Plan_02-2026.md`
- `docs/07_Infrastructure/Konfig-Matrix_Dev-ProZora.md`
- `docs/07_Infrastructure/Pangolin-vs-Cloudflare-Tunnel.md`
- `docs/07_Infrastructure/Reference/ports-and-urls.md`
- `docs/07_Infrastructure/Reference/zipkin.md`
- `docs/07_Infrastructure/Zora_Infrastructure_Deployment_02-2026.md`
- `docs/07_Infrastructure/Zora_System_Architektur.md`
- `docs/07_Infrastructure/guides/jwt-in-docker.md`
- `docs/07_Infrastructure/runbooks/local-development.md`
- `docs/03_Domain/00_Glossary.md`
- `docs/02_Guides/SQLDelight_Integration_Compose_Multiplatform.md`
- `docs/02_Guides/SQLDelight_Web_Asynchron.md`
- `docs/02_Guides/CodingGuidelines/kdoc-style.md`
### Journal-Header normalisiert (25 Einträge)
- **Header hinzugefügt** (fehlten komplett): 11 Einträge (u.a. `2026-02-03_*`, `2026-02-04_*`, `2026-03-09_*`, `2026-03-10_*`, `2026-03-11_*`)
- **Inkonsistente Werte korrigiert** (14 Einträge):
- `type`: `journal``Journal`, `JOURNAL``Journal`, `Session Log``Journal`
- `status`: `COMPLETED``ACTIVE`, `DONE``ACTIVE`, `FINAL``ACTIVE`, `In Progress``ACTIVE`
- `last_update` aus Dateiname ergänzt wo fehlend
### Temporäre Dateien gelöscht
- `docs/Bin/Temp.md` — leere Temp-Datei ohne Inhalt
---
## ✅ Quality Gate Status
| Prüfpunkt | Status |
|---|---|
| Alle aktiven Docs haben Standard-Header | ✅ |
| `last_update` in allen aktiven Docs | ✅ |
| `type`-Werte konsistent (Journal/Reference/Guide/ADR/Report/Roadmap) | ✅ |
| `status`-Werte konsistent (DRAFT/ACTIVE/DEPRECATED/ARCHIVED) | ✅ |
| Veraltete Dokumente archiviert | ✅ |
| Temporäre Dateien entfernt | ✅ |
---
## 🛠️ Nachbesserungen (Session 2, 20:02 Uhr)
Auf Basis von IDE-Warnings/Errors wurden folgende Korrekturen durchgeführt:
| Datei | Problem | Fix |
|---|---|---|
| `05_Backend/_archive/2026-03-15_TASK_...Hardening.md` | Broken Links (falsche relative Pfade nach Archivierung) | Pfade auf `../../01_Architecture/...` korrigiert; Roadmap-Link auf archivierte Version |
| `05_Backend/README.md` | `ping-service.md` existiert nicht | Link auf `PingService_Reference.md` korrigiert |
| `05_Backend/Guides/Database_Best_Practices.md` | `...` in Kotlin-Code-Blöcken → "Expecting an element" | Durch Kommentare ersetzt |
| `02_Guides/SQLDelight_Integration_Compose_Multiplatform.md` | `package`/`import`-Direktiven in Code-Fragmenten → IDE-Fehler | Alle `package`- und `import`-Zeilen aus Kotlin-Blöcken entfernt |
| `02_Guides/SQLDelight_Web_Asynchron.md` | `package`/`import`-Direktiven in Code-Fragmenten → IDE-Fehler | Alle `package`- und `import`-Zeilen aus Kotlin-Blöcken entfernt |
| `02_Guides/SQLDelight_Integration_Compose_Multiplatform.md` | `private val database` → Warning "Constructor parameter never used as property" | `val` entfernt: `UserRepository(database: AppDatabase)` |
| `02_Guides/SQLDelight_Integration_Compose_Multiplatform.md` | Swift-Code als ` ```kotlin ` markiert → "Expecting an element" / "Unexpected tokens" | Code-Fence auf ` ```swift ` korrigiert |
---
## 🔗 Offene Punkte / Empfehlungen
- **Domain-Analyse-Docs** (`docs/03_Domain/03_Analysis/`) haben noch kein `last_update` — diese sind DRAFT und sollten beim nächsten Domain-Workshop aktualisiert werden.
- **`docs/06_Frontend/Logs/`** — zwei Docker-Build-Troubleshooting-Logs ohne `last_update`; da reine Logs, niedrige Priorität.
- **ADR-Pflicht prüfen:** Die Entscheidung für den AI-Stack (Ollama + Open WebUI, Session 2026-03-06) ist bisher nur im Journal dokumentiert — ein ADR in `docs/01_Architecture/adr/` wäre angebracht.
@@ -0,0 +1,57 @@
# Session Log: Architektonische Gesamtbewertung & Freigabe Phase 3
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🏗️ [Lead Architect] in Zusammenarbeit mit 🧹 [Curator]
**Typ:** Architektur-Entscheidung & Meilenstein-Review
## 1. Executive Summary
Als Lead Architect habe ich die tiefgehenden Analysen aller Fachbereiche (DevOps, Backend, Frontend, UI/UX, QA, Curator)
evaluiert, um die Bereitschaft für die "Phase 3: Feature Development" der Master Roadmap zu bewerten.
**Das Ergebnis ist eindeutig:**
* 🟢 **Technologie & Infrastruktur:** 100% Ready. Das Fundament ist robust, modern und produktionsnah.
* 🔴 **Fachlichkeit & Domäne:** 0% Ready. Es existieren keine verabschiedeten Spezifikationen, Use-Cases oder UI-Flows.
## 2. Zusammenfassung der Fachberichte
1. **🐧 DevOps:** Infrastruktur, CI/CD und lokale Entwicklungsumgebung stehen stabil bereit. Die Dev/Prod-Parität (
Keycloak) ist gesichert.
2. **👷 Backend:** DDD-Core und Spring Boot Blueprints (KMP-kompatibel) sind lauffähig, aber fachliche Implementierung
würde ohne Domänenmodelle zu massiven Refactorings führen.
3. **🎨 Frontend:** KMP, Compose und Offline-First-Sync-Mechanismen sind exzellent aufgesetzt. Es fehlen jedoch
Datenmodelle und Wireframes.
4. **🖌️ UI/UX:** Das Basis-Design-System steht. Es fehlen jedoch zwingend Wireframes, Benutzer-Flows und Offline-First
UX-Konzepte, um das alte "SuDo"-System sinnvoll abzulösen.
5. **🧐 QA:** Test-Infrastruktur (Testcontainers, BDD-Bereitschaft) ist hervorragend. Es fehlen Akzeptanzkriterien,
Testdaten und "Given-When-Then"-Szenarien für TDD.
6. **🧹 Curator:** Docs-as-Code Struktur ist sauber. Jedoch sind alle Domänen-Dokumente im `docs/03_Domain/` als "Draft"
markiert, was die "Single Source of Truth"-Regel verletzt.
## 3. Architektonische Entscheidung (ADR)
Ich bestätige das einstimmige Veto des Teams gegen einen sofortigen Start der Programmierung. Das blinde Schreiben von
Feature-Code wird hiermit untersagt.
**Wir wenden strikt das "Shift-Left" Prinzip an.** Bevor Code geschrieben wird, muss die fachliche Architektur (Domäne)
geklärt sein.
## 4. Konkreter Fahrplan (Nächste Schritte)
Um die Blockade aufzulösen und Phase 3 aktiv zu schalten, ordne ich folgende Schritte an:
1. **Initiierung des Domain Workshops (Lead Architect & Fachexperte):**
* Fokus auf Kernprozesse (z.B. Nennung, Startliste, Ergebnisse).
* Überführung der Drafts (`Legacy_Spec_Analysis`, `Use_Cases_Draft.md`) in finale Spezifikationen.
2. **Parallele Ausarbeitung (QA & UI/UX):**
* **QA:** Definition der Akzeptanzkriterien und Gherkin-Szenarien aus den Workshop-Ergebnissen.
* **UI/UX:** Erstellung der Wireframes für die Kern-Flows (inkl. Offline-States) basierend auf den neuen
Domänenmodellen.
3. **Dokumenten-Freigabe (Curator):**
* Überführung der `docs/03_Domain/` Dokumente vom Status "DRAFT" auf "ACTIVE".
4. **Roadmap Update:**
* Sobald Schritte 1-3 abgeschlossen sind, wird Phase 3 in der `MASTER_ROADMAP.md` freigegeben und das
Entwicklungs-Team darf mit der Implementierung beginnen (Aktivierung des `entries-service`).
**Fazit:** Der technische Proof of Concept ist abgeschlossen. Wir wechseln nun in den Domänen- und Spezifikations-Modus.
@@ -0,0 +1,48 @@
# Session Log: Analyse der Backend-Bereitschaft für die Feature-Entwicklung
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator] in Zusammenarbeit mit 👷 [Backend Developer]
**Typ:** Code- & Projekt-Review
## 1. Ausgangslage
Nachdem die Infrastruktur freigegeben wurde, hat der 👷 **[Backend Developer]** die aktuelle Code-Basis (`:backend`,
`:core:core-domain`, `settings.gradle.kts`) auf ihre Bereitschaft für den Start der fachlichen Feature-Entwicklung
geprüft.
## 2. Analyse-Ergebnisse (Backend Developer)
Die Analyse gliedert sich in zwei Kernbereiche: die technische Basis und die fachliche Ausrichtung.
### 2.1 Technische Bereitschaft: 🟢 Exzellent
Das technische Fundament ist hervorragend aufgestellt und bereit für die Produktiventwicklung:
* **Domain-Driven Design (DDD) Core:** Das `:core:core-domain` Modul ist sehr sauber strukturiert. Die konsequente
Nutzung von Kotlin 2.3.0 `Value-Classes` (z.B. für `EntityId`, `ErrorCode` inkl. Regex-Validierung) garantiert
maximale Typsicherheit ohne Performance-Verlust zur Laufzeit.
* **KMP-Kompatibilität:** Die Basis-DTOs und Serializer (wie `KotlinxInstantSerializer`) sind im `commonMain` des
Core-Moduls platziert. Dies ermöglicht eine reibungslose Code-Wiederverwendung für das Kotlin/JS Frontend (KMP-Ready).
* **Service-Blaupause:** Der `ping-service` beweist, dass der aktuelle Technologie-Stack (Spring Boot 3.5.x, Security,
Resilience4j, Persistence, Monitoring via Zipkin/Micrometer) lauffähig verdrahtet ist. Auch die Testumgebung inkl.
`Testcontainers` steht bereit.
### 2.2 Fachliche Bereitschaft: 🔴 Blockiert (Warten auf Architect)
Trotz der technischen Einsatzbereitschaft darf die fachliche Implementierung noch nicht starten.
* **Roadmap-Status:** Die `MASTER_ROADMAP.md` definiert Phase 3 (Feature Development) aktuell ganz klar als **ON HOLD**.
* **Fehlende Domänen-Klarheit:** Es steht noch ein fundamentaler "Domain Analysis Workshop" mit dem Fachexperten aus, um
die Anforderungen, Aggregate und Bounded Contexts neu zu definieren.
* **Pausierte Services:** Der für die Fachlichkeit zentrale `:backend:services:entries:entries-service` ist in der
`settings.gradle.kts` bewusst auskommentiert und deaktiviert.
## 3. Fazit & Empfehlung
Ein unüberlegter Start der Programmierung würde unweigerlich zu Code führen, der nicht der finalen Domänen-Logik
entspricht und später aufwendig refaktorisiert werden müsste.
**Nächster logischer Schritt:**
Bevor Code geschrieben oder der `entries-service` reaktiviert wird, muss der **🏗️ [Lead Architect]** den Domain-Workshop
leiten. Erst wenn die fachliche "Feature Roadmap" und die Kern-Domänenmodelle spezifiziert sind, erfolgt die Freigabe
für das Backend-Team.
@@ -0,0 +1,52 @@
# Session Log: Analyse der Dokumentations-Bereitschaft für die Feature-Entwicklung
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator]
**Typ:** Projektdokumentations-Review
## 1. Ausgangslage
Als finaler Check vor dem möglichen Start der Phase 3 ("Feature Development") habe ich, der 🧹 **[Curator]**, das Projekt
aus Sicht der Dokumentation, Wissensverwaltung ("Docs-as-Code") und Nachvollziehbarkeit analysiert.
## 2. Analyse-Ergebnisse (Curator)
### 2.1 Technische Dokumentations-Infrastruktur: 🟢 Hervorragend
Die Basis für die Wissensverwaltung ist in einem exzellenten Zustand:
* **Docs-as-Code:** Die Verzeichnisstruktur unter `/docs` ist aufgeräumt (Phase 1 der Roadmap ist abgeschlossen). Alte
Dokumente sind ordnungsgemäß im `_archive` abgelegt.
* **Projekt-Journal:** Die Nachvollziehbarkeit von Architekturentscheidungen und Readiness-Checks funktioniert
fehlerfrei. Alle Agenten dokumentieren ihre Ergebnisse diszipliniert in `docs/99_Journal/`.
* **Playbooks:** Die Rollen und Vorgaben der KI-Agenten unter `docs/04_Agents/Playbooks/` sind präzise und lenken das
Team erfolgreich.
### 2.2 Fachliche Dokumentation (Single Source of Truth): 🔴 Blockiert
Trotz der guten Struktur fehlt der eigentliche Inhalt für die Umsetzung:
* **Domänen-Wissen als Draft:** Der Ordner `docs/03_Domain/` enthält wertvolle Vorarbeiten (z.B.
`Legacy_Spec_Analysis_2026-01.md`, `Use_Cases_Draft.md`), aber diese sind explizit als **"Draft"** markiert. Es gibt
keine final freigegebenen Spezifikationen.
* **Keine verbindlichen Verträge:** Für die Entwickler und die QA gibt es in der Dokumentation keine freigegebenen
API-Contracts, Bounded Contexts oder Aggregat-Definitionen.
* **Verletzung der Projekt-Philosophie:** Unsere Guideline lautet: *"Die Dokumentation ist die Single Source of Truth"*.
Solange diese "Truth" nicht formuliert ist, darf nicht programmiert werden.
## 3. Fazit & Empfehlung
Ich schließe mich aus dokumentarischer Sicht nahtlos allen anderen Fachbereichen an. Ein Start der Implementierung ohne
vorherige Festschreibung der Domäne würde das "Docs-as-Code"-Prinzip untergraben.
**Nächste Schritte & Fahrplan (Empfehlung des Curators):**
1. **Einberufung des Lead Architects:** Der **🏗️ [Lead Architect]** muss nun aktiv werden, um den "Domain Workshop"
durchzuführen.
2. **Spezifikationen finalisieren:** Die Ergebnisse des Workshops müssen von den aktuellen "Drafts" in verbindliche,
aktive Spezifikationen unter `docs/03_Domain/` überführt werden.
3. **Roadmap-Update:** Sobald die fachliche Dokumentation steht, passe ich als Curator die `MASTER_ROADMAP.md` an und
schalte Phase 3 offiziell auf "ACTIVE".
Alle Disziplinen haben nun gesprochen. Das Veto gegen einen verfrühten Code-Start ist einstimmig. Wir warten auf die
Architektur.
@@ -0,0 +1,49 @@
# 👷 Session Log: Fix SQLite Worker 404
**Datum:** 2026-03-16
**Agent:** Backend Developer / DevOps Engineer
**Status:** ✅ Abgeschlossen
## Problem
Die Web-App schlug beim Start mit folgendem Fehler fehl:
```
sqlite.worker.js:1 Uncaught SyntaxError: Unexpected token '<'
Error initializing database schema: WebWorkerException
```
Der Browser erhielt beim Laden von `sqlite.worker.js` eine HTML-Fehlerseite (404) statt der JavaScript-Datei — daher der
`Unexpected token '<'`-Fehler.
## Root Cause
`sqlite.worker.js` lag in `frontend/core/local-db/src/jsMain/resources/` und wurde via `CopyWebpackPlugin` in
`sqlite-config.js` in den Build-Output kopiert. **Kotlin/JS kopiert Ressourcen aus Abhängigkeits-Modulen jedoch nicht
automatisch** in den Output des Shell-Moduls (`meldestelle-portal`). Die `CopyWebpackPlugin`-Konfiguration griff nicht
zuverlässig, sodass die Datei im finalen `productionExecutable`-Verzeichnis fehlte.
## Fix
`sqlite.worker.js` direkt in das Shell-Modul kopiert:
```
frontend/shells/meldestelle-portal/src/jsMain/resources/sqlite.worker.js
```
Kotlin/JS kopiert alle Ressourcen aus diesem Verzeichnis automatisch in den Build-Output — ohne Abhängigkeit von
`CopyWebpackPlugin`.
## Verifikation
- `./gradlew :frontend:shells:meldestelle-portal:jsBrowserDistribution` → BUILD SUCCESSFUL
- `sqlite.worker.js` im Output: `build/dist/js/productionExecutable/sqlite.worker.js`
- Docker Image neu gebaut und Container neu gestartet
- `curl http://localhost:4000/sqlite.worker.js``200 text/javascript`
## Geänderte Dateien
| Datei | Änderung |
|----------------------------------------------------------------------------|-------------------------------------------------------------------|
| `frontend/shells/meldestelle-portal/src/jsMain/resources/sqlite.worker.js` | Neu hinzugefügt (Kopie aus `local-db`) |
| `frontend/shells/meldestelle-portal/webpack.config.d/sqlite-config.js` | Strategy D (processedResources) als zusätzlicher Fallback ergänzt |
@@ -0,0 +1,49 @@
# Session Log: Analyse der Frontend-Bereitschaft für die Feature-Entwicklung
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator] in Zusammenarbeit mit 🎨 [Frontend Expert]
**Typ:** Code- & Projekt-Review
## 1. Ausgangslage
Nach dem Backend-Review hat nun auch der 🎨 **[Frontend Expert]** das Kotlin Multiplatform (KMP) Frontend (
`:frontend:core`, `:frontend:shells:meldestelle-portal`) auf seine Bereitschaft für die fachliche Implementierung hin
untersucht.
## 2. Analyse-Ergebnisse (Frontend Expert)
### 2.1 Technische Bereitschaft: 🟢 Sehr gut
Die Architektur ist exzellent auf die Anforderungen (insbesondere "Offline-First") vorbereitet:
* **Architektur:** Saubere Modul-Trennung (`:core:auth`, `:core:network`, `:core:local-db`, `:core:sync`) und
funktionierendes Dependency Injection Setup via Koin im Main-Entrypoint.
* **Offline-First Basis:** Die lokale Datenbank via SQLDelight (inkl. `WebWorkerDriver` für die Kotlin/JS Target) ist
voll funktionsfähig. Der abstrakte `SyncManager` im Modul `:core:sync` bietet genau die richtige Basis für den
Delta-Sync mit dem Backend.
* **UI Foundation:** Das `:core:design-system` etabliert eine professionelle und einheitliche Theming-Grundlage (Farben,
Typografie, Material 3), die sich nahtlos in Compose Multiplatform integriert. Ein funktionierendes Basis-Routing (
`StateNavigationPort`) und Auth-Flows existieren bereits.
### 2.2 Fachliche Bereitschaft: 🔴 Blockiert (Warten auf Architect & UX)
Trotz der technischen Startklarheit fehlt die Grundlage für die eigentliche Feature-Entwicklung:
* **Roadmap-Status:** Gemäß `MASTER_ROADMAP.md` ist die Phase 3 (Feature Development) weiterhin **ON HOLD**.
* **Fehlende Spezifikationen:** Es existieren noch keine definierten Use-Cases, Datenmodelle oder API-Contracts (außer
Ping) für die kommenden Features.
* **UX/UI Design:** Konkrete Wireframes, Screen-Layouts oder Benutzer-Flows für die fachlichen Screens (z.B.
Nennungs-Übersicht) vom 🖌️ **[UI/UX Designer]** fehlen vollständig.
## 3. Fazit & Empfehlung
Ein verfrühter Start im Frontend würde bedeuten, ohne klare UI-Spezifikationen oder abgestimmte Backend-APIs "ins Blaue"
zu programmieren. Dies muss vermieden werden.
**Nächster logischer Schritt:**
Der 🎨 **[Frontend Expert]** schließt sich der Empfehlung des Backends an:
1. Der **🏗️ [Lead Architect]** muss den ausstehenden Domain-Workshop durchführen.
2. Im Anschluss (oder parallel) muss der **🖌️ [UI/UX Designer]** erste Wireframes für die neuen Features entwerfen.
3. Erst wenn Fachlichkeit (Domain Models) und Benutzerführung (UX-Flows) definiert sind, kann die
Frontend-Implementierung starten.
@@ -0,0 +1,50 @@
# Session Log: Infrastruktur-Analyse & Freigabe
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator] in Zusammenarbeit mit 🐧 [DevOps Engineer]
**Typ:** Infrastruktur-Review / Architektur-Entscheidung
## 1. Ausgangslage
Vor dem Start der fachlichen Implementierung wurde der 🐧 **[DevOps Engineer]** beauftragt, einen tiefgehenden Pre-Flight
Check der lokalen Docker-Infrastruktur (`docker-compose.yaml` und Teil-Dateien) durchzuführen. Ziel war es
sicherzustellen, dass das "Docs-as-Code" Setup robust, fehlerfrei und bereit für den Entwicklungsalltag ist.
## 2. Analyse-Ergebnisse
Das Setup (unterteilt in `dc-infra.yaml`, `dc-backend.yaml`, `dc-gui.yaml` und `dc-ops.yaml`) wurde als sehr robust und
durchdacht bewertet.
Folgende positive Aspekte wurden hervorgehoben:
* **Abhängigkeitsmanagement:** Exzellente Nutzung von `depends_on` mit `condition: service_healthy` (z.B. Backend wartet
auf Postgres und Keycloak).
* **Zentrale Konfiguration:** Erfolgreiche Einbindung von `config/app/base-application.yaml` via Volumes in die Spring
Boot Container.
* **Monitoring & Tools:** Das Ops-Profil bietet ein umfassendes Toolset (Mailpit, pgAdmin, Prometheus, Grafana).
### Identifizierter Klärungsbedarf (DevOps Perspektive)
Der **DevOps Engineer** wies auf eine Abweichung von den dokumentierten Leitlinien für die lokale Entwicklung hin:
* **Keycloak Setup:** Laut Playbook sollte für die lokale Entwicklung das offizielle Image (`quay.io/keycloak/keycloak`)
im schnellen `start-dev` Modus laufen.
* **Ist-Zustand:** Die `dc-infra.yaml` nutzt ein lokales Dockerfile (`config/docker/keycloak/Dockerfile`), führt einen
Build-Step (`kc.sh build`) aus und startet den Container im produktionsnahen `--optimized` Modus.
## 3. Architekturentscheidung (Owner)
Der **Owner** wurde über die Abweichung beim Keycloak-Setup informiert und hat folgende architektonische Entscheidung
getroffen:
* **Entscheidung:** Das aktuelle, produktionsnahe Keycloak-Setup (`build` + `start --optimized`) bleibt unverändert
bestehen. Es wird **nicht** auf den reinen `start-dev` Modus zurückgebaut.
* **Begründung:** Da die Entwicklung direkt auf dem `main`-Branch stattfindet, hat die **Dev/Prod-Parität** höchste
Priorität. Die lokale Umgebung soll so nah wie möglich an der späteren Produktionsumgebung (Zora) bleiben. Eine leicht
erhöhte initiale Build-Zeit des Containers wird zugunsten von maximaler Stabilität und Vorhersehbarkeit (Vermeidung
von "works on my machine" Problemen) in Kauf genommen.
## 4. Fazit & Nächste Schritte
* Die Infrastruktur-Analyse ist abgeschlossen.
* Das aktuelle Setup ist offiziell für die nächste Phase freigegeben.
* Das Team kann nun mit der fachlichen Implementierung (Backend/Frontend) beginnen.
@@ -0,0 +1,51 @@
# Session Log: Analyse der QA-Bereitschaft für die Feature-Entwicklung
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator] in Zusammenarbeit mit 🧐 [QA Specialist]
**Typ:** Code- & Projekt-Review
## 1. Ausgangslage
Nach den Analysen der Bereiche DevOps, Backend, Frontend und UI/UX hat der 🧐 **[QA Specialist]** das Projekt
hinsichtlich Testbarkeit, Test-Infrastruktur und "Shift-Left"-Qualitätssicherung bewertet.
## 2. Analyse-Ergebnisse (QA Specialist)
### 2.1 Technische Test-Infrastruktur: 🟢 Hervorragend
Das Projekt bietet eine exzellente Basis für eine moderne Test-Pyramide:
* **Zentrales Test-Modul:** Das Modul `:platform:platform-testing` bündelt alle wichtigen Test-Abhängigkeiten (JUnit 5,
AssertJ, MockK). Das sorgt für Konsistenz und vermeidet Versionskonflikte.
* **Integration Testing Setup:** Die Einbindung von `Testcontainers` (PostgreSQL, Keycloak, Kafka) ist vorhanden. Dies
ermöglicht deterministische Integrationstests gegen echte Infrastruktur-Komponenten, statt wackeliger Mocks.
* **Multiplatform Ready:** Die Test-SourceSets im `:core-domain` Modul sind für Kotlin Multiplatform (JVM, JS) korrekt
vorbereitet.
### 2.2 Fachliche Test-Spezifikation (Shift-Left): 🔴 Blockiert
Wie in den anderen Disziplinen fehlt die fachliche Grundlage:
* **Fehlende Akzeptanzkriterien:** Es existieren keine Use-Cases oder konkreten "Definition of Done" Kriterien für die
anstehenden Features.
* **Keine BDD-Szenarien:** Es gibt keine "Given-When-Then" (Gherkin) Spezifikationen, gegen die die Entwickler fachliche
Tests (TDD) schreiben könnten.
* **Testdaten-Mangel:** Da das finale Domain-Modell noch unklar ist, können noch keine realistischen Testdaten (
Mock-Objekte für Turniere, Nennungen etc.) definiert werden.
## 3. Fazit & Empfehlung
Ein sofortiger Implementierungsstart würde zu "technisch grünen", aber fachlich nutzlosen Tests führen. Die
Qualitätssicherung muss "Shift-Left" betrieben werden also weit vor der ersten Zeile Feature-Code.
**Nächste Schritte & Fahrplan (Empfehlung des QA Specialists):**
1. **Teilnahme am Domain Workshop:** Der QA Specialist muss in den anstehenden Workshop des **🏗️ [Lead Architect]**
integriert werden.
2. **Szenario-Definition:** Parallel zur Definition der Use-Cases durch den Architekten müssen die Akzeptanzkriterien
als Gherkin-Szenarien (Given-When-Then) dokumentiert werden.
3. **Edge-Cases aufdecken:** Im Workshop sollen Randfälle (z.B. "Was passiert bei einer Nennung ohne gültige Lizenz?")
identifiziert und als Test-Szenarien festgehalten werden.
Erst wenn diese fachlichen Test-Szenarien als Verträge existieren, dürfen die Entwickler mit der Implementierung
beginnen, um diese Verträge technisch zu erfüllen (Test-Driven Development Ansatz).
@@ -0,0 +1,54 @@
# Session Log: Analyse der UI/UX-Bereitschaft für die Feature-Entwicklung
**Datum:** 16. März 2026
**Verantwortlicher Agent:** 🧹 [Curator] in Zusammenarbeit mit 🖌️ [UI/UX Designer]
**Typ:** Code- & Projekt-Review
## 1. Ausgangslage
Nach den positiven technischen Reviews durch das Backend- und Frontend-Team hat der 🖌️ **[UI/UX Designer]** das Projekt
hinsichtlich der User Experience und Design-Bereitschaft analysiert. Der Fokus lag auf dem Zusammenspiel zwischen den
technischen Möglichkeiten, den alten System-Referenzen und den zukünftigen Anforderungen.
## 2. Analyse-Ergebnisse (UI/UX Designer)
### 2.1 Technische Design-Basis: 🟢 Gut
Die technische Umsetzung der grundlegenden Design-Sprache ist bereits im Frontend-Code verankert:
* **Design System (`AppTheme.kt`):** Ein starkes, "Enterprise-taugliches" Theme (Material 3) ist implementiert. Es
definiert Farbpaletten, Kontraste (inkl. Dark Mode) und Typografie-Hierarchien. Dies stellt sicher, dass neue
Komponenten konsistent und professionell aussehen werden.
* **Technologie (Compose):** Compose Multiplatform bietet die perfekte Basis, um hochgradig reaktive und responsive
Interfaces schnell zu entwickeln.
### 2.2 Fachliche UI/UX-Spezifikation: 🔴 Blockiert (Wireframes & Flows fehlen)
Die visuelle und konzeptionelle Ausarbeitung der eigentlichen Features fehlt komplett:
* **Fehlende UX-Flows:** Es gibt keine definierten Benutzerpfade. Es ist unklar, wie Nutzer durch die Kernprozesse (z.B.
Nennungen anlegen, Startlisten prüfen) navigieren sollen.
* **Umgang mit Legacy-Screenshots:** Die Bilder des alten "SuDo"-Systems (unter `docs/BilderSuDo/`) sind wertvolle
Referenzen für die Datenpunkte, **dürfen aber nicht 1:1 nachgebaut werden**. Das neue UI muss entschlackt, fokussiert
und intuitiver gestaltet werden ("Fokus auf den Sport").
* **Offline-First UX:** Ein entscheidender Aspekt fehlt: Das Interface-Design muss klar kommunizieren, ob der Nutzer
offline ist, ob Daten synchronisiert werden oder ob es Sync-Konflikte gibt. Diese speziellen UI-Muster müssen erst
gestaltet werden.
## 3. Fazit & Empfehlung
Ein Start der UI-Programmierung ohne vorherige Design-Spezifikationen würde unweigerlich zu einer unstrukturierten
Benutzeroberfläche ("Datenbank-Felder aufs UI klatschen") und damit zu einer schlechten User Experience führen.
**Nächste Schritte & Fahrplan (Empfehlung des UI/UX Designers):**
1. **Domain Workshop:** Teilnahme (passiv) am ausstehenden Workshop des **🏗️ [Lead Architect]**, um die Fachlichkeit und
die notwendigen Datenpunkte zu verstehen.
2. **Wireframing:** Erstellung von aufgeräumten, responsiven Wireframes (Mobile & Desktop) für die Kern-Flows (z.B.
Nennung, Startliste) basierend auf den neuen Modellen und unter zur Hilfenahme der SuDo-Screenshots als fachliche
Orientierung.
3. **Frontend-Abstimmung:** Review der Wireframes mit dem **🎨 [Frontend Expert]**, insbesondere hinsichtlich der
Offline-UX-Konzepte.
Erst nach der Freigabe der Wireframes für einen spezifischen Bounded Context sollte das Frontend-Team mit der
Implementierung der Screens beginnen.
@@ -0,0 +1,55 @@
# Session Log: 18.03.2026 - Domain Workshop (Fortsetzung) & Frontend Kick-off
**Teilnehmer:** Owner, 🏗️ [Lead Architect], 📜 [ÖTO/FEI Rulebook Expert], 👷 [Backend Developer], 🎨 [Frontend Expert],
🖌️ [UI/UX Designer], 🧹 [Curator]
## Ziel der Session
Zusammenfassung der Domain-Erkenntnisse vom Vortag, Festlegung des Scopes für das MVP (Phase 1) und Start der
Frontend-Implementierung auf Basis des "UI-Driven Development" Ansatzes.
## Ergebnisse & Beschlüsse
### 1. Scope für MVP (Phase 1)
* **Fokus-Turniere:** Die Turniere in Neumarkt (26128 und 26129) Ende April dienen als erstes großes Etappenziel (MVP
Feldtest).
* **Turnier-Kategorien:** Fokus ausschließlich auf **C-NEU** und **C**.
* **Sparten:** Fokus ausschließlich auf **Dressur (D)** und **Springen (S)**.
* **Begründung:** Diese Eingrenzung reduziert die Komplexität des Regelwerks massiv und ermöglicht eine schnelle
Auslieferung eines produktionsreifen Kernsystems für den Großteil der nationalen Turniere.
### 2. Frontend-Entwicklung (UI-Driven Development)
* Die Entwicklung startet beim Frontend (`frontend/shells/meldestelle-portal`), um den perfekten, praxisnahen
Workflow ("Enter & Tab") zu garantieren, bevor das Backend die Daten liefert.
* **Landing Page (`mo-code.at`):** Wurde neu designt. Kern-Säulen des Systems (Regelwerks-Intelligenz, Offline-First,
Speed-Workflow, Smarte Kassenführung) wurden als USPs platziert.
* **Aktuelle Turniere:** Eine neue Sektion auf der Landing Page zeigt eine Liste der kommenden Turniere (mit
Platzhaltern für Neumarkt 26128/26129).
* **Meldestelle Dashboard:** Nach dem Login gelangt der User nicht mehr auf eine generische "Welcome"-Seite, sondern in
ein dediziertes Dashboard.
* Links: Verwaltung der eigenen Turniere (inkl. Absprung ins Meldestellen-Cockpit).
* Rechts: System-Tools (Ping-Service, ZNS-Import).
* **Turnieranlage Wizard:** Der Button "+ Neues Turnier anlegen" führt nun in einen mehrstufigen Wizard:
1. Stammdaten & ZNS Import
2. Konfiguration (Austragungsplätze)
3. Funktionäre
4. Bewerbe anlegen (Master-Detail Ansicht analog zum Legacy-System)
* **Korrektur Compose-Updates:** Veraltete Compose-Komponenten (`Divider`, `TabRow`) wurden durch ihre modernen
Pendants (`HorizontalDivider`, `PrimaryTabRow`) ersetzt, um Kompilierfehler zu beheben.
### 3. Nächste Schritte (Backlog)
* **Backend:** Implementierung des ZNS-Importers (Entpacken der `zns.zip`, Einlesen der `.dat` Dateien mit Codepage 850,
Generierung erster Events).
* **Frontend:** Detaillierung der "Nennungs-Maske" (Cockpit), die für die schnelle telefonische Nennung optimiert werden
muss.
## Aktualisierte Dokumente
* `docs/03_Domain/01_Core_Model/Entities/Event_Structure_Diagram.md` (Scope-Eingrenzung auf C-NEU/C & D/S dokumentiert)
* `docs/03_Domain/03_Analysis/Domain_Workshop_Results_2026-03-17.md` (MVP-Fokus hinzugefügt)
* `frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt` (Landing Page, Dashboard & Wizard implementiert)
* `frontend/core/navigation/src/commonMain/kotlin/at/mocode/frontend/core/navigation/AppScreen.kt` (Routen für
Dashboard & CreateTournament hinzugefügt)
@@ -0,0 +1,65 @@
# Session Log: 19.03.2026 - Frontend "Turnier anlegen" & Offline-Architektur
**Teilnehmer:** Owner, 🏗️ [Lead Architect], 📜 [ÖTO/FEI Rulebook Expert], 👷 [Backend Developer], 🎨 [Frontend Expert],
🧹 [Curator]
## Ziel der Session
Erweiterung des Frontend-Konzepts für den Turnieranlage-Wizard (Setup) mit besonderem Fokus auf harte Offline-Szenarien,
Datenbank-Trennung pro Turnier, Synchronisation via USB-Stick und der architektonischen Trennung zwischen Web-App und
Master-Desktop-App.
## Ergebnisse & Beschlüsse
### 1. Trennung: Web-App vs. "Equest-Events Master Desktop"
Es wurde eine klare architektonische Trennung der Clients beschlossen, die auf den Fähigkeiten von Compose
Multiplatform (KMP) basiert:
* **Web-App (mo-code.at):** Dient als zentrale Anlaufstelle. Für die Öffentlichkeit (Ausschreibungen, Nennungen durch
Reiter) und als leichtgewichtiges "Meldestellen Dashboard" zur Übersicht. Sie benötigt keine komplexen lokalen
Datenbanken (Service Worker) für die Startseite.
* **Desktop-App ("Equest-Events Master Desktop"):** Eine herunterladbare, native Anwendung (.exe / .app). Dies ist das "
Profi-Werkzeug" für die Meldestelle vor Ort.
* *Nur* die Desktop-App hat volle Rechte auf das Dateisystem (OS-Ebene), um z.B. direkt auf USB-Sticks zuzugreifen.
* Sie beinhaltet exklusiv die "Admin-Features": Turnieranlage, ZNS-Import, OEPS-Export und die Initialisierung der
lokalen Offline-Datenbank (SQLite).
* Der Download-Link für diese Master-App ist direkt im Web-Dashboard für authentifizierte Meldestellen-Admins
integriert.
### 2. Hardcore Offline-First & Turnier-Datenbanken
* **Isolierte Datenbanken:** Um extreme Offline-Szenarien (kein Internet, kein lokales Netzwerk, "Plumpsklo"-Setup)
abzusichern, wird bei der Turnieranlage pro Turnier eine eigenständige, isolierte Datenbank (Turnier-Instanz)
initialisiert.
* **USB-Stick Synchronisation:** Die Master-Desktop-App muss in der Lage sein, diese Turnier-Datenbank komplett über das
Dateisystem zu exportieren und auf einem anderen Gerät (z.B. Desktop-App am Richterturm) wieder zu importieren. Es
gibt einen manuellen Sync-Prozess (Im-/Export) von Start- und Ergebnislisten via USB-Stick, falls WLAN/LAN ausfallen.
* **Spezifizierung Dateipfade im UI:** Der "Transfer"-Schritt im UI wurde verfeinert. Statt abstrakter Buttons gibt es
nun klare Eingabefelder für Datei- und Ordnerpfade inkl. File-Picker-Buttons (`...`), um den Desktop-Charakter der
Anwendung zu unterstreichen.
### 3. Fremddaten, Y- & Z-Nummern
* **Regelwerks-Bestätigung:** Der Rulebook Expert bestätigte, dass die Vergabe von **Y-Nummern** (junge nationale Pferde
ohne Registrierung) und **Z-Nummern** (ausländische Pferde) für *alle* nationalen Turniere gilt, nicht nur für C-NEU.
* **Manuelle Anlage:** Das System unterstützt zwingend die nahtlose manuelle Anlage dieser Pferde und Reiter, die nicht
im ZNS existieren (z.B. Gäste aus CZ). Diese manuellen Anlagen erfolgen auf Basis der isolierten Turnier-Datenbank.
### 4. UI-Erweiterung: Der neue "Transfer"-Schritt im Wizard
Der geführte Wizard zum Anlegen eines Turniers in der Desktop-App (`MainApp.kt`) wurde um den essenziellen ersten
Schritt erweitert: **"Transfer & Initialisierung"**.
Dieser Schritt fungiert als technische Schaltzentrale und beinhaltet:
* Initialisierung der Turnier-Datenbank (OEPS Nummer).
* ZNS-Daten Import (OEPS) & Import von externen Zucht-Daten (z.B. AWÖ) via Dateiauswahl.
* OEPS-Ergebnis-Export (Generierung der `.erg` Datei nach Turnierende) via Dateiauswahl.
* Manuelle Up-/Downloads für den USB-Stick Sync (Turnier Export / Import) via Verzeichnisauswahl.
## Aktualisierte Dokumente
* `frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt` (Fünfstufiger Wizard mit detailliertem "
Transfer"-Schritt und File-Picker Mockups implementiert. Dashboard-Hinweis auf Desktop-App Download hinzugefügt).
* `frontend/shells/meldestelle-portal/src/jvmMain/kotlin/main.kt` (Titel der Desktop-Anwendung auf "Equest-Events Master
Desktop" geändert).
@@ -0,0 +1,134 @@
# Session Log: 19.03.2026 - POC Rollen-basiertes Dashboard & Keycloak-Fix
**Teilnehmer:** Owner, 🏗️ [Lead Architect], 🎨 [Frontend Expert], 🧹 [Curator]
---
## Ziel der Session
Übernahme und Weiterführung eines POC, der zuvor mit Gemini begonnen wurde. Ziel war es, die rollenbasierte
Dashboard-Trennung (Admin vs. Veranstalter) sowohl in der Web-App als auch in der Desktop-App zum Laufen zu bringen.
---
## Ausgangslage (aus Gemini-Chat-Verlauf übernommen)
Der vorherige Chat-Verlauf (`docs/Neumarkt2026/Chat-Verlauf-Gemini_2026-03-19_16-30.txt`) wurde analysiert.
Folgende Punkte waren bereits implementiert, aber noch nicht vollständig verifiziert:
- `LoginScreen.kt`: Tab-Navigation, `singleLine = true` für Enter/Tab-Behandlung
- `PlatformType`: `expect/actual`-Mechanismus (`currentPlatform()`) für `WEB` vs. `DESKTOP`
- `AppScreen.kt`: `Login` als `data class Login(val returnTo: AppScreen? = null)`
- `MainApp.kt`: 4-Wege-Weiche für rollenbasiertes Routing
- `AuthTokenManager.kt`: Extraktion von `realm_access.roles` aus JWT, `isAdmin()` und `isOrganizer()`
- `meldestelle-realm.json`: Rolle `ORGANIZER`, Test-User `urfv_neumarkt` (Passwort: `Turnier#2026`)
---
## Durchgeführte Fixes
### Fix 1 Compiler-Warnung behoben (`AuthTokenManager.kt`)
**Problem:** `Json { ignoreUnknownKeys = true }` wurde als Instanz-Variable deklariert → bei jeder Instanz neu erstellt.
**Warnung:**
```
w: Redundant creation of Json format. Creating instances for each usage can be slow.
```
**Lösung:** `jsonParser` in ein `companion object` verschoben → wird nur einmal pro Klasse erstellt.
```kotlin
companion object {
// Shared Json instance einmalig erstellt, nicht bei jedem Aufruf
private val jsonParser = Json { ignoreUnknownKeys = true }
}
```
### Fix 2 Web-Sicht nach Rollen aufgeteilt (`MainApp.kt`)
Die 4-Wege-Weiche in `DashboardScreen` war bereits korrekt implementiert:
| Platform | Rolle | Dashboard |
|----------|-------------|----------------------------------------------------------------------|
| Desktop | `ADMIN` | Steuerungszentrale (alle Turniere, Filter, Toggles) |
| Desktop | `ORGANIZER` | Meldestellen-Software (Turnier initialisieren) |
| Web | `ADMIN` | Admin-Web-Portal + Download "Master-Desktop-App" |
| Web | `ORGANIZER` | Veranstalter-Portal + Download "Meldestelle-App" + Aktivierungs-Code |
### Fix 3 Keycloak-Config verifiziert (`meldestelle-realm.json`)
- Rolle `ORGANIZER` vorhanden ✅
- User `urfv_neumarkt` mit Rollen `USER` + `ORGANIZER` korrekt konfiguriert ✅
- User `admin` mit Rolle `ADMIN` korrekt konfiguriert ✅
---
## Problem: Beide User sahen dasselbe Dashboard
**Symptom:** Nach dem Login als `admin` und als `urfv_neumarkt` wurde immer dasselbe Dashboard angezeigt.
**Ursache:** Keycloak startet mit `--import-realm` und speichert alle Daten in **PostgreSQL** (`postgres-data` Volume).
Der Realm wird **nur beim allerersten Start** importiert, wenn er noch nicht in der Datenbank existiert.
Alle späteren Änderungen an der `meldestelle-realm.json` werden **ignoriert**, solange das PostgreSQL-Volume existiert.
→ Die Rollen `ADMIN` und `ORGANIZER` waren nie in Keycloak angekommen, weil das Volume noch den alten Stand enthielt.
---
## Lösung: PostgreSQL-Volume zurücksetzen
```bash
# Schritt 1 Alle Container stoppen
docker compose down
# Schritt 2 PostgreSQL-Volume löschen (⚠️ alle DB-Daten gehen verloren für POC OK)
docker volume rm meldestelle_postgres-data
# Schritt 3 Container neu starten (Keycloak importiert Realm frisch)
docker compose --profile infra up -d
```
---
## Verifikation nach dem Neustart
Nach dem Neustart muss das JWT-Token die korrekten Rollen enthalten.
Prüfung via [jwt.io](https://jwt.io) oder Browser-DevTools → Network-Tab → Token-Request:
**Für `admin`:**
```json
"realm_access": {
"roles": ["ADMIN", "USER", "MELD_USER", ...]
}
```
**Für `urfv_neumarkt`:**
```json
"realm_access": {
"roles": ["USER", "ORGANIZER"]
}
```
Sobald die Rollen korrekt im JWT sind, funktioniert die Dashboard-Weiche in `DashboardScreen` automatisch.
---
## Aktualisierte Dateien
| Datei | Änderung |
|-----------------------------------------------------------------------|--------------------------------------------------------------------------|
| `frontend/core/auth/src/commonMain/kotlin/.../AuthTokenManager.kt` | `jsonParser` in `companion object` verschoben (Compiler-Warnung behoben) |
| `config/docker/keycloak/meldestelle-realm.json` | Verifiziert keine Änderungen notwendig |
| `frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt` | Verifiziert 4-Wege-Weiche korrekt implementiert |
---
## Offene Punkte / Nächste Schritte
- [ ] PostgreSQL-Volume zurücksetzen und Keycloak neu starten (muss vom Owner manuell durchgeführt werden)
- [ ] JWT-Token nach Neustart verifizieren (jwt.io)
- [ ] End-to-End-Test: Login als `admin` → Admin-Dashboard, Login als `urfv_neumarkt` → Veranstalter-Dashboard
@@ -0,0 +1,75 @@
---
type: SessionLog
date: 2026-03-24
agents:
- Lead Architect
- Curator
status: ABGESCHLOSSEN
---
# Session Log: ADR-0014 & ADR-0015 — Bounded Context Mapping & Context Map
🏗️ **[Lead Architect]** | 🧹 **[Curator]** | 24. März 2026
---
## Ziel der Session
ADRs für Bounded Context Mapping und Context Map vervollständigen (PHASE 4, Task 1).
---
## Ergebnisse
### ADR-0014: Bounded Context Mapping (SCS-Architektur)
**Datei:** `docs/01_Architecture/adr/0014-bounded-context-mapping-de.md`
Dokumentiert die 6 Bounded Contexts als Self-Contained Systems:
| Context | Domänen-Typ | Priorität |
|----------------------------|-------------------|-----------|
| `registration-context` | Core Domain | P1 |
| `actor-context` | Supporting Domain | P1 |
| `competition-context` | Supporting Domain | P2 |
| `event-management-context` | Supporting Domain | P2 |
| `billing-context` | Generic Domain | P3 |
| `identity-context` | Generic Domain | P3 |
Für jeden Context dokumentiert: Aggregate Roots, Ubiquitous Language (Auswahl), Kern-Invarianten.
Begründung für Ablehnung der alten technischen Modulaufteilung (`masterdata`, `members`, `horses`, `events`).
---
### ADR-0015: Context Map & Integration Patterns
**Datei:** `docs/01_Architecture/adr/0015-context-map-de.md`
Dokumentiert 7 Context-Beziehungen mit ASCII-Diagramm und Detailtabellen:
| Beziehung | Pattern |
|-----------------------------------------------------|-----------------------------------|
| ZNS → `actor-context` | Upstream/Downstream + ACL |
| `actor-context``registration-context` | Customer/Supplier + Shared Kernel |
| `event-management-context``registration-context` | Customer/Supplier + Shared Kernel |
| `registration-context``competition-context` | Domain Events (asynchron) |
| `registration-context``billing-context` | Domain Events + ACL |
| `competition-context``billing-context` | Domain Events + ACL |
| Keycloak → alle Contexts | Conformist (OIDC/JWT) |
Enthält: ACL-Implementierungsrichtlinien, Offline-First-Verhalten pro Szenario.
---
## MASTER_ROADMAP Updates
- `[x]` **ADRs vervollständigen** (PHASE 4, Lead Architect) — abgeschlossen
- ADR-Tabelle: Einträge #8 (ADR-0014) und #9 (ADR-0015) hinzugefügt
---
## Offene Punkte (nächste Session)
- `[ ]` **API-Design:** Schnittstellen zwischen den Contexts definieren (Anti-Corruption Layer) — Lead Architect
- `[ ]` **`actor-context`:** `DomPferd`, `DomFunktionär`, `DomVerein` implementieren — Backend Developer
@@ -0,0 +1,92 @@
---
type: SessionLog
date: 2026-03-24
agent: Lead Architect
phase: PHASE 4
task: API-Design & Anti-Corruption Layer
status: ABGESCHLOSSEN
---
# 🧹 [Curator] Session Log API-Design & ACL
**Datum:** 24. März 2026
**Agent:** 🏗️ Lead Architect
**Phase:** PHASE 4 MVP-Implementierung
**Aufgabe:** API-Design: Schnittstellen zwischen den Contexts definieren (Anti-Corruption Layer)
---
## Ergebnisse
### Erstellt
- **`ADR-0016`** (`docs/01_Architecture/adr/0016-api-design-acl-de.md`)
- Architektur-Muster: Ports & Adapters (Hexagonal) für alle Contexts
- REST-API-Katalog für alle 3 P1-Contexts (`actor`, `event-management`, `registration`)
- Vollständige DTO-Definitionen (Inbound Commands + Outbound DTOs)
- ACL-Port-Interfaces: `AktorReferenzPort`, `TurnierReferenzPort`
- ACL-Adapter-Implementierung mit Übersetzungslogik (DTO → Referenz-Objekt)
- Domain Events-Katalog: 8 Events über 3 Contexts
- ZNS-Schnittstelle: `ZnsPort` mit A-Satz / B-Satz
- Offline-First Cache-Strategie für ACL-Adapter
- Implementierungs-Reihenfolge (P1-Priorität)
### Aktualisiert
- **`MASTER_ROADMAP.md`**: Task `[x]` abgehakt, ADR #10 in Tabelle eingetragen
- **`docs/01_Architecture/adr/README.md`**: ADR-0016 eingetragen
---
## Kern-Entscheidungen (ADR-0016)
| Bereich | Entscheidung |
|---------------|--------------------------------------------------|
| Muster | Ports & Adapters (Hexagonal Architecture) |
| Kommunikation | REST (synchron) + Domain Events (asynchron) |
| ACL-Regel | Domain-Objekte verlassen den Context **niemals** |
| DTOs | Flach, serialisierbar, ohne Domänen-Logik |
| Offline | Lokale SQLite-Caches in ACL-Adaptern |
| ZNS | Eigener `ZnsPort` im `actor-context` (isoliert) |
---
## REST-API Übersicht
| Context | Base-URL | Endpunkte |
|----------------------------|-------------------------|------------------------------------------|
| `actor-context` | `/api/v1/actors` | 8 (Reiter, Pferde, Funktionäre, Vereine) |
| `event-management-context` | `/api/v1/events` | 6 (Veranstaltungen, Turniere, Bewerbe) |
| `registration-context` | `/api/v1/registrations` | 6 (Nennungen, Transfer) |
---
## Domain Events Übersicht
| Context | Events |
|----------------------------|------------------------------------------------------------------|
| `actor-context` | `ReiterAktualisiert`, `PferdAktualisiert`, `ReiterGesperrt` |
| `registration-context` | `NennungEingereicht`, `NennungStorniert`, `NennungTransferiert` |
| `event-management-context` | `TurnierEroeffnet`, `NennungsschlussErreicht`, `TurnierAbgesagt` |
---
## Status PHASE 4: Lead Architect Tasks
- [x] ADRs vervollständigen (Bounded Context Mapping + Context Map) → ADR-0014, ADR-0015
- [x] API-Design & ACL definieren → ADR-0016
**Lead Architect Tasks PHASE 4: ✅ ABGESCHLOSSEN**
---
## Nächste Schritte (Backend Developer)
Gemäß Implementierungs-Reihenfolge aus ADR-0016:
1. `actor-context` REST API (`/api/v1/actors`) implementieren
2. `event-management-context` REST API (`/api/v1/events`) implementieren
3. ACL-Adapter im `registration-context` implementieren
4. `registration-context` REST API (`/api/v1/registrations`) implementieren
5. Domain Event `NennungEingereicht` als erstes Event
6. Offline-Cache (Bulk-Sync beim Turnier-Download)
@@ -0,0 +1,70 @@
---
type: Session Log
date: 2026-03-24
agent: Backend Developer
status: ABGESCHLOSSEN
roadmap_phase: PHASE 4 MVP-Implementierung
---
# Session Log: actor-context Domain-Modelle
👷 **[Backend Developer]** | 24. März 2026
## Ziel
Domain-Modelle für `DomPferd`, `DomFunktionär` und `DomVerein` im `actor-context` implementieren (PHASE 4,
MASTER_ROADMAP).
---
## Ergebnis
### ✅ DomPferd
- Bereits vollständig und ÖTO-konform im Modul `backend/services/horses/horses-domain` vorhanden.
- Keine Änderungen notwendig.
### ✅ DomFunktionaer (neu)
- **Datei:**
`backend/services/officials/officials-domain/src/main/kotlin/at/mocode/officials/domain/model/DomFunktionaer.kt`
- Aggregate Root des `officials`-Bounded Context.
- Felder: `richterNummer` (ZNS RICHT01.dat), `vorname`, `nachname`, `geburtsdatum`, `rollen`, `richterQualifikation`,
`qualifiziertFuerSparten`, `email`, `telefon`, `vereinsNummer`, `istAktiv`, `bemerkungen`, `datenQuelle`.
- Domain-Methoden: `getDisplayName()`, `istRichterFuerSparte()`, `istTba()`, `validateFuerTurniereinsatz()` (Warn-Logik,
kein harter Fehler).
### ✅ DomVerein (neu)
- **Datei:** `backend/services/clubs/clubs-domain/src/main/kotlin/at/mocode/clubs/domain/model/DomVerein.kt`
- Aggregate Root des `clubs`-Bounded Context.
- Felder: `vereinsNummer` (ZNS VEREIN01.dat, 4-stellig), `name`, `kurzname`, `bundesland`, `ort`, `plz`, `strasse`,
`email`, `telefon`, `website`, `oepsRegionNummer`, `istVeranstalter`, `istAktiv`, `bemerkungen`, `datenQuelle`.
- Domain-Methoden: `getDisplayName()`, `getDisplayNameWithNummer()`, `hasCompleteAddress()`,
`validateFuerVeranstaltung()` (Warn-Logik).
### ✅ Neue Enums in core-domain
- **Datei:** `core/core-domain/src/commonMain/kotlin/at/mocode/core/domain/model/Enums.kt`
- `FunktionaerRolleE`: TBA, RICHTER, PARCOURSBAUER, STRECKENDESIGNER, TIERARZT, STEWARD, STARTER, ZEITNEHMER,
PROTOKOLLFUEHRER, SONSTIGE
- `RichterQualifikationE`: GA, G3, G2, G1, INTERNATIONAL, SONSTIGE (gemäß ZNS RICHT01.dat)
---
## Design-Entscheidungen
| Entscheidung | Begründung |
|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DomFunktionaer` statt Erweiterung von `DomOfficial` | `DomOfficial` war ein minimaler ZNS-Import-Stub. `DomFunktionaer` ist das vollständige ÖTO-konforme Domain-Modell mit Rollen und Sparten-Qualifikation. |
| `DomVerein` statt Erweiterung von `DomClub` | Analog: `DomClub` war ein ZNS-Import-Stub. `DomVerein` enthält Adresse, Kontakt, Veranstalter-Flag und OEPS-Region. |
| Warn-Logik statt harter Fehler | Konsistent mit ADR-0016 und Override-Event-Prinzip: `validateFuerTurniereinsatz()` und `validateFuerVeranstaltung()` geben Warnungen zurück, kein Exception-Throwing. |
| `rollen: Set<FunktionaerRolleE>` | Eine Person kann mehrere Rollen haben (z.B. TBA + Richter). Set verhindert Duplikate. |
---
## Nächste Schritte (PHASE 4)
- [ ] `registration-context`: `DomBewerb`, `DomAbteilung`, `DomStartliste` implementieren.
- [ ] `event-management-context`: `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementieren.
- [ ] Persistenz: Repository-Interfaces und DB-Migrationen (Flyway/Liquibase).
@@ -0,0 +1,105 @@
---
date: 2026-03-24
type: Session Log
agents: UI/UX Designer, Lead Architect, ÖTO/FEI Rulebook Expert, Curator
status: COMPLETED
---
# Session Log DDD-Analyse, Terminologie & Ubiquitous Language
🧹 **[Curator]** | 24. März 2026
---
## Zusammenfassung der Session
Diese Session umfasste mehrere aufeinander aufbauende Diskussionen rund um das Domain-Design,
die ÖTO-konforme Terminologie und die Erstellung der offiziellen Ubiquitous Language.
---
## Durchgeführte Aktivitäten
### 1. Figma-Analyse (Vision_01 → Vision_02 → Vision_03)
- Alle drei Figma-Prototypen wurden analysiert und verglichen
- **Vision_03** wurde als offizieller Design-Baseline festgelegt
- Vision_03 deckt den vollständigen Kern-Workflow ab: Login → Veranstalter → Veranstaltung → Turnier → Nennungen →
Startlisten → Ergebnisse
- Fehlende Screens aus Vision_02 (Startlisten, Ergebnislisten, Veranstalter-Flow) sind in Vision_03 vollständig
implementiert
### 2. Technologie-Entscheidung: Desktop-First mit KMP
- Fokus auf **Compose Desktop (KMP)** als primäre Plattform
- Sharing-Grad: ~100% Business Logic, ~8090% UI-Komponenten, ~70% Layout/Navigation
- Desktop-App zuerst → Shared Module extrahieren → Web-Portal aufbauen
### 3. DDD-Analyse: 6 Bounded Contexts (SCS-Architektur)
| SCS | Kontext | Priorität |
|----------------------------|---------------------------------------|-----------|
| `registration-context` | Nennungs-Workflow (Herzstück) | P1 |
| `actor-context` | Reiter, Pferde, Funktionäre, ZNS | P1 |
| `competition-context` | Bewerbe, Startlisten, Ergebnisse | P2 |
| `event-management-context` | Veranstaltung, Turnier, Ausschreibung | P2 |
| `billing-context` | Abrechnung, Kassa, Gebühren | P3 |
| `identity-context` | Auth, Rollen | P3 |
| `series-context` | Cups, Serien, Meisterschaften | Phase 2+ |
### 4. Terminologie-Klärung (ÖTO § 2 Abs. 1)
- **Kritische Korrektur:** „Veranstaltung" ≠ „Turnier" in der ÖTO
- `Veranstaltung` = Oberbegriff (interne ID, selbst vergeben) für alle pferdesportlichen Veranstaltungen
- `Turnier` = Spezialisierung mit Ausschreibung + OEPS-Turniernummer (§ 2 Abs. 2)
- Eine Veranstaltung kann mehrere Turniere enthalten (z.B. CDN + CSN am selben Wochenende)
### 5. Meisterschaften / Cups / Serien Eigene Reglements
- Jede Meisterschaft, jeder Cup und jede Serie besitzt ein **eigenes, individuelles Reglement**
- Das Reglement ist **nicht** durch die ÖTO allein abgedeckt
- Kritische Architektur-Konsequenz: `series-context` muss Reglement als **konfigurierbare Entität** abbilden (kein
Hard-Coding)
- Verschiedene Cups können unterschiedliche Punktesysteme haben → pluggable Berechnungsmodell erforderlich
- **Paar-Bindung** (Punkte an Reiter+Pferd vs. nur Reiter) ist pro Reglement konfigurierbar
---
## Erstellte / Aktualisierte Dokumente
| Dokument | Aktion | Beschreibung |
|----------------------------------------------------------------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` | ✅ NEU ERSTELLT | Offizielle Domänen-Terminologie mit ÖTO-Referenzen, Bounded Context Zuordnung, Hierarchie-Diagramm, Reglement-Hinweis für Cups/Serien/Meisterschaften und MVP-Scope-Tabelle |
| `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` | ✅ KORRIGIERT | Drei Korrekturen eingearbeitet (📜 ÖTO/FEI Rulebook Expert Review): **Abteilung** als kleinste Einheit für Nennungen/Startlisten/Ergebnisse mit Abteilungsnummer und Referenzformat `BW:9 Abt:1`; **Bewerb** korrigiert (nicht mehr „kleinste Einheit"); **Kopfnummer** als nicht eindeutige ID markiert; **Lebensnummer** mit Hinweis auf inkonsistente ZNS-Daten ergänzt |
| `core/core-domain/.../Enums.kt` | ✅ ERWEITERT | Neue Enums: `SparteE`, `TurnierkategorieE`, `VeranstaltungsTypE`, `LizenzKlasseE`, `NennungsStatusE`, `StartwunschE` alle ÖTO-konform mit KDoc-Kommentaren |
| `backend/services/persons/persons-domain/.../DomReiter.kt` | ✅ NEU ERSTELLT | Reiter-Domänenmodell (actor-context): Satznummer als ZNS-Primärschlüssel, LizenzKlasse, Startkarte, Sparten-Lizenz, Gastreiter-Flag, `validateForNennung()` gibt nur Warnungen (kein harter Fehler) |
| `backend/services/entries/entries-domain/.../DomNennung.kt` | ✅ NEU ERSTELLT | Nennungs-Domänenmodell (registration-context): Referenz auf Abteilung (kleinste Einheit), Reiter, Pferd, Zahler; Nachnennung-Flag, Gebühren-Verzicht, Status-Lifecycle |
| `backend/services/entries/entries-domain/.../DomNennungsTransfer.kt` | ✅ NEU ERSTELLT | Transfer-Domänenmodell: explizites Audit-Trail (alter/neuer Reiter, altes/neues Pferd), Override-Event-Referenz, `isValid()` prüft dass mindestens Reiter oder Pferd getauscht wurde |
| `backend/services/entries/entries-domain/build.gradle.kts` | ✅ NEU ERSTELLT | Neues KMP-Modul nach Muster `horses-domain`; in `settings.gradle.kts` registriert; `compileKotlinJvm` erfolgreich |
---
## Wichtige Entscheidungen (ADRs)
1. **Vision_03 = Design-Baseline** für die KMP-Implementierung
2. **Desktop-First-Strategie** mit KMP/Compose Desktop
3. **`Veranstaltung``Turnier`** Terminologie gemäß ÖTO § 2 Abs. 1 festgelegt
4. **6 Bounded Contexts** als SCS-Architektur definiert
5. **`series-context`** ist Phase 2+ Architektur ist aber von Anfang an vorbereitet
6. **Cups/Serien/Meisterschaften** benötigen eigene, konfigurierbare Reglements
---
## Nächste Schritte (Empfehlung)
- [x] 👷 **[Backend Developer]**: Kotlin Domain-Modelle für `registration-context` und `actor-context` definieren
- [x] 🏗️ **[Lead Architect]**: MASTER_ROADMAP mit den 6 Bounded Contexts aktualisieren →
`docs/01_Architecture/MASTER_ROADMAP.md`
- [x] 🎨 **[Frontend Expert]**: KMP/Compose Desktop Projektstruktur aufsetzen
- [x] 📜 **[ÖTO/FEI Rulebook Expert]**: Abteilungs-Trennungs-Schwellenwerte (sparten- und klassenabhängig) recherchieren
und dokumentieren → `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md`
---
*Session-Dauer: ~24. März 2026, ganztägig*
*Curator: Junie (KI-Agent)*
@@ -0,0 +1,117 @@
---
date: 2026-03-24
type: Session Log
agents: Frontend Expert, Curator
status: COMPLETED
---
# Session Log KMP/Compose Desktop Shell aufsetzen
🎨 **[Frontend Expert]** & 🧹 **[Curator]** | 24. März 2026
---
## Zusammenfassung der Session
Aufsetzen der dedizierten Desktop-Shell `meldestelle-desktop` als eigenständiges
JVM/Compose-Desktop-Modul gemäß Desktop-First-Strategie (ADR-0009) und Vision_03-Design-Baseline.
---
## Durchgeführte Aktivitäten
### 1. Neues Modul: `frontend/shells/meldestelle-desktop`
- Eigenständige Desktop-Shell, getrennt vom Web-Portal (`meldestelle-portal`)
- Reines JVM-Modul (kein JS/WASM) Desktop-First gemäß MASTER_ROADMAP
- In `settings.gradle.kts` registriert
- `compileKotlinJvm` ✅ BUILD SUCCESSFUL
### 2. Projektstruktur
```
frontend/shells/meldestelle-desktop/
├── build.gradle.kts # JVM-only, compose.desktop, nativeDistributions
└── src/jvmMain/kotlin/at/mocode/desktop/
├── main.kt # application {} Entry-Point, Koin-Init, Window
├── DesktopApp.kt # Login-Gate + Haupt-Composable
├── di/
│ └── DesktopModule.kt # Koin: DesktopNavigationPort, CurrentUserProvider, DeepLinkHandler
├── navigation/
│ └── DesktopNavigationPort.kt # StateFlow-basierte Navigation
└── screens/
├── DesktopMainLayout.kt # Sidebar (220dp) + Content-Bereich
├── PlaceholderContent.kt # Wiederverwendbarer Platzhalter
├── VeranstaltungenScreen.kt # Übersicht + "Neue Veranstaltung"-Button
├── VeranstaltungNeuScreen.kt # Tabs: Übersicht | Stammdaten* | Organisation | Preisliste
├── VeranstaltungDetailScreen.kt # Übersicht-Tab + Turniere-Section
├── TurnierNeuScreen.kt # Tabs: Übersicht | Stammdaten | Organisation | Bewerbe⭐* | Preisliste
├── TurnierDetailScreen.kt # Bewerbe-Tab integriert NennungsMaske (nennung-feature)
└── AktorScreens.kt # Reiter, Pferde, Funktionäre, Meisterschaften, Cups
```
### 3. Navigation gemäß Vision_03
Sidebar-Navigation mit 6 Einträgen (links, 220dp, Material3 `surfaceVariant`):
| Eintrag | Route | Status |
|-----------------|--------------------|---------------------------------|
| Veranstaltungen | `/veranstaltungen` | ✅ Screen implementiert |
| Reiter | `/reiter` | ✅ Placeholder |
| Pferde | `/pferde` | ✅ Placeholder |
| Funktionäre | `/funktionaere` | ✅ Placeholder |
| Meisterschaften | `/meisterschaften` | ✅ Placeholder (Phase 2+) |
| Cups | `/cups` | ✅ Placeholder (Phase 2+) |
| Logout | — | ✅ Löscht Token, zurück zu Login |
### 4. Neue `AppScreen`-Einträge (core/navigation)
Folgende Screens wurden in `AppScreen.kt` ergänzt:
- `Veranstaltungen`, `VeranstaltungNeu`, `VeranstaltungDetail(id)`
- `TurnierNeu(veranstaltungId)`, `TurnierDetail(veranstaltungId, turnierId)`
- `Reiter`, `Pferde`, `Funktionaere`, `Meisterschaften`, `Cups`
### 5. Nennungs-Integration
- `TurnierDetailScreen` → Bewerbe-Tab (⭐ Standard-Tab) integriert `NennungsMaske` aus `nennung-feature`
- Callbacks für Startliste, Ergebnisse, Abrechnung als TODO vorbereitet
---
## Erstellte / Aktualisierte Dokumente
| Dokument | Aktion | Beschreibung |
|-----------------------------------------------------------------------------------|----------------|---------------------------------------------------------------------|
| `frontend/shells/meldestelle-desktop/build.gradle.kts` | ✅ NEU | JVM-only Shell, compose.desktop, nativeDistributions (Deb/Msi/Dmg) |
| `frontend/shells/meldestelle-desktop/src/.../main.kt` | ✅ NEU | application {} Entry-Point, Koin-Init, Window 1400×900 |
| `frontend/shells/meldestelle-desktop/src/.../DesktopApp.kt` | ✅ NEU | Login-Gate, delegiert an DesktopMainLayout |
| `frontend/shells/meldestelle-desktop/src/.../di/DesktopModule.kt` | ✅ NEU | Koin-Modul mit Navigation, CurrentUserProvider, DeepLinkHandler |
| `frontend/shells/meldestelle-desktop/src/.../navigation/DesktopNavigationPort.kt` | ✅ NEU | StateFlow-Navigation |
| `frontend/shells/meldestelle-desktop/src/.../screens/*.kt` | ✅ NEU | 8 Screen-Dateien (Layout, Placeholders, Veranstaltung/Turnier-Flow) |
| `frontend/core/navigation/.../AppScreen.kt` | ✅ ERWEITERT | 10 neue Desktop-Screens ergänzt |
| `settings.gradle.kts` | ✅ ERWEITERT | `:frontend:shells:meldestelle-desktop` registriert |
| `docs/01_Architecture/MASTER_ROADMAP.md` | ✅ AKTUALISIERT | Frontend-Expert-Tasks als abgeschlossen markiert |
---
## Wichtige Entscheidungen
1. **Eigenständiges Modul** statt Erweiterung des Portal-Shells → saubere Trennung Desktop/Web
2. **Login-Gate** in `DesktopApp.kt` → Desktop startet immer mit Login, kein Landing-Screen
3. **`PrimaryTabRow`** statt deprecated `TabRow` verwendet
4. **`NennungsMaske`** direkt im Bewerbe-Tab des `TurnierDetailScreen` integriert
---
## Nächste Schritte (Empfehlung)
- [ ] 👷 **[Backend Developer]**: `DomVeranstaltung`, `DomTurnier`, `DomBewerb`, `DomAbteilung` implementieren
- [ ] 🎨 **[Frontend Expert]**: `VeranstaltungenScreen` mit echten Daten aus Repository befüllen
- [ ] 🎨 **[Frontend Expert]**: Startlisten- und Ergebnisse-Screens implementieren (competition-context)
- [ ] 🎨 **[Frontend Expert]**: Formular-Felder für `VeranstaltungNeuScreen` und `TurnierNeuScreen` ausbauen
---
*Session-Dauer: 24. März 2026*
*Curator: Junie (KI-Agent)*
@@ -0,0 +1,78 @@
---
type: Session Log
date: 2026-03-24
agent: Backend Developer
context: event-management-context
status: ABGESCHLOSSEN
---
# Session Log: event-management-context Domain-Modelle
👷 **[Backend Developer]** | 24. März 2026
## Ziel
Implementierung der Domain-Modelle `DomVeranstaltung`, `DomTurnier` und `DomAusschreibung`
für den `event-management-context` gemäß ÖTO § 2 Abs. 1 und ADR-0003 (`Veranstaltung ≠ Turnier`).
---
## Implementierte Modelle
### `DomVeranstaltung` (`events-domain`)
- **Aggregate Root** für den organisatorischen Rahmen einer pferdesportlichen Veranstaltung.
- Felder: `veranstaltungId`, `name`, `veranstaltungsTyp`, `sparten`, `veranstalterVereinId`,
`verantwortlicheFunktionaerId`, `startDatum`, `endDatum`, `ort`, `nennschluss`, `status`,
`ausschreibungsId`, `oepsGenehmigungsNummer`, `bemerkungen`, Audit-Felder.
- Warn-Logik: `validateNennungsmoeglichkeit()` (Status GENEHMIGT + Nennschluss vorhanden),
`validateFuerEinreichung()` (Pflichtfelder, Datum-Konsistenz, Ausschreibung verknüpft).
### `DomTurnier` (`events-domain`)
- **Aggregate Root** für ein einzelnes Turnier innerhalb einer Veranstaltung.
- Felder: `turnierId`, `veranstaltungId` (FK), `name`, `sparte`, `kategorie`, `datum`,
`richterObmannId`, `parcoursbauerId`, `status`, `maxBewerbe`, `istMeisterschaft`, `bemerkungen`, Audit-Felder.
- Warn-Logik: `validateFunktionaerBesetzung()` (Richter-Obmann Pflicht; Parcoursbauer Pflicht bei Springen),
`validateFuerPlanung()` (Pflichtfelder, positive maxBewerbe).
### `DomAusschreibung` (`events-domain`)
- **Aggregate Root** für das offizielle Ausschreibungs-Dokument.
- Felder: `ausschreibungsId`, `veranstaltungId` (FK), `titel`, `sparten`, `nennschluss`,
`nachnennung`, `nachnennungBis`, Gebühren in Cent (Integer, kein Float), `tierwohleuroAktiv`,
Veranstaltungsort, Stallplätze, Kontakt, `status`, `eingereichtAm`, `genehmigungsNummer`, Audit-Felder.
- Warn-Logik: `validateFuerEinreichung()` (Pflichtfelder, Gebühren ≥ 0, Nachnennungs-Datum-Konsistenz).
- Hilfsmethoden: `getNenngebuehrAlsEuroString()`, `getGesamtgebuehrCent()`.
---
## Neue Enums in `Enums.kt` (`core-domain`)
| Enum | Werte |
|-------------------------|----------------------------------------------------------------------------------------------------------|
| `VeranstaltungsStatusE` | `IN_PLANUNG`, `EINGEREICHT`, `GENEHMIGT`, `NENNSCHLUSS_ABGELAUFEN`, `AKTIV`, `ABGESCHLOSSEN`, `ABGESAGT` |
| `TurnierStatusE` | `GEPLANT`, `AKTIV`, `ABGESCHLOSSEN`, `ABGESAGT` |
| `AusschreibungsStatusE` | `ENTWURF`, `EINGEREICHT`, `GENEHMIGT`, `ABGELEHNT`, `VEROEFFENTLICHT` |
---
## Design-Entscheidungen
- **Veranstaltung ≠ Turnier** (ADR-0003): `DomVeranstaltung` ist der Rahmen, `DomTurnier` die Durchführungseinheit.
- **Gebühren in Cent (Integer)**: Vermeidung von Floating-Point-Fehlern bei Geldbeträgen.
- **Warn-Logik statt Exceptions** (ADR-0007): Alle Validierungen geben `List<String>` zurück.
- **Bestehende `Veranstaltung.kt`** bleibt als Legacy-Scaffold erhalten; `DomVeranstaltung.kt` ist das neue ÖTO-konforme
Modell.
---
## Geänderte Dateien
| Datei | Aktion |
|------------------------------------------|----------------------|
| `events-domain/.../DomVeranstaltung.kt` | NEU |
| `events-domain/.../DomTurnier.kt` | NEU |
| `events-domain/.../DomAusschreibung.kt` | NEU |
| `core-domain/.../Enums.kt` | ERWEITERT (+3 Enums) |
| `docs/01_Architecture/MASTER_ROADMAP.md` | AKTUALISIERT |
@@ -0,0 +1,121 @@
---
date: 2026-03-24
agent: Backend Developer
phase: PHASE 4 MVP-Implementierung
status: ABGESCHLOSSEN
---
# Session Log: REST-Endpunkte Nennungs-Workflow
👷 **[Backend Developer]** | 24. März 2026
## Ziel
Implementierung der REST-Endpunkte für den Nennungs-Workflow (registration-context) gemäß MASTER_ROADMAP Phase 4.
---
## Erledigte Aufgaben
### 1. `entries-service` aktiviert
- `settings.gradle.kts`: `:backend:services:entries:entries-service` aus dem ON-HOLD-Kommentar befreit und aktiv
eingebunden.
### 2. `entries-api` Fachliche DTOs (`NennungDtos.kt`)
Neue Datei: `entries-api/src/commonMain/kotlin/at/mocode/entries/api/NennungDtos.kt`
| DTO | Zweck |
|-------------------------------|-------------------------------------|
| `NennungEinreichenRequest` | POST Neue Nennung einreichen |
| `NennungStatusAendernRequest` | PUT Status ändern |
| `NennungTransferRequest` | POST /transfer Transfer-Operation |
| `NennungSummaryDto` | GET Liste kompakte Ansicht |
| `NennungDetailDto` | GET Detail / POST Response |
| `NennungsTransferDto` | Transfer-Response mit Audit-Trail |
**Dependency ergänzt:** `projects.core.coreDomain` in `entries-api/build.gradle.kts` (für `NennungsStatusE`,
`StartwunschE`, `UuidSerializer`).
### 3. `entries-domain` `NennungsTransferRepository`
Neues Interface: `entries-domain/.../repository/NennungsTransferRepository.kt`
- `findById`, `findByUrsprungsNennungId`, `save`
### 4. `entries-service` Persistence-Schicht
| Datei | Inhalt |
|-------------------------------------|-----------------------------------------------------------------|
| `NennungTable.kt` | Exposed-Tabelle `nennungen` mit allen Feldern + Indizes |
| `NennungsTransferTable.kt` | Exposed-Tabelle `nennungs_transfers` mit Audit-Trail |
| `NennungRepositoryImpl.kt` | Vollständige Implementierung aller `NennungRepository`-Methoden |
| `NennungsTransferRepositoryImpl.kt` | Implementierung aller `NennungsTransferRepository`-Methoden |
### 5. `entries-service` Use Cases (`NennungUseCases.kt`)
`@Service`-Klasse mit folgenden Use Cases:
| Methode | Fachliche Logik |
|-------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| `getNennungById` | Query by ID |
| `getNennungenByTurnier/Bewerb/Abteilung/Reiter` | Gefilterte Listen |
| `nennungEinreichen` | Neue Nennung, Warn-Log bei Nachnennung |
| `statusAendern` | Status-Transition mit Audit-Timestamp |
| `nennungZurueckziehen` | Soft-Delete → Status `ZURUECKGEZOGEN` |
| `nennungTransferieren` | **Atomare Transfer-Operation** (ÖTO-konform): Ursprung → TRANSFERIERT, neue Nennung anlegen, Transfer-Record speichern |
**ÖTO-Konformität:** Warn-Logik statt harter Fehler. TBA hat das letzte Wort.
### 6. `entries-service` REST-Controller (`NennungController.kt`)
Basis-URL: `/api/v1/registrations/nennungen`
| Methode | Endpunkt | Beschreibung |
|----------|--------------------------|------------------------------------------------------------|
| `GET` | `/` | Liste (Filter: turnierId, bewerbId, abteilungId, reiterId) |
| `GET` | `/{nennungsId}` | Detail |
| `POST` | `/` | Neue Nennung einreichen (201) |
| `PUT` | `/{nennungsId}/status` | Status ändern |
| `DELETE` | `/{nennungsId}` | Zurückziehen |
| `POST` | `/{nennungsId}/transfer` | Transfer (201) |
### 7. `entries-service` Konfiguration
| Datei | Inhalt |
|-----------------------------------|---------------------------------------------------------------|
| `EntriesBeansConfiguration.kt` | Spring-Beans für Repository-Implementierungen |
| `EntriesDatabaseConfiguration.kt` | Exposed-Schema-Init (`NennungTable`, `NennungsTransferTable`) |
| `EntriesExceptionHandler.kt` | RFC 9457 Problem Details (404, 400, 409) |
### 8. `entries-service` Build-Dependencies ergänzt
```kotlin
implementation(projects.backend.services.entries.entriesDomain)
implementation(projects.core.coreUtils)
implementation(projects.core.coreDomain)
implementation(libs.exposed.core)
implementation(libs.exposed.jdbc)
implementation(libs.exposed.kotlin.datetime)
```
---
## Architektur-Entscheidungen
- **Warn-Logik:** Nachnennungen und Transfers nach Nennschluss werden geloggt (`log.warn`), aber nicht blockiert gemäß
ADR-7 (Warn-Logik statt harter Fehler).
- **Transfer = atomare Operation:** Keine Storno + Neunennung, sondern: Ursprung → TRANSFERIERT + neue Nennung +
Transfer-Record. Entspricht ÖTO-Regelwerk.
- **Soft-Delete:** Nennungen werden nie physisch gelöscht, sondern auf `ZURUECKGEZOGEN` gesetzt.
- **Repository-Pattern:** Interfaces in `entries-domain`, Implementierungen in `entries-service` (Dependency Inversion).
---
## Nächste Schritte
- **ÖTO/FEI Rulebook Expert:** Voltigieren (CVN) und Fahren (CAN) Abteilungs-Trennungsregeln auswerten (offene Fragen
#3, #4).
- **QA Specialist:** Integrationstests für den Nennungs-Workflow schreiben.
- **Backend Developer:** `competition-context` (Bewerbe, Startlisten, Ergebnisse) PHASE 5.
@@ -0,0 +1,107 @@
---
type: Session Log
date: 2026-03-24
agent: Backend Developer
topic: Persistenz Repository-Interfaces und erste DB-Migrationen
status: ABGESCHLOSSEN
---
# 👷 Session Log: Persistenz Repository-Interfaces & DB-Migrationen
**Datum:** 24. März 2026
**Agent:** 👷 Backend Developer
**Aufgabe:** Repository-Interfaces und erste DB-Migrationen (Flyway) für `actor-context`, `registration-context`.
---
## Erledigte Aufgaben
### 1. Repository-Interfaces (Domain-Layer)
Vier neue Repository-Interfaces als Ports (Hexagonale Architektur) in den `-domain`-Modulen:
| Interface | Modul | Aggregate Root |
|-------------------------|--------------------|------------------|
| `FunktionaerRepository` | `officials-domain` | `DomFunktionaer` |
| `VereinRepository` | `clubs-domain` | `DomVerein` |
| `ReiterRepository` | `persons-domain` | `DomReiter` |
| `NennungRepository` | `entries-domain` | `DomNennung` |
Alle Interfaces folgen dem gleichen Muster:
- `findById`, `findByXxx`, `findAll`, `findAllActive` (paginiert)
- `save` (Upsert-Semantik)
- `delete`, `countXxx`, `existsByXxx`
- `suspend fun` für Coroutine-Kompatibilität
### 2. Exposed-Tabellendefinitionen (Infrastructure-Layer)
Drei neue `Table`-Objekte (Exposed 1.0.0, `org.jetbrains.exposed.v1.core.Table` + `javaUUID`):
| Table | Modul | DB-Tabelle |
|--------------------|----------------------------|----------------|
| `FunktionaerTable` | `officials-infrastructure` | `funktionaere` |
| `VereinTable` | `clubs-infrastructure` | `vereine` |
| `ReiterTable` | `persons-infrastructure` | `reiter` |
Technische Details:
- UUID-PK via `javaUUID("id").autoGenerate()` (konsistent mit `HorseTable`)
- JSON-Spalten (`TEXT`) für `rollen`, `qualifiziert_fuer_sparten`, `lizenziert_fuer_sparten`
- `timestamp()` aus `org.jetbrains.exposed.v1.datetime` für Audit-Felder
- Partial Unique Indexes für nullable Felder (Richternummer, Satznummer, FEI-ID)
### 3. Repository-Implementierungen (Infrastructure-Layer)
Drei neue `Exposed*Repository`-Klassen:
| Implementierung | Modul |
|--------------------------------|----------------------------|
| `ExposedFunktionaerRepository` | `officials-infrastructure` |
| `ExposedVereinRepository` | `clubs-infrastructure` |
| `ExposedReiterRepository` | `persons-infrastructure` |
Technische Details:
- Imports: `org.jetbrains.exposed.v1.core.eq`, `.like`, `.and`, `.or` (Top-Level-Funktionen in Exposed 1.0.0)
- Pagination: `.limit(n).offset(m.toLong())` (Exposed 1.0.0 API)
- JSON-Serialisierung via `kotlinx.serialization.json.Json`
- `kotlin.time.Clock` (nicht `kotlinx.datetime.Clock`) für Timestamp-Kompatibilität mit Exposed
### 4. Flyway-SQL-Migrationen (Service-Layer)
Drei neue V001-Migrationen im Stil der bestehenden `masterdata-service`-Migrationen:
| Migration | Service | Tabelle |
|---------------------------------------|---------------------|----------------|
| `V001__Create_Funktionaere_Table.sql` | `officials-service` | `funktionaere` |
| `V001__Create_Vereine_Table.sql` | `clubs-service` | `vereine` |
| `V001__Create_Reiter_Table.sql` | `persons-service` | `reiter` |
Alle Migrationen enthalten:
- `CREATE TABLE IF NOT EXISTS` mit vollständiger Spaltendefinition
- Partial Unique Indexes für nullable Identifikationsfelder
- Performance-Indizes für häufige Suchabfragen
- `COMMENT ON TABLE/COLUMN` für Dokumentation
---
## Architektur-Entscheidungen
- **Hexagonale Architektur:** Repository-Interfaces im Domain-Layer, Implementierungen im Infrastructure-Layer keine
Abhängigkeit der Domain von Exposed.
- **JSON für Collections:** Rollen und Sparten als JSON-Arrays in TEXT-Spalten (kein Join-Table) pragmatisch für MVP,
erweiterbar.
- **Upsert-Semantik:** `save()` prüft Existenz via `selectAll().where { id eq ... }` und führt Insert oder Update durch.
- **Partial Unique Indexes:** Nullable Felder (Richternummer, Satznummer, FEI-ID) mit `WHERE field IS NOT NULL`
erlaubt mehrere NULL-Werte.
---
## Offene Punkte
- `entries-infrastructure`-Modul existiert noch nicht → `NennungRepository`-Implementierung ausstehend.
- Flyway-Konfiguration in `officials-service`, `clubs-service`, `persons-service` `application.yml` noch nicht
geprüft/ergänzt.
- Spring-DI-Konfiguration (Bean-Registrierung der Repository-Implementierungen) noch ausstehend.
@@ -0,0 +1,76 @@
---
type: Session Log
date: 2026-03-24
agent: Backend Developer
status: ABGESCHLOSSEN
roadmap_phase: PHASE 4 MVP-Implementierung
---
# Session Log: registration-context Domain-Modelle
👷 **[Backend Developer]** | 24. März 2026
## Ziel
Domain-Modelle `DomBewerb`, `DomAbteilung` und `DomStartliste` im `registration-context` implementieren (PHASE 4,
MASTER_ROADMAP).
---
## Ergebnis
### ✅ DomBewerb (neu)
- **Datei:** `backend/services/entries/entries-domain/src/main/kotlin/at/mocode/entries/domain/model/DomBewerb.kt`
- Aggregate Root für den Bewerbs-Workflow im `registration-context`.
- Felder: `turnierId`, `bewerbNummer`, `bezeichnung`, `sparte`, `turnierkategorie`, `pruefungsTyp`, `hoeheCm`,
`teilungsTyp`, `maxStarterProAbteilung`, `istMeisterschaft`, `istNachnennungErlaubt`.
- Domain-Methoden: `getDisplayName()`, `getPflichtTeilungsSchwellenwert()` (§ 39-konform),
`getKannTeilungsSchwellenwert()`, `validateAbteilungsSchwellenwerte()` (Warn-Logik).
### ✅ DomAbteilung (neu)
- **Datei:** `backend/services/entries/entries-domain/src/main/kotlin/at/mocode/entries/domain/model/DomAbteilung.kt`
- Kleinste startbare Einheit innerhalb eines Bewerbs.
- Felder: `bewerbId`, `abteilungsNummer`, `bezeichnung`, `teilungsTyp`, `teilnehmerkreisBeschreibung`, `starterAnzahl`,
`maxStarter`, `startzeit`.
- Domain-Methoden: `getDisplayName()`, `hatFreiePlaetze()`, `validateStarterLimit()` (Warn-Logik für > 80 Starter, § 39
Abs. 2).
### ✅ DomStartliste (neu)
- **Datei:** `backend/services/entries/entries-domain/src/main/kotlin/at/mocode/entries/domain/model/DomStartliste.kt`
- Enthält geordnete Liste von `StartlistenEintrag` (Startnummer → Nennung).
- Workflow: `NICHT_ERSTELLT → ENTWURF → VEROEFFENTLICHT → GESPERRT → ARCHIVIERT`.
- Domain-Methoden: `getStarterAnzahl()`, `getEintragByStartnummer()`, `istBearbeitbar()`, `istSichtbar()`,
`veroeffentlichen()`, `sperren()` (Warn-Logik für ungültige Status-Übergänge).
- `StartlistenEintrag`: Denormalisierte Felder `reiterName`, `pferdeName` für schnelle Anzeige; `istGestrichen`-Flag für
Abmeldungen nach Startlistenerstellung.
### ✅ Neue Enums in core-domain
- **Datei:** `core/core-domain/src/commonMain/kotlin/at/mocode/core/domain/model/Enums.kt`
- `PruefungsTypE`: STIL_SPRINGEN, SPRINGPFERDE, DRESSURPFERDE, VIELSEITIGKEIT, SPRINGEN_UEBRIG, DRESSUR, CAPRILLI,
FAHREN, VOLTIGIEREN, SONSTIGE mit Schwellenwert-Kommentaren gemäß § 39.
- `AbteilungsTeilungsTypE`: KEINE, NACH_LIZENZ, NACH_PLATZ, NACH_PFERDEALTER, STRUKTURELL, NACH_AUSSCHREIBUNG.
- `StartlistenStatusE`: NICHT_ERSTELLT, ENTWURF, VEROEFFENTLICHT, GESPERRT, ARCHIVIERT.
---
## Design-Entscheidungen
| Entscheidung | Begründung |
|----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DomBewerb` im `entries-domain`-Modul | Bewerbe sind direkt mit Nennungen verknüpft; `entries-domain` ist das bestehende KMP-Modul für den `registration-context`. |
| Schwellenwerte als Domain-Methoden, nicht hard-coded | Konsistent mit Implementierungs-Hinweisen in `Abteilungs-Trennungs-Schwellenwerte.md` (§ 4.2). Konfigurierbare Parameter für spätere Persistenz vorbereitet. |
| `StartlistenEintrag` als Value Object in `DomStartliste` | Einträge haben keine eigene Identität außerhalb der Startliste; Denormalisierung von `reiterName`/`pferdeName` für performante Anzeige ohne Join. |
| Warn-Logik statt harter Fehler | Konsistent mit ADR-0016 und Override-Event-Prinzip: alle `validate*()`-Methoden geben Warnungen zurück, kein Exception-Throwing. |
| `istMeisterschaft`-Flag auf `DomBewerb` | Meisterschaftsbewerbe sind von der Pflicht-Teilung ausgenommen (§ 39 Abs. 4) Flag ermöglicht direkte Prüfung in `getPflichtTeilungsSchwellenwert()`. |
---
## Nächste Schritte (PHASE 4)
- [ ] `event-management-context`: `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementieren.
- [ ] Persistenz: Repository-Interfaces und DB-Migrationen (Flyway/Liquibase).
- [ ] API: REST-Endpunkte für Nennungs-Workflow (Kern-Use-Cases).
@@ -0,0 +1,82 @@
---
type: Session Log
date: 2026-03-24
agent: ÖTO/FEI Rulebook Expert
status: ABGESCHLOSSEN
---
# Session Log: Warn-Logik-Spezifikation `competition-context`
🧹 **[Curator]** | 24. März 2026
---
## Aufgabe
Spezifikation der `competition-context` Warn-Logik für Abteilungs-Schwellenwerte
(MASTER_ROADMAP Phase 4, ÖTO/FEI Rulebook Expert).
## Ergebnis
### Neues Dokument erstellt
**`docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md`**
Verbindliche Implementierungs-Spezifikation für die Warn-Logik im `competition-context`.
### Inhalt der Spezifikation
**6 Warn-Codes definiert:**
| Warn-Code | Typ |
|--------------------------------------------|----------------------------------------------|
| `WARN_PFLICHT_TEILUNG_UEBERSCHRITTEN` | Starter-Schwellenwert überschritten |
| `WARN_KANN_TEILUNG_EMPFOHLEN` | Kann-Teilung empfohlen (Dressur) |
| `WARN_ABTEILUNG_ZU_GROSS` | Abteilung nach Teilung > 80 Starter |
| `WARN_ABTEILUNG_MAX_UEBERSCHRITTEN` | Konfiguriertes Starter-Limit überschritten |
| `WARN_STRUKTURELLE_TEILUNG_FEHLT` | Strukturelle Pflicht-Teilung nicht vorhanden |
| `WARN_STRUKTURELLE_TEILUNG_UNVOLLSTAENDIG` | Strukturelle Teilung unvollständig |
**3 Warn-Typen mit vollständigem Entscheidungsbaum:**
1. Starter-Schwellenwerte (`DomBewerb.validateAbteilungsSchwellenwerte`)
2. Abteilungs-Größe nach Teilung (`DomAbteilung.validateStarterLimit`)
3. Strukturelle Pflicht-Teilungen (`DomBewerb.validateStrukturellesTeilung`) NEU
**Strukturelle Prüfungen abgedeckt:**
- CSN Stil-/Idealzeitspringen ≤ 95 cm: ohne Lizenz vs. R1 (§ 200 Abs. 5.3)
- Springpferdeprüfung 95110 cm / Dressurpferdeprüfung Kl. A: Pferdealter 4 vs. 56 (§ 200 Abs. 6 / § 100 Abs. 5)
- CSN-C-NEU ≤ 95 cm: ohne Lizenz vs. mit Lizenz (§ 231)
- CSN-C-NEU ≥ 100 cm: R1 vs. R2+ (§ 231)
- CCN-C-NEU Gelände ≤ 80 cm: 3 Abteilungen (§ 300)
- CCN-C-NEU Gelände ≥ 90 cm: 2 Abteilungen (§ 300)
- CCN Welcome / 80 cm: R2+ eigene Abteilung (§ 301 Abs. 1.4)
- Caprilli: lizenzfrei vs. RD1+ (§ 803 Abs. 2)
- Fahren/Fahrertreffen: F1+ eigene Abteilung (§ 850 Abs. 9)
**Implementierungs-Vorgaben:**
- Typisiertes Value Object `AbteilungsWarnung` (statt roher Strings)
- `AbteilungsWarnungCodeE` Enum
- `AbteilungsWarnungOverrideEvent` mit Pflicht-Begründungsfeld
- `AbteilungsSchwellenwertConfig` (konfigurierbare Schwellenwerte, nicht hard-coded)
- Aufruf-Zeitpunkte (Trigger) definiert
### Aktualisierte Dokumente
- `docs/01_Architecture/MASTER_ROADMAP.md` Task als `[x]` markiert, Referenz ergänzt, Referenz-Tabelle aktualisiert
## Offene Fragen (weiterhin offen)
| # | Frage |
|---|--------------------------------------------------------------------|
| 1 | Gelten § 39-Schwellenwerte auch für Reitertreffen? |
| 2 | Pflicht-Teilung bei kombinierten Turnieren (§ 4)? |
| 3 | Voltigieren (CVN): Eigene Abteilungs-Trennungsregeln? |
| 4 | Fahren (CAN): Eigene Starter-Schwellenwerte? |
| 5 | Abbildung „Geldpreise > Doppeltes Gebührenordnung" im Datenmodell? |
---
*Session: 2026-03-24 | Agent: ÖTO/FEI Rulebook Expert + Curator (Junie)*
@@ -0,0 +1,42 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-25
---
# Journal: Playbook Audit & Fixes
## Session-Ziel
Vollständige Analyse aller Agent-Playbooks auf Konsistenz, Korrektheit und Vollständigkeit.
## Befunde
### 🔴 Kritisch (behoben)
- **`Gemini.md` & `Junie.md`:** Falsche Pfade in der Startpunkt-Sektion.
- `docs/03_Agents/` → korrigiert zu `docs/04_Agents/`
- `docs/04_Backend/` → korrigiert zu `docs/05_Backend/`
- `docs/05_Frontend/` → korrigiert zu `docs/06_Frontend/`
- `docs/06_Infrastructure/` → korrigiert zu `docs/07_Infrastructure/`
### ⚠️ Mittel (behoben)
- **`Curator.md`:** Fehlender Frontmatter-Header — ergänzt (`type`, `status`, `owner`, `last_update`).
- **`04_Agents/README.md`:** Nur 3 von 11 Playbooks aufgelistet — vollständige Tabelle ergänzt.
### ️ Nachträglich behoben (Session 2)
- **Alle Playbooks:** `## Abschluss (Pflicht)`-Abschnitt mit Curator-Hinweis ergänzt.
- **`UIUXDesigner.md`:** `owner: Curator``owner: Lead Architect` korrigiert.
- **`Architect.md`:** Expliziter `Don't`-Block zur Rollenabgrenzung ergänzt.
## Geänderte Dateien
- `docs/04_Agents/Playbooks/Gemini.md`
- `docs/04_Agents/Playbooks/Junie.md`
- `docs/04_Agents/Playbooks/Curator.md`
- `docs/04_Agents/README.md`
- `docs/04_Agents/Playbooks/Architect.md`
- `docs/04_Agents/Playbooks/BackendDeveloper.md`
- `docs/04_Agents/Playbooks/DevOpsEngineer.md`
- `docs/04_Agents/Playbooks/DomainExpert.md`
- `docs/04_Agents/Playbooks/FrontendExpert.md`
- `docs/04_Agents/Playbooks/QASpecialist.md`
- `docs/04_Agents/Playbooks/RulebookExpert.md`
- `docs/04_Agents/Playbooks/UIUXDesigner.md`
@@ -0,0 +1,91 @@
---
type: Session Log
date: 2026-03-25
agent: ÖTO/FEI Rulebook Expert
topic: Fahren (CAN) Starter-Schwellenwerte jenseits der Reitertreffen-Regel klären
status: ABGESCHLOSSEN (teilweise CAN-Reglement fehlt)
roadmap_ref: PHASE 4 offene Frage #4
---
# Session Log: CAN Starter-Schwellenwerte
📜 **[ÖTO/FEI Rulebook Expert]** | 25. März 2026
---
## 1. Aufgabe
Klärung der Frage, ob es für Fahren (CAN) eigene Starter-Schwellenwerte jenseits der
Reitertreffen-Regel (§ 850 Abs. 9) gibt (offene Frage #4 aus `Abteilungs-Trennungs-Schwellenwerte.md`).
---
## 2. Analysierte Quellen
| Quelle | Ergebnis |
|----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| ÖTO 2026, B-Teil Abschnitt B VII (Fahrprüfungen) | Enthält **keine eigenen Abteilungsregeln** vollständiger Verweis auf OEPS-Reglement „Turnierordnung für Gespanne" |
| ÖTO 2026, A-Teil § 39 Abs. 1 | Gilt **nicht** für Fahren B VII ist dort nicht aufgeführt (nur B I, B II, B III) |
| ÖTO 2026, A-Teil § 39 Abs. 2 | Gilt **allgemein** für alle Sparten inkl. CAN: > 80 Starter in einer Abteilung → Pflicht-Teilung |
| ÖTO 2026, B-Teil § 850 Abs. 9 | Fahrer mit Lizenz **höher als F1** werden bei Fahrertreffen in einer **separaten Abteilung** gewertet gilt nur für Treffen, nicht für reguläre Turniere |
| OEPS-Reglement „Turnierordnung für Gespanne" (CAN) | **Nicht im Projekt vorhanden** muss beim OEPS beschafft werden |
---
## 3. Kernergebnisse
### 3.1 Was gesichert gilt (aus ÖTO A-Teil und § 850)
- **§ 39 Abs. 1 gilt NICHT für CAN:** Die Lizenz-Pflicht-Teilung ist explizit nur für
B I (Dressur), B II (Springen) und B III (Vielseitigkeit) vorgeschrieben.
Fahren (B VII) ist dort **nicht** genannt.
- **§ 39 Abs. 2 gilt als allgemeiner Fallback:** Bei mehr als 80 Startern in einer Abteilung
nach Teilung muss diese erneut geteilt werden. Dies gilt für alle Sparten.
- **Fahrertreffen-Lizenzregel (§ 850 Abs. 9):** Fahrer mit Lizenz höher als F1 werden in
einer separaten Abteilung gewertet. Diese Regel gilt **ausschließlich für Treffen**,
nicht für reguläre CAN-Turniere.
- **Strukturelle Parallele zu CVN:** Abschnitt B VII verhält sich identisch zu Abschnitt B IV
(Voltigieren) beide verweisen vollständig auf externe OEPS-Reglements.
### 3.2 Was unbekannt bleibt (nur im CAN-Reglement)
- Abteilungs-Trennungsregeln für reguläre CAN-Turniere (Dressurfahren, Hindernisfahren, Geländefahren)
- Schwellenwerte für Starter pro Disziplin
- Lizenz-Abteilungstrennung (F1/F2/F3) bei regulären Turnieren
---
## 4. Implementierungs-Empfehlung
| Maßnahme | Begründung |
|--------------------------------------------------------------------------------|-------------------------------------------------------------|
| § 39 Abs. 2-Fallback (> 80 Starter → WARN) für CAN implementieren | Einzige gesicherte Rechtsgrundlage aus ÖTO |
| **Fahrertreffen:** F1+ in separater Abteilung als strukturelle Pflicht-Teilung | Gesicherte Rechtsgrundlage: § 850 Abs. 9 |
| **Keine** weiteren strukturellen Lizenz-Pflicht-Teilungen für CAN-Turniere | Keine Rechtsgrundlage im ÖTO A-Teil § 39 Abs. 1 |
| CAN-spezifische Warn-Logik für reguläre Turniere als `TODO` markieren | CAN-Reglement fehlt Implementierung nach Beschaffung |
| OEPS-Reglement „Turnierordnung für Gespanne" beim OEPS beschaffen | Für vollständige spartenspezifische Auswertung erforderlich |
---
## 5. Geänderte Dokumente
| Dokument | Änderung |
|-------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` | Abschnitt 2.5 (CAN) vollständig überarbeitet; Matrix um CAN-Zeilen ergänzt; offene Frage #4 auf ✅ Teilweise geklärt gesetzt; Quellen-Header und Footer ergänzt |
| `docs/01_Architecture/MASTER_ROADMAP.md` | Aufgabe „Fahren (CAN)" auf [x] gesetzt mit Kurzbeschreibung des Ergebnisses |
---
## 6. Nächste Schritte
- [ ] **OEPS-Reglement „Turnierordnung für Gespanne" (CAN) beschaffen** → beim OEPS anfordern oder herunterladen
- [ ] Nach Beschaffung: CAN-spezifische Abteilungsregeln auswerten und Abschnitt 2.5 vervollständigen
- [ ] **OEPS-Reglement „Voltigieren" (CVN) beschaffen** → offene Frage #3 vollständig klären
- [ ] **Offene Fragen #1 und #2** (Reitertreffen-Schwellenwerte, kombinierte Turniere) bei Gelegenheit klären
---
*Autor: ÖTO/FEI Rulebook Expert (Junie) | 2026-03-25*
@@ -0,0 +1,85 @@
---
type: Session Log
date: 2026-03-25
agent: ÖTO/FEI Rulebook Expert
topic: Voltigieren (CVN) Abteilungs-Trennungsregeln aus B-Teil § 400 ff. auswerten
status: ABGESCHLOSSEN (teilweise CVN-Reglement fehlt)
roadmap_ref: PHASE 4 offene Frage #3
---
# Session Log: CVN Abteilungs-Trennungsregeln
📜 **[ÖTO/FEI Rulebook Expert]** | 25. März 2026
---
## 1. Aufgabe
Auswertung der Abteilungs-Trennungsregeln für Voltigieren (CVN) aus dem ÖTO B-Teil § 400 ff.
(offene Frage #3 aus `Abteilungs-Trennungs-Schwellenwerte.md`).
---
## 2. Analysierte Quellen
| Quelle | Ergebnis |
|---------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| ÖTO 2026, B-Teil Abschnitt B IV (§ 400 ff.) | Enthält **keine eigenen Abteilungsregeln** vollständiger Verweis auf OEPS-Reglement „Voltigieren" (CVN) |
| ÖTO 2026, A-Teil § 39 Abs. 1 | Gilt **nicht** für Voltigieren B IV ist dort nicht aufgeführt (nur B I, B II, B III) |
| ÖTO 2026, A-Teil § 39 Abs. 2 | Gilt **allgemein** für alle Sparten inkl. CVN: > 80 Starter in einer Abteilung → Pflicht-Teilung |
| ÖTO 2026, B-Teil § 850 Abs. 9 | Keine analoge Lizenz-Abteilungsregel für Voltigierertreffen (nur für Fahren: F1+ in eigener Abt.) |
| OEPS-Reglement „Voltigieren" (CVN) | **Nicht im Projekt vorhanden** muss beim OEPS beschafft werden |
---
## 3. Kernergebnisse
### 3.1 Was gesichert gilt (aus ÖTO A-Teil)
- **§ 39 Abs. 1 gilt NICHT für CVN:** Die Lizenz-Pflicht-Teilung (R1 in eigener Abteilung) ist
explizit nur für B I (Dressur), B II (Springen) und B III (Vielseitigkeit) vorgeschrieben.
Voltigieren (B IV) ist dort **nicht** genannt.
- **§ 39 Abs. 2 gilt als allgemeiner Fallback:** Bei mehr als 80 Startern in einer Abteilung
nach Teilung muss diese erneut geteilt werden. Dies gilt für alle Sparten.
- **Keine Voltigierertreffen-Lizenzregel:** § 850 Abs. 9 enthält eine Lizenz-Abteilungsregel
nur für Fahren (F1+ in separater Abteilung). Für Voltigierertreffen gibt es keine analoge Regel.
### 3.2 Was unbekannt bleibt (nur im CVN-Reglement)
- Abteilungs-Trennungsregeln nach Disziplin (Gruppe / Einzel / Pas de Deux)
- Schwellenwerte für Starter pro Disziplin
- Lizenz-Abteilungstrennung für Voltigierer
---
## 4. Implementierungs-Empfehlung
| Maßnahme | Begründung |
|-------------------------------------------------------------------|-------------------------------------------------------------|
| § 39 Abs. 2-Fallback (> 80 Starter → WARN) für CVN implementieren | Einzige gesicherte Rechtsgrundlage aus ÖTO |
| **Keine** strukturelle Lizenz-Pflicht-Teilung für CVN | Keine Rechtsgrundlage im ÖTO A-Teil § 39 Abs. 1 |
| CVN-spezifische Warn-Logik als `TODO` markieren | CVN-Reglement fehlt Implementierung nach Beschaffung |
| OEPS-Reglement „Voltigieren" beim OEPS beschaffen | Für vollständige spartenspezifische Auswertung erforderlich |
---
## 5. Geänderte Dokumente
| Dokument | Änderung |
|-------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` | Abschnitt 2.6 (CVN) neu hinzugefügt; Matrix um CVN-Zeilen ergänzt; offene Frage #3 auf ✅ Teilweise geklärt gesetzt |
| `docs/01_Architecture/MASTER_ROADMAP.md` | Aufgabe „Voltigieren (CVN)" auf [x] gesetzt |
---
## 6. Nächste Schritte
- [ ] **OEPS-Reglement „Voltigieren" (CVN) beschaffen** → beim OEPS anfordern oder herunterladen
- [ ] Nach Beschaffung: CVN-spezifische Abteilungsregeln auswerten und Abschnitt 2.6 vervollständigen
- [ ] **Offene Frage #4 (Fahren/CAN):** Starter-Schwellenwerte jenseits der Reitertreffen-Regel klären
---
*Autor: ÖTO/FEI Rulebook Expert (Junie) | 2026-03-25*
@@ -0,0 +1,78 @@
---
date: 2026-03-25
type: Session Log
agents: [ Lead Architect, Frontend Expert, Curator ]
status: ABGESCHLOSSEN
---
# Session Log: Frontend-Architektur-Bereinigung & ZNS-Import Phase 3
## Zusammenfassung
Diese Session umfasste zwei Hauptthemen:
1. Vollständige Implementierung von **Phase 3 (ZNS-Import Frontend)**
2. Analyse und Bereinigung von **5 Frontend-Architektur-Problemen**
---
## Phase 3: ZNS-Import Frontend (✅ Abgeschlossen)
### Implementierte Komponenten
| Datei | Beschreibung |
|-----------------------------|-----------------------------------------------------------------|
| `AppScreen.kt` | `StammdatenImport`-Route + `fromRoute`-Mapping |
| `ZnsImportViewModel.kt` | Ktor Multipart-Upload, Polling (2s), Auth-Token-Injection |
| `StammdatenImportScreen.kt` | File-Picker (JFileChooser, nur .zip), ProgressBar, Fehler-Liste |
| `DesktopMainLayout.kt` | Nav-Rail-Eintrag "Stammdaten-Import" |
| `DesktopModule.kt` | ZnsImportViewModel via Koin registriert |
---
## Architektur-Bereinigung (✅ Abgeschlossen)
### Problem 1 NetworkModule.kt (🔴 Hoch)
- **Was:** Doppelter `HttpSend`-Interceptor + ~90 Zeilen auskommentierter Debug-Code
- **Fix:** Bereinigt auf 83 Zeilen, ein sauberer Interceptor
### Problem 2 meldestelle-portal (🟡 Mittel)
- **Was:** Toter Prototyp (JVM+JS+WASM) ohne Package, ohne DI, mit falschem Fenstertitel
- **Fix:** Verzeichnis gelöscht, `settings.gradle.kts` bereinigt
- **Hinweis:** Web-Portal ist in MASTER_ROADMAP als zukünftige Phase vorgesehen wird neu & sauber aufgebaut
### Problem 3 AppScreen.fromRoute (🟡 Mittel)
- **Was:** Fehlende Mappings für parametrisierte Routen (VeranstaltungDetail, TurnierDetail, TurnierNeu)
- **Fix:** Regex-Parsing ergänzt
### Problem 4 NavigationPort Interface (🟢 Niedrig)
- **Was:** `navigateToScreen` und `currentScreen` fehlten im Interface
- **Fix:** Interface erweitert, `DesktopNavigationPort` implementiert beide Methoden
### Problem 5 ZnsImportViewModel Auslagerung (🟢 Niedrig)
- **Was:** ViewModel mit Business-Logik in der Shell statt im Feature-Modul
- **Fix:** Neues Feature-Modul `frontend/features/zns-import-feature` erstellt
---
## Build-Fehler behoben
| Fehler | Fix |
|---------------------------------------------------|----------------------------------------------------|
| `:frontend:shells:meldestelle-portal` not found | `architecture-tests/build.gradle.kts` aktualisiert |
| `libs.ktor.client.content.negotiation` unresolved | → `libs.ktor.client.contentNegotiation` |
| `libs.ktor.serialization.kotlinx.json` unresolved | → `libs.ktor.client.serialization.kotlinx.json` |
| `libs.androidx.lifecycle.viewmodel` unresolved | → `libs.androidx.lifecycle.viewmodelCompose` |
---
## Offene Punkte (nächste Session)
- [ ] Phase 4: QA & Testing des ZNS-Imports (🧐 QA Specialist)
- [ ] `competition-context` Backend (👷 Backend Developer)
- [ ] `event-management-context` Backend (👷 Backend Developer)
@@ -0,0 +1,77 @@
# Session Log: Frontend-Architektur-Refactor
**Datum:** 26.03.2026
**Agent:** 🏗️ Lead Architect
**Dauer:** ~1 Session
**Trigger:** Inkonsistente Schichttrennung — fachliche Screens lagen im Shell statt in Features
---
## Problem
Die Desktop-App hatte alle Screen-Composables direkt im Shell-Modul (`meldestelle-desktop/screens/`).
Das verletzt das Shell-Feature-Core-Pattern:
- Shell enthielt Fachlogik (Veranstalter, Veranstaltung, Turnier, ZNS)
- `zns-import-feature` war gespalten: ViewModel im Feature, Screen im Shell
- `SharedUiModels` (Enums, Badges) lagen im Shell statt in `core/design-system`
---
## Durchgeführte Änderungen
### Neue Feature-Module
| Modul | Inhalt |
|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|
| `frontend/features/veranstalter-feature` | VeranstalterAuswahlScreen, VeranstalterDetailScreen, VeranstalterNeuScreen |
| `frontend/features/veranstaltung-feature` | AdminUebersichtScreen, VeranstaltungenScreen, VeranstaltungDetailScreen, VeranstaltungNeuScreen, VeranstaltungUebersichtScreen |
| `frontend/features/turnier-feature` | TurnierDetailScreen, TurnierNeuScreen, alle 8 Turnier-Tabs, AktorScreens |
### Verschobene Dateien
| Von | Nach |
|----------------------------------------------------|----------------------------------------------------|
| `shells/.../screens/zns/StammdatenImportScreen.kt` | `features/zns-import-feature/.../presentation/` |
| `shells/.../screens/shared/SharedUiModels.kt` | `core/design-system/.../models/` |
| `shells/.../screens/shared/PlaceholderContent.kt` | `core/design-system/.../models/` |
| `shells/.../screens/veranstalter/*.kt` | `features/veranstalter-feature/.../presentation/` |
| `shells/.../screens/veranstaltung/*.kt` | `features/veranstaltung-feature/.../presentation/` |
| `shells/.../screens/turnier/*.kt` | `features/turnier-feature/.../presentation/` |
| `shells/.../screens/aktor/AktorScreens.kt` | `features/turnier-feature/.../presentation/` |
### Konfiguration
- `settings.gradle.kts`: 3 neue Feature-Module eingetragen
- `shells/meldestelle-desktop/build.gradle.kts`: 3 neue Feature-Abhängigkeiten
- `shells/.../DesktopMainLayout.kt`: Imports auf neue Feature-Packages umgestellt
- `shells/.../ScreenPreviews.kt`: Imports auf neue Feature-Packages umgestellt
### Shell nach Refactor
Der Shell enthält jetzt nur noch:
- `main.kt` — Koin-Init, Window
- `DesktopApp.kt` — Root-Composable, Login-Gate
- `di/DesktopModule.kt` — Shell-DI
- `navigation/DesktopNavigationPort.kt` — Navigation-Port
- `screens/layout/DesktopMainLayout.kt` — Layout + Navigation
- `screens/preview/ScreenPreviews.kt` — IDE-Previews
### Neue Dokumentation
- `docs/06_Frontend/ARCHITECTURE_RULES.md` — verbindliche Architektur-Richtlinien mit Checkliste und Anti-Patterns
---
## Offene Punkte
- Gradle-Sync erforderlich, damit Typesafe-Accessors für neue Module generiert werden
- `ArchitectureTest` (falls vorhanden) sollte die neuen Schichtgrenzen prüfen
---
## Lessons Learned
Architektur-Regeln müssen **schriftlich und verbindlich** festgehalten werden, bevor Code geschrieben wird.
Die `ARCHITECTURE_RULES.md` ist ab sofort Pflichtlektüre für jeden Agenten vor dem ersten Commit.
@@ -0,0 +1,114 @@
---
type: Journal
status: ACTIVE
owner: Frontend Expert + UI/UX Designer
last_update: 2026-03-26
---
# Session Log: Desktop-App Figma-Konformität (Vision_03)
🎨 **[Frontend Expert]** / 🖌️ **[UI/UX Designer]** / 🧹 **[Curator]** | 26. März 2026
## Kontext
Ziel: Desktop-App an Figma Vision_03 (22 Screenshots) angleichen.
Styling hat keine Priorität — Struktur, Layout und Inhalte stehen im Vordergrund.
---
## Analyse: Figma Vision_03 (22 Screenshots)
| Screenshot | Screen / Tab | Status |
|----------------|--------------------------------|---------------------|
| 01, 04, 05 | TurnierDetail > NENNUNGEN | Struktur vorhanden |
| 02 | TurnierDetail > ERGEBNISLISTEN | Struktur vorhanden |
| 03 | TurnierDetail > STARTLISTEN | Struktur vorhanden |
| 06 | TurnierDetail > ABRECHNUNG | ✅ Neu implementiert |
| 07, 08 | TurnierDetail > ARTIKEL | ✅ Neu implementiert |
| 09, 10, 11, 12 | TurnierDetail > BEWERBE | Struktur vorhanden |
| 13, 14 | TurnierDetail > ORGANISATION | ✅ Neu implementiert |
| 15, 16 | TurnierDetail > STAMMDATEN | ✅ Neu implementiert |
| 17 | VeranstaltungUebersichtScreen | ✅ Überarbeitet |
| 18, 19 | VeranstalterDetailScreen | ✅ Neu implementiert |
| 20, 22 | VeranstalterAuswahlScreen | ✅ Neu implementiert |
| 21 | Neuer Veranstalter (Formular) | ⬜ TODO |
---
## Erledigte Änderungen
### 1. ✅ SharedUiModels.kt (NEU)
- Gemeinsame Enums: `LoginStatus`, `VeranstaltungStatus`
- Gemeinsame Composable: `LoginStatusBadge`
- Eliminiert Duplikate aus 3 Dateien
### 2. ✅ VeranstalterAuswahlScreen.kt (ÜBERARBEITET)
- OEPS-Nummer, Ansprechpartner, E-Mail, Login-Status-Badge
- "+ Neuer Veranstalter"-Button
- Hinweis-Box (blau)
- Abbrechen / "Weiter zum Veranstalter"-Buttons unten
### 3. ✅ VeranstalterDetailScreen.kt (ÜBERARBEITET)
- Avatar-Circle (Initialen)
- OEPS-Nummer, Kontaktdetails-Grid (Ansprechpartner, E-Mail, Telefon, Adresse, Login-Status, Mitglied-seit)
- "Profil bearbeiten"-Button
- Suchfeld + Status-Filter-Chips (Alle/Vorbereitung/Live/Abgeschlossen)
- Veranstaltungs-Liste mit Statistiken (Nennungen, Bewerbe, Letzte Aktivität)
### 4. ✅ VeranstaltungUebersichtScreen.kt (ÜBERARBEITET)
- "VERANSTALTUNG - ÜBERSICHT"-Tab-Header
- Turnier-Nummer als echte ZNS-Nummer (26128, 26129, ...)
- Buttons: Öffnen / Import / Export / USB
### 5. ✅ TurnierStammdatenTab.kt (NEU)
- Turnier-Konfiguration: Nr., Typ (OTO/FEI), ZNS-Import via Internet/USB, Sprache
- Sparten-Checkboxen (Dressur, Springen), Klassen (C/B/A), Kategorien, Datum
- Turnier-Beschreibung: Titel, Sub-Titel
- Sponsoren-Sektion
### 6. ✅ TurnierOrganisationTab.kt (NEU)
- Funktionäre & Offizielle: Turnierleiter, Turnierbeauftragter, Technischer Delegierter, Parcourschef
- Support-Team: Tierarzt, Schmied, Steward
- Richterkollegium: dynamische Liste (Name, Qualifikation-Dropdown, Funktion-Dropdown, Löschen)
- Austragungsplätze: dynamische Liste (Sparte, Größe, Bezeichnung, Löschen)
### 7. ✅ TurnierArtikelTab.kt (NEU)
- Nennungs- und Startgebühren: Nenngebühr, Startgebühr, Sporteuro, Nachnennungsgebühr, Nennungstausch
- Stallungen & Boxen: Box/Tag, Einstreu, Paddock
- Zusatzgebühren: dynamische Liste (Bezeichnung, Betrag, Pflicht-Checkbox)
- Hinweis-Box zur Preisliste
### 8. ✅ TurnierAbrechnungTab.kt (NEU)
- Sub-Tabs: BUCHUNGEN | OFFENE POSTEN | RECHNUNG
- Rechte Sidebar: AUSWAHL | VERKAUF | BUCHUNGEN | ADRESSEN
- Buchungstabelle: Buchungstext, Soll, Haben, Saldo (rot bei offen), Buchen/Rechnung-Checkboxen
- Sidebar: Reiter/Pferd-Suche, Buchen-Betrag, Direkt-Drucken, Zahlungsart (BAR/Scheck/Bankomat/Kreditkarte)
---
## Offene Punkte (TODO)
| Prio | Thema | Aufwand |
|-------|------------------------------------------------------|---------|
| 🟡 P1 | "Neuer Veranstalter"-Formular (Screenshot 21) | Klein |
| 🟡 P1 | BEWERBE-Tab: echte Datentabelle + Bewerb-Formular | Mittel |
| 🟡 P1 | NENNUNGEN-Tab: Pferd+Reiter-Suche + Bewerbsübersicht | Mittel |
| 🟡 P2 | STARTLISTEN-Tab: Bewerbs-Tabs + Sortierung/Zeit | Mittel |
| 🟡 P2 | ERGEBNISLISTEN-Tab: Bewerbs-Tabs + Platzierung | Mittel |
| 🟢 P3 | Styling: Farben, Fonts, Abstände gemäß Figma | Klein |
---
## Referenzen
- Figma Screenshots: `docs/06_Frontend/FIGMA/Vision_03/Screenshots/`
- Quellcode: `frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/screens/`
- Routing-Diagramm: `docs/06_Frontend/Navigation_Routing_Diagramm.md`
@@ -0,0 +1,54 @@
# Session Log Figma-Konformität Teil 2
**Datum:** 26.03.2026
**Agent:** 🎨 Frontend Expert + 🏗️ Lead Architect (Junie)
**Dauer:** ~1h
---
## Ziel
Offene Punkte aus Session "Figma-Konformität Teil 1" abarbeiten:
- "Neuer Veranstalter"-Formular (Screenshot 21)
- BEWERBE-Tab: echte Datentabelle + alle 4 Detail-Panel Sub-Tabs
- NENNUNGEN-Tab: Pferd+Reiter-Suche + Nennungs-Tabelle + Verkauf/Buchungen
- STARTLISTEN-Tab: Bewerbs-Tabs + Sortierung & Zeit-Panel
- ERGEBNISLISTEN-Tab: Bewerbs-Tabs + Platzierung & Geldpreis-Panel
---
## Umgesetzte Änderungen
### Neue Dateien
| Datei | Inhalt |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| `VeranstalterNeuScreen.kt` | Formular gemäß Screenshot 21: Info-Banner, Vereinsdaten, Kontaktdaten, Adresse, Footer-Buttons mit Validierung |
| `TurnierBewerbeTab.kt` | Vollständige BEWERBE-Implementierung: Datentabelle (12 Spalten), 4 Sub-Tabs (Bewerb/Bewertung/Geldpreise/Ort/Zeit) mit echten Feldern |
| `TurnierNennungenTab.kt` | NENNUNGEN: Pferd+Reiter-Suche, Nennungs-Tabelle mit Status-Badges, Verkauf/Buchungen, Bewerbsübersicht |
| `TurnierStartlistenTab.kt` | STARTLISTEN: Bewerbs-Tabs, Starter-Tabelle, Sortierungs-Optionen, Zeiten-Panel |
| `TurnierErgebnislistenTab.kt` | ERGEBNISLISTEN: Bewerbs-Tabs, Ergebnis-Tabelle, Platzierung & Geldpreis-Panel |
### Geänderte Dateien
| Datei | Änderung |
|--------------------------------|----------------------------------------------------------------------------|
| `AppScreen.kt` | `VeranstalterNeu` als neuer Screen hinzugefügt |
| `VeranstalterAuswahlScreen.kt` | `onNeuerVeranstalter`-Parameter + Button verdrahtet |
| `DesktopMainLayout.kt` | VeranstalterNeu-Screen registriert + Breadcrumb-Eintrag |
| `TurnierDetailScreen.kt` | Placeholder-Implementierungen entfernt, Verweis auf dedizierte Tab-Dateien |
---
## Qualitätssicherung
- Lint-Check auf alle 9 geänderten/neuen Dateien: **keine Fehler**
---
## Offene Punkte (Phase 4/5)
- Echte Daten aus Backend laden (alle Tabs zeigen noch Placeholder-Daten)
- ZNS-Frontend-Integration (Status-Polling) noch offen
- Web-App-Strategie (ADR-0017) noch nicht entschieden
@@ -0,0 +1,49 @@
# Session Log: Screens-Reorganisation
**Datum:** 2026-03-26
**Agent:** 🎨 Frontend Expert (Junie)
**Scope:** `frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/screens/`
---
## Ziel
Ordnung in das `screens/`-Paket bringen: 24 Flat-Dateien in logische Unterordner aufteilen für bessere Übersicht und
Wartbarkeit.
## Neue Paketstruktur
```
screens/
├── shared/ → SharedUiModels.kt, PlaceholderContent.kt
├── layout/ → DesktopMainLayout.kt
├── veranstalter/ → VeranstalterAuswahlScreen.kt, VeranstalterDetailScreen.kt, VeranstalterNeuScreen.kt
├── veranstaltung/ → AdminUebersichtScreen.kt, VeranstaltungenScreen.kt, VeranstaltungDetailScreen.kt,
│ VeranstaltungNeuScreen.kt, VeranstaltungUebersichtScreen.kt
├── turnier/ → TurnierDetailScreen.kt, TurnierNeuScreen.kt,
│ TurnierStammdatenTab.kt, TurnierOrganisationTab.kt, TurnierBewerbeTab.kt,
│ TurnierArtikelTab.kt, TurnierAbrechnungTab.kt, TurnierNennungenTab.kt,
│ TurnierStartlistenTab.kt, TurnierErgebnislistenTab.kt
├── zns/ → StammdatenImportScreen.kt
├── aktor/ → AktorScreens.kt
└── preview/ → ScreenPreviews.kt
```
## Durchgeführte Änderungen
| Datei | Änderung |
|--------------------------------------------------|--------------------------------------------------------------------------------------|
| Alle 24 Dateien | Package-Deklaration auf neues Sub-Package angepasst |
| `layout/DesktopMainLayout.kt` | Imports für alle Screen-Packages ergänzt |
| `preview/ScreenPreviews.kt` | Imports für alle Screen- und Tab-Composables ergänzt |
| `veranstalter/VeranstalterAuswahlScreen.kt` | Import `shared.LoginStatus`, `shared.LoginStatusBadge` |
| `veranstalter/VeranstalterDetailScreen.kt` | Import `shared.LoginStatus`, `shared.LoginStatusBadge`, `shared.VeranstaltungStatus` |
| `veranstaltung/AdminUebersichtScreen.kt` | Import `shared.VeranstaltungStatus` |
| `veranstaltung/VeranstaltungUebersichtScreen.kt` | Import `shared.VeranstaltungStatus` |
| `DesktopApp.kt` | Import von `screens.DesktopMainLayout``screens.layout.DesktopMainLayout` |
## Verifikation
- Lint-Check auf alle kritischen Dateien: ✅ keine Fehler
- Alte Flat-Dateien gelöscht
- `screens/`-Root enthält nur noch die 8 Unterordner
@@ -0,0 +1,78 @@
---
type: Journal
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-26
---
# Session Log: Struktur-Sprint & Orientierung
🏗️ **[Lead Architect]** / 🧹 **[Curator]** | 26. März 2026
## Kontext
Nach intensiver Phase-4-Arbeit fehlte der Überblick. Ziel dieser Session: Orientierung
wiederherstellen, offene Baustellen priorisieren, zwei konkrete Aufgaben abarbeiten.
---
## Erledigte Aufgaben
### 1. ✅ Routing-Diagramm erstellt
- **Artefakt:** `docs/06_Frontend/Navigation_Routing_Diagramm.md`
- Vollständiges Mermaid-Flowchart aller Screens und Navigationsübergänge
- Screen-Status-Tabellen (✅ implementiert / 🟡 teilweise / ⬜ Placeholder / 🗑️ Relikt)
- **Fund:** 9 Web-App-Relikte im `AppScreen` (siehe offene Entscheidung unten)
### 2. ✅ CI/CD Gradle-Version synchronisiert
- **Datei:** `.gitea/workflows/docker-publish.yaml`
- `GRADLE_VERSION` von `9.3.1` auf `9.4.0` korrigiert (synchron mit `gradle-wrapper.properties`)
- `paths:`-Whitelist war bereits korrekt — Doku-Änderungen triggern die Pipeline nicht
---
## Priorisierte Backlog-Übersicht (Stand 26.03.2026)
| Prio | Thema | Agent | Status |
|-------|--------------------------------------------|--------------------------------|----------------------|
| 🔴 P1 | Desktop-App: Figma-Konformität (Vision_03) | 🎨 Frontend Expert + 🖌️ UI/UX | ⬜ Offen |
| 🔴 P1 | ZNS-Importer Phase 3: Status-Polling | 🎨 Frontend Expert | ⬜ Offen |
| 🟡 P2 | Web-App-Strategie: ADR erforderlich | 🏗️ Lead Architect | ⬜ Entscheidung offen |
| 🟡 P2 | Docker & Datenbanken aufräumen | 🐧 DevOps Engineer | ⬜ Offen |
| 🟢 P3 | CI/CD weiter optimieren | 🐧 DevOps Engineer | ✅ Teilweise erledigt |
---
## Offene Entscheidung: Web-App-Strategie
Im `AppScreen` existieren 9 Screens, die aus der alten Web-App stammen und in der
Desktop-App nicht gerendert werden:
`Landing`, `Home`, `Dashboard`, `Ping`, `Profile`, `OrganizerProfile`,
`AuthCallback`, `Nennung`, `CreateTournament`
**Optionen:**
- **A) Bereinigen:** Relikte aus `AppScreen` entfernen → sauberer Code, weniger Verwirrung
- **B) Behalten:** Für zukünftige Web-App-Phase (Phase 7) aufheben → kein Aufwand jetzt
- **C) Web-App wieder aufbauen:** `meldestelle-portal` reaktivieren → ADR + Planung nötig
**ADR-0017 erforderlich**, sobald Entscheidung getroffen.
---
## Nächste empfohlene Schritte
1. **Web-App-Entscheidung** treffen (Option A/B/C) → ADR-0017
2. **Desktop-App Figma-Delta** aufnehmen: Figma Vision_03 vs. aktueller Compose-Code
3. **ZNS Phase 3** abschließen: Status-Polling im `StammdatenImportScreen`
4. **Docker/DB** Ist-Zustand prüfen
---
## Referenzen
- Routing-Diagramm: `docs/06_Frontend/Navigation_Routing_Diagramm.md`
- CI/CD Pipeline: `.gitea/workflows/docker-publish.yaml`
- MASTER_ROADMAP: `docs/01_Architecture/MASTER_ROADMAP.md`
@@ -0,0 +1,127 @@
---
type: Journal
status: ARCHIVED
owner: Lead Architect
created: 2026-03-27
source: ../temp/Caht-Verlauf_2026-03-27.md
---
# Chat-Verlauf — 27. März 2026
Hinweis: Inhalt aus `docs/temp/Caht-Verlauf_2026-03-27.md` übernommen. Original belassen, bis die vollständige Migration
abgeschlossen ist.
```text
🏗️ [Lead Architect]
Guten Morgen!
Datum: 27. März 2026
In den letzten Tagen haben wir am Frontend gebastelt.
Jetzt habe ich Angst, dass wir unseren Fokus verlieren.
Das Frontend und dessen Entwürfe sollten uns helfen die einzelnen Workflows praxisnah abzugrenzen. Daraus ergibt sich
eine Domäne/Boundet-Context und dieses Wollen wir als eigenständigen Service entwickeln.
Das Ping-Service sollte für uns quasi als Vorlage dienen, also komplett von der echten fachlichen Implementierung
isoliert.
Mittlerweile vermischen wir alles miteinander und das gefällt mir nicht.
Ich will für die ganzen technischen Implementierungen mit dessen Monitorings und Metriken ein eigenes isoliertes
Frontend in dem dann auch das Ping-Service enthalten sein soll.
Aber, dadurch dass wir nicht mehr viel Zeit haben bis zum ersten Einsatz in Neumarkt, will ich die wichtigsten
Grundlegende Funktionen bereits einsatzbereit haben, ohne dabei durch schlampiges husch pfusch eine saubere
Weiterentwicklung verbauen.
Verstehst du meine bedenken?
Ich will mit dir jetzt einen Fahrplan durchdiskutieren, was wir jetzt wie genau entwickeln wollen. Bist du damit
einverstanden?
---
🏗️ [Lead Architect]
### Kurzantwort
Ja, ich verstehe deine Bedenken. Wir trennen konsequent die fachlichen Kontexte vom technischen Monitoring, kapseln das
`Ping-Service` als reine technische Schablone, und liefern bis Neumarkt ein minimal tragfähiges Set an Kernfunktionen
ohne künftige Weiterentwicklung zu verbauen. Unten ist ein konkreter, umsetzbarer Fahrplan mit klaren Leitplanken,
Architektur-Skizze, Modulschnitt und Sprint-Plan.
---
### Leitplanken (nicht verhandelbar)
- Bounded Contexts pro Domäne: kein Mischen von fachlichen Flows mit technischen Utilities.
- Zwei getrennte UIs:
- Fach-UI: produktive Workflows (Meldungen etc.).
- TechOps-UI: Betrieb, Metriken, Logs, `Ping-Service` (Referenz/Schablone), Admin-Tools.
- `Ping-Service` bleibt fachlich neutral: keine Domänen-Referenzen, dient nur als Vorlage für technische Patterns (
Transport, Observability, Resilience, CI/CD).
- Offline-First bleibt Prinzip: Sync-Schicht ist eigenständig, nicht in Screens verwoben.
- „Saubere Weiterentwicklung“ absichern durch: stabile Contracts (`api`-Module), Consumer-Driven-Contracts,
Telemetrie-Standards, Migrationspfade.
---
### Zielbild: Kontext-/Service-Architektur
- Fachliche Kontexte (Beispiele bitte bei Bedarf präzisieren):
- `Meldung-Erfassung` (Form, Validierung, Lokalspeicher, Drafts)
- `Meldung-Verwaltung` (Liste, Details, Statuswechsel)
- `Sync` (Offline-Queue, Konfliktlösung, Retry)
- `Auth/Identity` (Rollen/Permissions, lokale Session)
- Technischer Kontext:
- `TechOps` (Monitoring-UI, Admin-Funktionen)
- `Ping-Service` (Health, Latenz, Transportwege, Resilience-Demo)
- Context Map: klare Schnittstellen zwischen `Fach``Sync``Backend-APIs` sowie `TechOps` isoliert daneben.
---
### Frontend-Aufteilung (KMP/Compose, Beispiele passend zum Repo)
- `frontend/shells/meldestelle-desktop` → Fach-UI Shell
- `frontend/shells/techops-desktop` → NEU: TechOps-UI Shell (enthält `Ping`-Feature, Metriken/Logs)
- `frontend/features/*` → Feature-Module pro Kontext:
- `features/meldung-erfassung`
- `features/meldung-verwaltung`
- `features/auth`
- `features/sync`
- `features/ping-feature` (nur in `techops-desktop` eingebunden)
- `frontend/core/*` → Querschnitt (Design-System, Navigation, State, Telemetrie-SDK, Storage-Abstraktion)
- Strikte Regel: `features/ping-feature` darf kein fachliches Modul importieren. Fach-Features dürfen `ping` nicht
importieren.
---
### Backend-Aufteilung (Kotlin/Spring Boot als Annahme)
- `services/ping` → reine Technik (Health, echo, stream), OpenAPI, OTel, RateLimit, Chaos toggelbar.
- `services/meldung` → Domäne (Erfassung, Verwaltung, Validierung), eigene DB-Schemata.
- `services/auth` → Rollen/Claims, Tokens.
- `platform/observability` → Zentral: OTel Collector, Metrics, Tracing, Log-Pipeline.
---
### MVP für Neumarkt (einsatzbereit, aber erweiterbar)
- Fach-UI
- `Meldung erfassen`: Basisformular, Pflichtfelder, lokale Drafts, Validierung.
- `Meldung verwalten`: Liste, Detailansicht, einfacher Statuswechsel.
- `Sync`: Hintergrund-Sync mit Retry, Konflikt-Hinweis-UI (einfacher Merge/Last-Write-Wins als Start, später
verfeinern).
- `Auth`: Lokale Anmeldung (konfigurierbar), Rollen-Gating auf kritische Aktionen.
- TechOps-UI
- `Ping`-Dashboard: Latenz/Verfügbarkeit, einfache Last- und Retry-Demos.
- `Metrics`: Service-Health, Build-Infos, Versionen, simple Logs-View.
- Nicht-Ziele für MVP: komplexe Berichte, granularer Rechtemanager, komplexe Konfliktlösung.
---
### Roadmap bis Neumarkt (Beispiel: 3 Sprints à 2 Wochen)
```
… (vollständiger Verlauf aus der Quelle)
```
```
@@ -0,0 +1,47 @@
---
type: Journal
status: COMPLETED
owner: DevOps Engineer
last_update: 2026-03-28
---
# Session Log: Korrektur der Spring Boot Konfiguration im Masterdata-Modul
🐧 **[DevOps Engineer]** | 28. März 2026
## Kontext
Der Build schlug im Modul `:backend:services:masterdata:masterdata-infrastructure` beim Task `bootJar` fehl, da keine
`mainClass` konfiguriert war. Da dieses Modul nur Infrastruktur-Code (Exposed Repositories etc.) bereitstellt und keine
eigenständige Spring Boot Application ist, sollte kein `bootJar` (ausführbares JAR) erstellt werden.
## Erledigte Aufgaben
### 1. ✅ build.gradle.kts Anpassung
- Das `spring-boot` Plugin in `masterdata-infrastructure/build.gradle.kts` auf `apply false` gesetzt.
- Dadurch wird der `bootJar` Task (der eine Main-Class zwingend erfordert) für dieses Modul nicht mehr registriert.
- Der Standard `jar` Task bleibt aktiv und stellt die Library für andere Module zur Verfügung.
### 2. ✅ Build-Verifizierung
- Lokaler Build der betroffenen Tasks erfolgreich durchgeführt:
- `./gradlew :backend:services:masterdata:masterdata-infrastructure:jar` (Erfolgreich)
- `./gradlew :backend:services:masterdata:masterdata-service:bootJar` (Erfolgreich, nutzt die Infrastruktur-Library)
- Status: **GRÜN**
## Technische Änderungen
### `backend/services/masterdata/masterdata-infrastructure/build.gradle.kts`
- Geändert: `alias(libs.plugins.spring.boot) apply false`
## Nächste Schritte
- Prüfung anderer Infrastruktur-Module auf ähnliche Fehlkonfigurationen (redundante `bootJar` Tasks).
---
## Referenzen
- `MASTER_ROADMAP.md` (Phase 4: MVP-Implementierung)
@@ -0,0 +1,54 @@
---
type: Journal
status: COMPLETED
owner: DevOps Engineer
last_update: 2026-03-28
---
# Session Log: Metaspace-Optimierung & Build-Fix
🐧 **[DevOps Engineer]** | 28. März 2026
## Kontext
Der Build schlug in mehreren Modulen mit `java.lang.OutOfMemoryError: Metaspace` fehl.
Betroffen waren insbesondere die Kotlin/JS und WASM Kompilationen:
- `:contracts:ping-api:compileKotlinWasmJs`
- `:core:core-domain:compileTestKotlinJs`
- `:core:core-utils:compileKotlinJs`
Die bisherigen Limits (1GB Metaspace) reichten für die komplexe Multiplatform-Struktur nicht mehr aus.
## Erledigte Aufgaben
### 1. ✅ Metaspace & Heap Erhöhung
- Metaspace-Limit für den Kotlin Daemon und den Gradle Daemon von **1GB auf 2GB** erhöht.
- Heap-Speicher für den Kotlin Daemon von **4GB auf 6GB** erhöht.
- Redundante/widersprüchliche JVM-Argumente in `gradle.properties` harmonisiert.
### 2. ✅ Build-Verifizierung
- Lokaler Build der betroffenen Tasks erfolgreich durchgeführt:
`./gradlew :contracts:ping-api:compileKotlinWasmJs :core:core-domain:compileTestKotlinJs :core:core-utils:compileKotlinJs --no-daemon`
- Status: **GRÜN**
## Technische Änderungen
### `gradle.properties`
- `kotlin.daemon.jvmargs`: `-Xmx6g -XX:MaxMetaspaceSize=2g`
- `org.gradle.jvmargs`: `-Xmx6g -Dkotlin.daemon.jvm.options="-Xmx4g" -XX:MaxMetaspaceSize=2g`
## Nächste Schritte
- Überwachung der CI/CD Pipeline auf ähnliche Ressourcen-Engpässe.
- Bei weiteren Problemen: Prüfung, ob `--parallel` in Kombination mit vielen JS-Targets zu hohen Lastspitzen führt.
---
## Referenzen
- `gradle.properties`
- `MASTER_ROADMAP.md` (Phase 4: MVP-Implementierung)
@@ -0,0 +1,50 @@
---
type: Journal
status: COMPLETED
owner: QA Specialist
last_update: 2026-03-28
---
# Session Log: Behebung Flyway Migrations-Fehler (Ping-Service)
🧐 **[QA Specialist]** | 28. März 2026
## Kontext
Der Test-Task `:backend:services:ping:ping-service:test` schlug fehl. Die Ursache war ein `FlywayMigrateException` mit
der Meldung `ERROR: relation "ping" already exists`.
Dies passierte, weil zwei separate Migrations-Dateien versuchten, die gleiche Tabelle `ping` zu erstellen.
## Erledigte Aufgaben
### 1. ✅ Identifizierung des Konflikts
- `V1__init_ping.sql` enthielt bereits die `CREATE TABLE ping` Anweisung.
- `V3__.sql` (vermutlich ein automatisches Relikt oder Fehl-Generat) versuchte die gleiche Tabelle erneut anzulegen.
### 2. ✅ Bereinigung
- Die redundante Datei `backend/services/ping/ping-service/src/main/resources/db/migration/V3__.sql` wurde gelöscht.
- `V1__init_ping.sql` (Schema) und `V2__seed_data.sql` (Testdaten) bleiben als Basis bestehen.
### 3. ✅ Test-Verifizierung
- Ausführung von `./gradlew :backend:services:ping:ping-service:test`
- Ergebnis: **BUILD SUCCESSFUL**
- Alle Tests (Controller, Service, Repository mit Testcontainers) sind grün.
## Technische Details
- Die Warnung bezüglich `sun.misc.Unsafe` (ByteBuddy) in Java 25 wurde zur Kenntnis genommen, blockiert den Build aber
nicht und ist ein bekanntes Upstream-Thema bei Spring Boot / Hibernate auf neuesten JDKs.
## Nächste Schritte
- Überwachung der Schema-Generierung in anderen Services, um ähnliche Duplikate zu vermeiden.
---
## Referenzen
- `MASTER_ROADMAP.md` (Phase 4: MVP-Implementierung)
- `backend/services/ping/ping-service/src/main/resources/db/migration/`
@@ -0,0 +1,59 @@
---
type: Journal
status: COMPLETED
owner: Frontend Expert
last_update: 2026-03-28
---
# Session Log: Modernisierung der Tab-Komponenten (Material 3)
🎨 **[Frontend Expert]** | 28. März 2026
## Kontext
Die generische `TabRow`-Komponente aus Material 3 wurde als `@Deprecated` markiert. Gemäß den aktuellen Guidelines muss
sie durch `PrimaryTabRow` oder `SecondaryTabRow` ersetzt werden, um eine bessere semantische Trennung und konsistente
Visualisierung (Indikatoren, Divider) zu gewährleisten.
## Erledigte Aufgaben
### 1. ✅ Ersetzung in `turnier-feature`
- In `TurnierAbrechnungTab.kt` wurde die `TabRow` für die Sidebar durch `SecondaryTabRow` ersetzt.
- Eine fehlerhafte/veraltete `SecondaryTabRow` im Hauptbereich wurde korrigiert und vereinfacht (Entfernung von
manuellem `tabIndicatorOffset`).
- Redundante und fehlerhafte Hilfsmethoden für `tabIndicatorOffset` wurden entfernt.
### 2. ✅ Ersetzung in `veranstaltung-feature`
- In `VeranstaltungUebersichtScreen.kt` wurde die Header-`TabRow` durch `PrimaryTabRow` ersetzt.
### 3. ✅ Build & Verifizierung
- Test-Kompilation der betroffenen Module erfolgreich:
- `:frontend:features:turnier-feature:compileKotlinJvm`
- `:frontend:features:veranstaltung-feature:compileKotlinJvm`
- Alle unpräfixierten `TabRow`-Aufrufe im Projekt wurden identifiziert und (wo nötig) migriert.
## Technische Änderungen
### `TurnierAbrechnungTab.kt`
- Wechsel zu `SecondaryTabRow` für Sidebar und Hauptbereich.
- Cleanup der Imports und Entfernung von `androidx.compose.material` Relikten.
### `VeranstaltungUebersichtScreen.kt`
- Wechsel zu `PrimaryTabRow` für den Haupt-Header.
## Nächste Schritte
- Prüfung weiterer Screens auf ähnliche Deprecations bei zukünftigen Material 3 Updates.
- Visueller Abgleich mit Figma Vision_03 nach der Migration der restlichen UI-Komponenten.
---
## Referenzen
- Material 3 Design Guidelines (Tabs)
- `MASTER_ROADMAP.md` (Phase 4: MVP-Implementierung)
@@ -0,0 +1,47 @@
# Session Log: Einarbeitung C-NEU Bestimmungen & Turnier-Sparten
**Datum:** 2026-03-30
**Agent:** 📜 [ÖTO/FEI Rulebook Expert] / 🧹 [Curator]
## Zielsetzung
Integration der spezifischen Bestimmungen für C-NEU Turniere (CDN-C NEU / CSN-C NEU) in die Stammdaten-Dokumentation des
`masterdata` Services. Aufbereitung einer detaillierten Übersicht über Turnier-Sparten (Dressur & Springen), deren
Klassen und die korrespondierenden Startberechtigungen (Lizenz-Matrix).
## Durchgeführte Änderungen
### 1. Erweiterung der zentralen Stammdaten (`OETO_STAMMDATEN.md`)
* **Abteilungslogik:** Spezifikation der 3-Abteilungs-Regel für CSN-C NEU bis 95 cm (Abt. 1: ohne Lizenz, Abt. 2: R1,
Abt. 3: R2+).
* **Dressur-Klassen:** Ergänzung der Klasse `LF` (Lizenzfrei) für Reiterpass-/Reiternadel-Aufgaben im C-NEU Bereich.
* **C-NEU Spezifika:** Dokumentation der Einschränkung, dass Lizenzinhaber in RP/Nadel-Bewerben nicht startberechtigt
sind.
### 2. Neue Fachdokumentation (`TURNIER_KLASSEN.md`)
* Erstellung einer detaillierten Übersicht für **Springen (CSN)**:
* Höhenstufen (E0 bis S****).
* C-NEU Besonderheiten (Registrierungspflicht erst ab 95 cm, Startlimits).
* Strukturelle Abteilungs-Vorgaben.
* Erstellung einer detaillierten Übersicht für **Dressur (CDN)**:
* Aufgabenniveau (LF bis S).
* Startberechtigungen pro Klasse.
* **Startberechtigungs-Matrix:** Zentrale Gegenüberstellung von Lizenzstufen (LZF, R1-R4, RD1-RD3) und den maximal
zulässigen Klassen in beiden Sparten.
### 3. Service-Integration (`README.md`)
* Verlinkung der neuen `TURNIER_KLASSEN.md` in der zentralen Dokumentations-Übersicht des `masterdata` Services.
## Verifizierung
* Abgleich der Daten mit `Bestimmungen_CSN-C_NEU.md` und `Bestimmungen_CDN-C_NEU.md`.
* Validierung der Lizenzstufen gegen `REITER_LIZENZEN.md` und die ÖTO 2026.
* Prüfung der Konsistenz mit den Abteilungs-Schwellenwerten aus der Master-Referenz.
## Nächste Schritte
* Implementierung der `Validation-Engine` Logik basierend auf der erstellten Startberechtigungs-Matrix.
* Erweiterung des `zns-import` Moduls zur Berücksichtigung der C-NEU Registrierungs-Ausnahmen für Pferde.
@@ -0,0 +1,36 @@
# Session Log: Masterdata Funktionär-Qualifikationen
**Datum:** 2026-03-30
**Agent:** 📜 [ÖTO/FEI Rulebook Expert]
## 🎯 Ziel
Aufbereitung der Qualifikationen für Richter und Parcoursbauer basierend auf der ÖTO 2026 und dem ZNS-Pflichtenheft v2.4
zur Integration in den `masterdata` Service.
## 🛠️ Änderungen
### 1. Neue Dokumentation: `FUNKTIONAERE_QUALIFIKATIONEN.md`
* **Fachlich:** Zusammenfassung der Richtergruppen (Dressur, Springen, Vielseitigkeit) und Zusatzqualifikationen (SPF,
DPF).
* **Level:** Dokumentation der Parcoursbauer-Level (P1-P4) inklusive der spezifischen Anforderung für C-NEU (mind. P1).
* **Regelwerk:** Integration der Einsatzvorgaben (§ 50 A-Teil) wie Mindestbesetzung und Zeitlimits.
* **Technisch:** Detaillierung der ZNS-Satzarten (X-Satz für Richter, Y-Satz für Parcoursbauer) mit Felddefinitionen (
Stelle/Länge).
### 2. README-Update
* Verlinkung der neuen Dokumentation in der zentralen `README.md` des `masterdata` Services.
## 🔍 Validierung
* Abgleich der Felddefinitionen mit dem Original-Pflichtenheft v2.4.
* Prüfung der fachlichen Anforderungen gegen die ÖTO 2026 (A- und B-Teil).
* Verifizierung der Pfade und Verlinkungen innerhalb des Service-Kontexts.
## 📌 Nächste Schritte
* Implementierung der `Funktionaer`-Entity in `masterdata-domain` (erledigt).
* Ausbau des `ExposedFunktionaerRepository` zur Unterstützung des ZNS-Imports der X- und Y-Sätze.
* Integration der Qualifikations-Validierung in die Turnier-Ausschreibung (Validation Engine).
@@ -0,0 +1,41 @@
# Session Log: Masterdata Gebührenordnung (ÖTO 2026)
**Datum:** 2026-03-30
**Agent:** 🧹 [Curator] & 📜 [ÖTO/FEI Rulebook Expert]
## 🎯 Ziel
Aufbereitung der offiziellen ÖTO-Gebührenordnung 2026 für die Sparten Dressur und Springen zur späteren Implementierung
in die Berechnungs- und Validierungs-Logik des Masterdata-Services.
## 📝 Durchgeführte Änderungen
### 1. Fachdokumentation erstellt
* **Datei:** `backend/services/masterdata/docs/GEBUEHRENORDNUNG.md`
* **Inhalt:**
* **Nenn- und Startgelder:** Strukturierte Übersicht über Nenngelder nach Kategorie (A/B/C) und
Startgeld-Obergrenzen (mit/ohne Geldpreis, C-NEU, getrenntes Richten).
* **Zusatzabgaben:** Dokumentation von Tierwohleuro (1,00 €) und Sportförderbeitrag (1,00 €).
* **Geldpreise:** Tabellarische Aufbereitung der Mindest-Geldpreise für Dressur (Klassen A bis S) und Springen (
Höhenstufen 105 cm bis 160 cm) für alle Turnierkategorien.
* **Funktionärsvergütung:** Festhalten der Tagessätze (120 € / 100 €), Kilometergelder (0,50 €) und
Unterkunftsvorgaben.
### 2. Integration & Verlinkung
* Aktualisierung der `backend/services/masterdata/README.md`, um die neue Gebührenordnung als Referenz für die
ÖTO-Konformität aufzunehmen.
## 🔍 Validierung
* Abgleich der Daten mit dem Originaldokument
`docs/03_Domain/02_Reference/OETO_Regelwerk/OETO-2026_E-Teil-Gebuehrenordnung_18-12-2025.md`.
* Sicherstellung, dass spartenrelevante Ausnahmen (z.B. Tierwohleuro nur bei Springen) korrekt markiert sind.
## 💡 Nächste Schritte
* Überführung der Gebührensätze in Domänen-Konstanten (`masterdata-domain`).
* Implementierung einer `AccountingEngine` oder eines `FeeCalculator` Services im `competition-context`, der auf diese
Stammdaten zugreift.
* Erweiterung der Ausschreibungs-Validierung um die Prüfung der Mindest-Geldpreis-Summen.

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