52 Commits

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

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 23:18:25 +02:00
stefan 15222b5453 chore: entferne veraltete Architekturdokumente
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 21:23:02 +02:00
stefan 6f15ada447 chore: dc-gui aus docker-compose.yaml auskommentiert
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-05 17:48:23 +02:00
stefan 8b294d947d docs(readme): Gitea-Test-Abschnitt hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-05 15:13:42 +02:00
stefan 66c8838379 docs(journal): POC-Status aktualisiert, Master-UX-Fixes dokumentiert und Follow-up geplant
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-30 16:49:04 +02:00
stefan 022ffccccd feat(device-initialization, core): mDNS-Discovery erweitert, Geräte- und UI-Interaktion optimiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-30 15:58:24 +02:00
stefan 8ab6ab1c2a feat(core, device-initialization): Netzwerk-Discovery verbessert, IP-Binding hinzugefügt und UI optimiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-30 12:12:52 +02:00
stefan 46d993e47f docs(journal): Roadmap und Schritte für Plan-USB-Hardware-PoC ergänzt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 15:08:37 +02:00
stefan 62f9472695 feat(device-initialization, core): Plan-USB-Backup hinzugefügt, BackupService implementiert und UI-Export-Button ergänzt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 15:08:11 +02:00
stefan b94984043c feat(device-initialization, core): Theme-Support hinzugefügt, Fokus- und UI-Optimierungen umgesetzt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 15:03:03 +02:00
stefan fd78404d72 refactor(design-system): Tooltip-Positionierung auf Above geändert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 12:53:15 +02:00
stefan 884ccc0db5 refactor(core, device-initialization): Icons auf AutoMirrored geändert, Tooltip-Positionierung und Alignment vereinfacht
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 12:50:27 +02:00
stefan 8ecc9fbe52 feat(device-initialization, core): Unterstützung für Hilfe-Tooltips, Netzwerk-Interface-Auswahl & Discovery-Radar ergänzt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 12:45:49 +02:00
stefan d0edfa2538 feat(docs): neue ADRs für Plan-USB, Offline-Lizenzierung & Netzwerk-Discovery hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-04-29 12:35:22 +02:00
stefan e1bf4d8454 docs: MASTER_ROADMAP aktualisiert und ältere Phasen zusammengefasst
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-04-28 21:19:27 +02:00
stefan 5a08361f83 docs: add unversioned results and event documents for Neumarkt and St. Poelten
Co-authored-by: Junie <junie@jetbrains.com>
2026-04-28 13:25:25 +02:00
stefan 5d6d9efd27 feat(veranstaltung): migrate event wizard to declarative orchestrator (ADR-0025). Transferred logic from EventFlowSample to EventWizardFlow. Renamed Demo* components to EventWizard*. Added OETO-compliant steps: TurnierKonfiguration, BewerbKonfiguration, AbteilungKonfiguration, Summary. Updated DSL flow to include full sequential path. --trailer "Co-authored-by: Junie <junie@jetbrains.com>" 2026-04-28 13:24:27 +02:00
403 changed files with 8259 additions and 8120 deletions
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/lib/common.sh"
REPO_ROOT="$(resolve_repo_root)"
cd "$REPO_ROOT"
# check-docs-drift.sh
# Zweck: sehr schlanke Drift-Checks gegen die neue Doku-Struktur.
# - Kein Guidelines-System mehr.
# - Single Source of Truth: `docs/`
err=0
has() { grep -q "$2" "$1" || { echo "[DRIFT] '$2' fehlt in $1"; err=1; }; }
miss() { grep -q "$2" "$1" && { echo "[DRIFT] Veralteter Begriff '$2' in $1"; err=1; }; }
# Harte Altlast-Pfade dürfen nicht mehr vorkommen
if git grep -n "docs/00_Domain/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/00_Domain/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/adr/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/adr/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/c4/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/c4/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/how-to/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/how-to/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/reference/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/reference/' in docs/* gefunden"
err=1
fi
# Quelle der Wahrheit: Gateway-Technologie (sollte in Architektur/ADRs/C4 konsistent sein)
has docs/01_Architecture/ARCHITECTURE.md "Spring Cloud Gateway"
has docs/01_Architecture/adr/0007-api-gateway-pattern-de.md "Spring Cloud Gateway"
miss docs/01_Architecture/adr/0007-api-gateway-pattern-de.md "Ktor"
has docs/01_Architecture/c4/02-container-de.puml "Spring Cloud Gateway"
miss docs/01_Architecture/c4/02-container-de.puml "Ktor"
exit $err
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
# Common helpers for AI guardrail scripts
# Robustly resolve the repository root directory.
# Strategy: prefer Git; fallback to marker search upwards; last resort: current dir.
resolve_repo_root() {
local start
start="${1:-$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)}"
if command -v git >/dev/null 2>&1; then
if git -C "$start" rev-parse --show-toplevel >/dev/null 2>&1; then
git -C "$start" rev-parse --show-toplevel
return 0
fi
fi
local dir
dir="$(cd "$start" && pwd)"
while [ "$dir" != "/" ]; do
if [ -f "$dir/gradlew" ] || [ -f "$dir/settings.gradle.kts" ] || [ -d "$dir/.git" ]; then
echo "$dir"
return 0
fi
dir="$(dirname "$dir")"
done
pwd
}
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/lib/common.sh"
REPO_ROOT="$(resolve_repo_root)"
cd "$REPO_ROOT"
mkdir -p build/diagrams
shopt -s nullglob
for f in docs/architecture/c4/*.puml; do
docker run --rm -v "$PWD":/data plantuml/plantuml -tsvg "/data/$f" -o "/data/build/diagrams"
echo "Rendered build/diagrams/$(basename "${f%.puml}").svg"
done
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/lib/common.sh"
REPO_ROOT="$(resolve_repo_root)"
cd "$REPO_ROOT"
QUICK_MODE=false
while [[ $# -gt 0 ]]; do
case $1 in
--quick)
QUICK_MODE=true
shift
;;
--help|-h)
cat << 'EOF'
Docs Link-Validierung
USAGE:
./.ai/scripts/validate-links.sh [--quick]
BESCHREIBUNG:
Prüft Markdown-Links in `docs/**/*.md` auf gebrochene relative Pfade.
Ignoriert externe Links (http/https/mailto) sowie reine Anchors (#...).
OPTIONEN:
--quick Führt nur eine Teilmenge der Prüfungen durch (aktuell nicht implementiert).
EOF
exit 0
;;
*)
echo "[ERROR] Unbekannter Parameter: $1" >&2
exit 2
;;
esac
done
python3 - <<'PY'
import re
import sys
from pathlib import Path
from urllib.parse import unquote
root = Path.cwd()
docs_dir = root / "docs"
if not docs_dir.is_dir():
print(f"[ERROR] docs-Verzeichnis nicht gefunden: {docs_dir}", file=sys.stderr)
sys.exit(2)
# Veraltete Pfad-Prüfungen wurden entfernt; Fokus auf Link-Integrität.
FORBIDDEN_SUBSTRINGS = []
md_files = sorted(docs_dir.rglob("*.md"))
link_pattern = re.compile(r"\]\(([^)]+)\)")
errors = 0
def is_external(target: str) -> bool:
t = target.lower()
return t.startswith("http://") or t.startswith("https://") or t.startswith("mailto:")
def strip_fragment_and_query(target: str) -> str:
target = target.split("#", 1)[0]
target = target.split("?", 1)[0]
return target
for f in md_files:
text = f.read_text(encoding="utf-8", errors="replace")
for forbidden in FORBIDDEN_SUBSTRINGS:
if forbidden in text:
print(f"[ERROR] Veralteter Pfad '{forbidden}' in {f}")
errors += 1
for match in link_pattern.finditer(text):
target = match.group(1).strip()
if not target:
continue
if is_external(target):
continue
if target.startswith("#"):
continue
if target.startswith("<") and target.endswith(">"):
target = target[1:-1]
target = unquote(strip_fragment_and_query(target))
if target.startswith("/"):
continue
if ":" in target.split("/", 1)[0]:
# z.B. "vscode:..."
continue
resolved = (f.parent / target).resolve()
try:
resolved.relative_to(root.resolve())
except ValueError:
print(f"[ERROR] Link zeigt außerhalb des Repos: {f} -> {target}")
errors += 1
continue
if resolved.is_dir():
if not (resolved / "README.md").is_file():
print(f"[ERROR] Verlinktes Verzeichnis ohne README.md: {f} -> {target}")
errors += 1
continue
if not resolved.exists():
print(f"[ERROR] Broken link: {f} -> {target}")
errors += 1
if errors:
print(f"[ERROR] Link-Validierung fehlgeschlagen: {errors} Fehler")
sys.exit(1)
print(f"[OK] Link-Validierung erfolgreich: {len(md_files)} Markdown-Dateien geprüft")
PY
+1 -1
View File
@@ -193,7 +193,7 @@ secrets/
# ===================================================================
TODO*.md
NOTES*.md
**/.junie/
.junie/
# ===================================================================
# Keep essential files (override exclusions)
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
desktop-tests:
# Komplett deaktivierbar über Repo-Variable: Settings → Variables → DESKTOP_CI_ENABLED=true
# Zusätzlich: Für PlanBBuilds überspringen, wenn Commit-Message [planb] enthält
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(github.event.head_commit.message, '[planb]') }}
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(gitea.event.head_commit.message, '[planb]') }}
name: Compose Desktop — Tests (headless) & Build
runs-on: ubuntu-latest
+8 -5
View File
@@ -1,9 +1,11 @@
name: Build and Publish Docker Images
run-name: Build & Publish by @${{ github.actor }}
run-name: Build & Publish by @${{ gitea.actor }}
on:
push:
branches: [ "main" ]
tags:
- 'v*'
paths:
- 'backend/**'
- 'platform/**'
@@ -114,8 +116,9 @@ jobs:
with:
images: ${{ env.REGISTRY_INTERNAL }}/${{ env.IMAGE_PREFIX }}/${{ matrix.image }}
tags: |
type=raw,value=latest
type=sha,format=long
type=ref,event=tag
type=raw,value=latest,enable=${{ gitea.ref == 'refs/heads/main' }}
type=sha,format=long,enable=${{ gitea.ref == 'refs/heads/main' }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
@@ -129,5 +132,5 @@ jobs:
provenance: false
sbom: false
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp || 'unknown' }}
VERSION=${{ github.sha }}
BUILD_DATE=${{ gitea.event.head_commit.timestamp || 'unknown' }}
VERSION=${{ gitea.sha }}
+56
View File
@@ -0,0 +1,56 @@
name: Feature Build — Windows MSI (via Conveyor)
on:
workflow_dispatch: # Nur noch manueller Start möglich, da ARM64-Runner inkompatibel
# push:
# branches: [ "feature/*" ] # Deaktiviert wegen ARM64 Exec Format Error
jobs:
package-windows:
name: 📦 Windows .msi Packaging
# Desktop-CI ist nun via Conveyor auf Linux möglich
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup JDK 21 (Temurin)
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: gradle
- name: Gradle Build (Uber-JAR)
run: |
./gradlew :frontend:shells:meldestelle-desktop:jvmJar --no-daemon
ls -lh frontend/shells/meldestelle-desktop/build/libs/
- name: Setup Conveyor
run: |
# Conveyor-Installation via Debian-Paket (stabiler in CI)
sudo apt-get update && sudo apt-get install -y curl
# Wir nutzen die offizielle Empfehlung für Debian-basierte Systeme
curl -L https://conveyor.hydraulic.dev/install.sh -o install-conveyor.sh
# Validierung: Wenn es kein Shell-Skript ist (sondern HTML), abbrechen
if grep -q "<!DOCTYPE HTML" install-conveyor.sh; then
echo "Fehler: Download-URL lieferte HTML statt Skript. Nutze npm-Fallback."
npm install -g @hydraulic/conveyor
else
chmod +x install-conveyor.sh
./install-conveyor.sh
fi
echo "$HOME/.conveyor/bin" >> $GITEA_PATH
- name: Windows .msi mit Conveyor bauen
run: |
# HINWEIS: Erfordert aktuell einen x64-Linux-Runner.
# Schlägt auf ARM64 (Zora) mit 'Exec format error' fehl.
CONVEYOR_BIN=$(which conveyor || echo "$HOME/.conveyor/bin/conveyor")
$CONVEYOR_BIN make windows-msi
- name: .msi Artefakt hochladen
uses: actions/upload-artifact@v4
with:
name: meldestelle-windows-feature-build
path: output/*.msi
if-no-files-found: error
+1 -1
View File
@@ -5,7 +5,7 @@ on:
jobs:
no-hardcoded-versions:
# Für Plan-B-Builds überspringen: Commit-Message enthält [planb]
if: ${{ !contains(github.event.head_commit.message, '[planb]') }}
if: ${{ !contains(gitea.event.head_commit.message, '[planb]') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+16 -16
View File
@@ -23,7 +23,7 @@ jobs:
tag-release:
name: 🏷️ Git-Tag setzen
# Für Plan-B-Builds überspringen: Commit-Message enthält [planb]
if: ${{ !contains(github.event.head_commit.message, '[planb]') }}
if: ${{ !contains(gitea.event.head_commit.message, '[planb]') }}
runs-on: ubuntu-latest
outputs:
version: ${{ steps.read-version.outputs.version }}
@@ -64,7 +64,7 @@ jobs:
fi
- name: Git-Tag erstellen & pushen
if: steps.check-tag.outputs.already_tagged == 'false' && github.event.inputs.dry_run != 'true'
if: steps.check-tag.outputs.already_tagged == 'false' && gitea.event.inputs.dry_run != 'true'
run: |
TAG="${{ steps.read-version.outputs.tag }}"
VERSION="${{ steps.read-version.outputs.version }}"
@@ -80,7 +80,7 @@ jobs:
package-linux:
name: 📦 Linux .deb Packaging
# Nur ausführen, wenn Desktop-CI explizit aktiviert ist UND kein PlanB Commit
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(github.event.head_commit.message, '[planb]') }}
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(gitea.event.head_commit.message, '[planb]') }}
runs-on: ubuntu-latest
needs: tag-release
@@ -88,11 +88,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup JDK 21 (Temurin)
- name: Setup JDK 25 (Temurin)
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
java-version: '25'
- name: Gradle cache
uses: actions/cache@v4
@@ -128,7 +128,7 @@ jobs:
package-windows:
name: 📦 Windows .msi Packaging
# Nur ausführen, wenn Desktop-CI explizit aktiviert ist UND kein PlanB Commit
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(github.event.head_commit.message, '[planb]') }}
if: ${{ vars.DESKTOP_CI_ENABLED == 'true' && !contains(gitea.event.head_commit.message, '[planb]') }}
runs-on: windows-latest
needs: tag-release
@@ -136,11 +136,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup JDK 21 (Temurin)
- name: Setup JDK 25 (Temurin)
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
java-version: '25'
- name: Gradle cache
uses: actions/cache@v4
@@ -179,11 +179,11 @@ jobs:
steps:
- name: Summary ausgeben
run: |
echo "## 🚀 Release ${{ needs.tag-release.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Artefakt | Status |" >> $GITHUB_STEP_SUMMARY
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Linux .deb | ${{ needs.package-linux.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Windows .msi | ${{ needs.package-windows.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Git-Tag:** \`${{ needs.tag-release.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
echo "## 🚀 Release ${{ needs.tag-release.outputs.version }}" >> $GITEA_STEP_SUMMARY
echo "" >> $GITEA_STEP_SUMMARY
echo "| Artefakt | Status |" >> $GITEA_STEP_SUMMARY
echo "|----------|--------|" >> $GITEA_STEP_SUMMARY
echo "| Linux .deb | ${{ needs.package-linux.result }} |" >> $GITEA_STEP_SUMMARY
echo "| Windows .msi | ${{ needs.package-windows.result }} |" >> $GITEA_STEP_SUMMARY
echo "" >> $GITEA_STEP_SUMMARY
echo "**Git-Tag:** \`${{ needs.tag-release.outputs.tag }}\`" >> $GITEA_STEP_SUMMARY
+4
View File
@@ -56,3 +56,7 @@ desktop.ini
docs/temp/
docs/Bin/
docs/_archive/
# Conveyor
conveyor.rootkey
output/
+4 -40
View File
@@ -1,43 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
# check-docs-drift.sh
# Zweck: sehr schlanke Drift-Checks gegen die neue Doku-Struktur.
# - Kein Guidelines-System mehr.
# - Single Source of Truth: `docs/`
err=0
has() { grep -q "$2" "$1" || { echo "[DRIFT] '$2' fehlt in $1"; err=1; }; }
miss() { grep -q "$2" "$1" && { echo "[DRIFT] Veralteter Begriff '$2' in $1"; err=1; }; }
# Harte Altlast-Pfade dürfen nicht mehr vorkommen
if git grep -n "docs/00_Domain/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/00_Domain/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/adr/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/adr/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/c4/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/c4/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/how-to/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/how-to/' in docs/* gefunden"
err=1
fi
if git grep -n "docs/reference/" -- docs >/dev/null 2>&1; then
echo "[DRIFT] Veralteter Pfad 'docs/reference/' in docs/* gefunden"
err=1
fi
# Quelle der Wahrheit: Gateway-Technologie (sollte in Architektur/ADRs/C4 konsistent sein)
has docs/01_Architecture/ARCHITECTURE.md "Spring Cloud Gateway"
has docs/01_Architecture/adr/0007-api-gateway-pattern-de.md "Spring Cloud Gateway"
miss docs/01_Architecture/adr/0007-api-gateway-pattern-de.md "Ktor"
has docs/01_Architecture/c4/02-container-de.puml "Spring Cloud Gateway"
miss docs/01_Architecture/c4/02-container-de.puml "Ktor"
exit $err
# Shim: Weiterleitung auf zentrale Guardrail in .ai/
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
exec "$ROOT_DIR/.ai/scripts/check-docs-drift.sh" "$@"
+4 -6
View File
@@ -1,9 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
mkdir -p build/diagrams
shopt -s nullglob
for f in docs/architecture/c4/*.puml; do
docker run --rm -v "$PWD":/data plantuml/plantuml -tsvg "/data/$f" -o "/data/build/diagrams"
echo "Rendered build/diagrams/$(basename "${f%.puml}").svg"
done
# Shim: Weiterleitung auf zentrale Guardrail in .ai/
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
exec "$ROOT_DIR/.ai/scripts/render-plantuml.sh" "$@"
+4 -133
View File
@@ -1,136 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
# validate-links.sh - Link-Validierung für Projektdokumentation (`docs/**`).
# Zweck: Guardrail für die "Docs-as-Code"-Strategie.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
QUICK_MODE=false
while [[ $# -gt 0 ]]; do
case $1 in
--quick)
QUICK_MODE=true
shift
;;
--help|-h)
cat << 'EOF'
Docs Link-Validierung
USAGE:
./.junie/scripts/validate-links.sh [--quick]
BESCHREIBUNG:
Prüft Markdown-Links in `docs/**/*.md` auf gebrochene relative Pfade.
Ignoriert externe Links (http/https/mailto) sowie reine Anchors (#...).
OPTIONEN:
--quick Führt nur eine Teilmenge der Prüfungen durch (aktuell nicht implementiert).
EOF
exit 0
;;
*)
echo "[ERROR] Unbekannter Parameter: $1" >&2
exit 2
;;
esac
done
python3 - <<'PY'
import os
import re
import sys
from pathlib import Path
from urllib.parse import unquote
root = Path.cwd()
docs_dir = root / "docs"
if not docs_dir.is_dir():
print(f"[ERROR] docs-Verzeichnis nicht gefunden: {docs_dir}", file=sys.stderr)
sys.exit(2)
# Veraltete Pfad-Prüfungen wurden entfernt, da sie zu wartungsintensiv waren.
# Das Skript konzentriert sich nun auf die Validierung der Link-Integrität.
FORBIDDEN_SUBSTRINGS = []
md_files = sorted(docs_dir.rglob("*.md"))
link_pattern = re.compile(r"\]\(([^)]+)\)")
errors = 0
def is_external(target: str) -> bool:
t = target.lower()
return t.startswith("http://") or t.startswith("https://") or t.startswith("mailto:")
def strip_fragment_and_query(target: str) -> str:
# remove fragment and query parts
target = target.split("#", 1)[0]
target = target.split("?", 1)[0]
return target
for f in md_files:
text = f.read_text(encoding="utf-8", errors="replace")
for forbidden in FORBIDDEN_SUBSTRINGS:
if forbidden in text:
print(f"[ERROR] Veralteter Pfad '{forbidden}' in {f}")
errors += 1
for match in link_pattern.finditer(text):
target = match.group(1).strip()
if not target:
continue
if is_external(target):
continue
if target.startswith("#"):
continue
# drop angle brackets <...> used in markdown for urls with spaces
if target.startswith("<") and target.endswith(">"):
target = target[1:-1]
target = unquote(strip_fragment_and_query(target))
# ignore absolute paths in the repo (we treat them as doc-style links; validate only if relative)
if target.startswith("/"):
continue
# ignore non-file targets (e.g. empty or protocol-less anchors)
if ":" in target.split("/", 1)[0]:
# things like "vscode:..." etc.
continue
# treat as file path relative to markdown file
resolved = (f.parent / target).resolve()
# keep validation within repo
try:
resolved.relative_to(root.resolve())
except ValueError:
print(f"[ERROR] Link zeigt außerhalb des Repos: {f} -> {target}")
errors += 1
continue
# allow directories if they contain README.md
if resolved.is_dir():
if not (resolved / "README.md").is_file():
print(f"[ERROR] Verlinktes Verzeichnis ohne README.md: {f} -> {target}")
errors += 1
continue
if not resolved.exists():
print(f"[ERROR] Broken link: {f} -> {target}")
errors += 1
if errors:
print(f"[ERROR] Link-Validierung fehlgeschlagen: {errors} Fehler")
sys.exit(1)
print(f"[OK] Link-Validierung erfolgreich: {len(md_files)} Markdown-Dateien geprüft")
PY
# Shim: Weiterleitung auf zentrale Guardrail in .ai/
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
exec "$ROOT_DIR/.ai/scripts/validate-links.sh" "$@"
+21
View File
@@ -0,0 +1,21 @@
# .aiignore - Verhindert Token-Waste für Nolik
# Abhängigkeiten & Binaries
build/
.gradle/
*.jar
*.deb
*.msi
# Sensible Daten (auch lokal!)
.env
.env.*
config/docker/certs/
*.pem
*.jks
postgres-data/
valkey-data/
# Doku-Builds (Nolik soll die Source-Files in docs/ lesen, nicht die HTML-Exporte)
build/dokka/
docs/Neumarkt2026/*.pdf
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
# Shim: Weiterleitung auf zentrale Guardrail in .ai/
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
exec "$ROOT_DIR/.ai/scripts/check-docs-drift.sh" "$@"
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
# Shim: Weiterleitung auf zentrale Guardrail in .ai/
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
exec "$ROOT_DIR/.ai/scripts/validate-links.sh" "$@"
+12 -7
View File
@@ -3,12 +3,15 @@
Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten.
Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions.
## 🚀 Strategische Ausrichtung
## 🚀 Strategische Ausrichtung (Reality-Reset 28.04.2026)
Das Projekt **"Meldestelle"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software.
1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert.
2. **Offline-First:** Das System muss autark (ohne Internet) funktionieren. Sync-Logik ist Kernbestandteil.
3. **Domain-Driven:** 6 Bounded Contexts (SCS) bilden den fachlichen Rahmen.
2. **Offline-First:** Das System muss autark (ohne Internet) funktionieren.
3. **Domain-Driven:** Die Hierarchie **Veranstaltung -> Turnier -> Bewerb/Abteilung** ist das absolute Fundament.
**WICHTIG:** Alle Agenten arbeiten ab sofort nur noch auf Basis von verifiziertem Code. "Halluzinationen" über
abgeschlossene Phasen ohne entsprechende Implementierung sind untersagt.
## 1. Protokoll & Rollen-Badges
Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kontext und die Verantwortlichkeit zu klären.
@@ -37,7 +40,9 @@ Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kont
4. **Doku-as-Code:** Änderungen an Code/Architektur müssen sofort in `docs/` (ADR/Reference) reflektiert werden.
5. **Session-Abschluss:** Jede Session endet mit einem Eintrag durch den **Curator** (Journal oder Artefakt).
## 3. Projekt-Philosophie
* **Information Density over White Space:** Wir bauen ein Profi-Werkzeug, kein Spielzeug.
* **Speed over Animation:** Reaktionsgeschwindigkeit der UI hat höchste Priorität.
* **Offline-Authentizität:** Lokale Daten sind die "Source of Truth" für den User; der Server ist das Backup/Sync-Target.
## 🚫 Anti-Halluzinations-Protokoll (WICHTIG)
Um Fehlentscheidungen und falsche Status-Meldungen zu verhindern, gelten ab sofort folgende Regeln:
1. **Kein "Erledigt" ohne Beweis:** Ein Task darf erst dann als abgeschlossen markiert werden, wenn ein Test-Log, ein erfolgreicher Build oder eine explizite Bestätigung des Users vorliegt.
2. **Status "Verifikation ausstehend":** Code, der geschrieben, aber nicht auf Hardware getestet wurde, muss zwingend diesen Zusatz tragen.
3. **Fakten-Check vor Abschluss:** Vor dem Senden der `submit`-Meldung muss der Agent prüfen: "Habe ich das wirklich laufen sehen oder nehme ich es nur an?"
4. **Fehler-Eingeständnis:** Bei Entdeckung einer Halluzination ist sofort der User zu informieren und der Status in allen Dokumenten (Roadmap, Journal) zu korrigieren.
+10 -209
View File
@@ -17,218 +17,19 @@ Versionierung folgt [Semantic Versioning](https://semver.org/lang/de/).
### Hinzugefügt
- **Onboarding & Desktop-UX - 15.04.2026:**
- **Desktop-App:** Dynamisierung der Statusanzeigen im App-Footer ("Cloud synchronisiert" & "Verbunden").
- **Connectivity-Tracking:** Implementierung des `ConnectivityTracker` (KMP) zur Echtzeit-Überwachung der API-Gateway
Erreichbarkeit.
- **LAN-Erkennung:** Integration des `NetworkDiscoveryService` (mDNS) im Footer zur Anzeige aktiver Instanzen im
lokalen Netzwerk.
- **Onboarding:** Datenfluss vom `SettingsManager` bis in den Footer finalisiert (Anzeige des echten Gerätenamens).
- **Online-Nennung & Integration - 15.04.2026:**
- **Backend (Mail-Service):** Finalisierung des `MailController` für Web-Nennungen inkl. SMTP-Versand via World4You.
- **Frontend (Desktop):** `NennungsEingangScreen` an Live-Daten vom `mail-service` angebunden.
- **Repository:** `NennungRemoteRepository` (KMP) um `holeNennungen()` erweitert.
- **Billing & ÖTO - 15.04.2026:**
- **Sportförderbeitrag:** Automatische Buchung von 1,00 EUR (§16 ÖTO) bei jeder Nennung im `entries-service`
implementiert.
- **Basis-Infrastruktur & Domain-Definition:**
- DDD-Modelle für `Veranstaltung`, `Turnier`, `Bewerb` und `Abteilung` gemäß ÖTO definiert.
- ZNS-Parser Prototyp für Dateiformate (VEREIN01, LIZENZ01, PFERD01, RICHT01).
- Plan-B Mail-Service (Spring Boot) für Nennungs-Versand via World4You.
- Desktop-App Skelett mit Navigation und UI-Hüllen (Compose Desktop).
### Behoben
### Reality-Reset (28.04.2026)
- **Frontend (Desktop):** Behebung von Kompilierungsfehlern in `ScreenPreviews.kt` durch Implementierung der fehlenden
`getStats()` Methode in den `MasterdataRepository`-Mocks.
- **Identity-Modul:** Umstellung auf `kotlin.time.Instant` zur Vermeidung von Deprecation-Warnungen und Behebung von
Persistenz-Konflikten im `ExposedDeviceRepository`.
- **Koin DI:** Korrektur von Typ-Inferenz-Fehlern beim `HttpClient` im `nennung-feature` durch explizite Qualifier.
- **Turnier-Feature:** Behebung eines unsicheren Casts (`Any!` zu `List<String>`) in `TurnierStammdatenTab.kt`.
- **Konfiguration:** Harmonisierung der Ports (Mail-Service auf 8083) in `.env`, `dc-backend.yaml` und
`PlatformConfig.jvm.kt`.
- **Korrektur:** Vormalige Einträge über "abgeschlossene" Billing-, Results- und Zeitplan-Features wurden entfernt, da
diese im Code nicht funktional hinterlegt waren.
- **Status:** Fokus zurück auf die Kern-Hierarchie (Veranstaltung -> Turnier -> Bewerb).
### Hinzugefügt
- **Phase 12 (Abrechnung & Infrastruktur) - 12.04.2026:**
- **Infrastruktur:** Docker-Integration für `billing-service` (Port 8087) und API-Gateway Routing vervollständigt.
- **Service Discovery:** Alle relevanten Microservices (`masterdata`, `events`, `results`, `series`, `billing`) sind nun bei Consul registriert.
- **Frontend Billing:** `BillingRepository` und `BillingViewModel` auf reale API-Anbindung (Ktor) umgestellt; `BillingScreen` funktionalisiert.
- **Backend (Series):** JPA-Entitäten `Serie` und `SeriePunkt` im `series-service` stabilisiert und Flyway-Migrationen für das Datenbankschema erstellt.
- **Fix:** Behebung von IDE-Mapping-Warnungen durch explizite `@Column` Namen in den JPA-Entitäten.
- **Backend Fixes - 12.04.2026:**
- **Infrastruktur:** Behebung von Startfehlern im `events-service` (DataSource) und `masterdata-service` (Consul).
- **Build:** Integration von `results-service` und `series-service` in `settings.gradle.kts`.
- **Domain:** `Serie` und `SeriePunkt` zu `data class` konvertiert (copy() Unterstützung).
- **Phase 11 (Ergebniserfassung & Platzierung) - 12.04.2026:**
- **Backend (Results):** `results-service` um JPA-Entitäten, Repositories und Business-Logik für Platzierungsberechnungen (Wertnote, Zeit, Fehler) ergänzt.
- **Infrastructure:** `dc-backend.yaml` und `GatewayConfig.kt` um den Service `results` (Port 8088) erweitert.
- **Frontend Domain:** `ErgebnisRepository` und `Ergebnis`-Modell für Wertnoten, Zeiten und Status erstellt.
- **Frontend UI:** `ErgebnisEditDialog` zur schnellen Ergebniserfassung hinzugefügt; `TurnierStartlistenTab` ermöglicht nun Erfassung per Zeilen-Klick.
- **Frontend UI:** `TurnierErgebnislistenTab` vervollständigt: Buttons für "Platzierung berechnen" und "Drucken" (PDF) funktionalisiert.
- **Fix:** Kompilierungsprobleme im `TurnierFeatureModule` und `ScreenPreviews.kt` behoben (fehlende `ergebnisRepo` Parameter).
### Hinzugefügt
- **Phase 10.4 (Series-Context Vertiefung) - 12.04.2026:**
- **Backend (Series):** `series-service` um Logik für Streichresultate (`ReglementTyp`) und Bindungsarten (Reiter-zentriert, Pferde-zentriert, Paar-Bindung) erweitert.
- **Infrastructure:** `dc-backend.yaml` und `GatewayConfig.kt` um den Service `series` (Port 8089) erweitert.
- **Frontend Domain:** `SeriesRepository` und Modelle an das neue Ranking-Format (`SerieStandEntry`) angepasst.
- **UI:** `SeriesScreen.kt` überarbeitet: Zeigt nun Reiter- und Pferde-IDs sowie Fortschritt pro Teilnehmer an.
- **Dokumentation:** `MASTER_ROADMAP.md` aktualisiert (Phase 10 & 11 auf 'Completed' gesetzt).
### Hinzugefügt
- **Phase 10.3 (Echter Datenverkehr & Infrastruktur) - 12.04.2026:**
- **Infrastructure:** Docker-Services für `masterdata`, `events` und `zns-import` in `dc-backend.yaml` ergänzt.
- **Gateway:** API-Gateway Routing für Masterdata (`/api/v1/masterdata`) und Events (`/api/v1/events`) konfiguriert.
- **Frontend (Vereine):** `VereinRepository` (Ktor) und `VereinViewModel` implementiert für echtes Anlegen von Veranstaltern.
- **Frontend (Events):** `TurnierViewModel` an das reale `TurnierRepository` angebunden.
- **Fix:** `verein-feature` Abhängigkeiten korrigiert (Network/Ktor).
- **Fix:** Polling-Endpoints im `ZnsImportViewModel` an das neue Gateway-Routing angepasst.
### Hinzugefügt
- **Phase 10.2 (Masterdata-Editoren & Organisation) - 12.04.2026:**
- **Frontend:** `MasterdataEditDialogs.kt` für die Bearbeitung von Reiter- und Pferdedaten direkt im Turnier-Kontext.
- **Frontend:** Erweiterung des `MasterdataRepository` um Schreibzugriffe (`saveReiter`, `savePferd`).
- **Frontend:** Funktionale Suche für Turnierleiter im `Organisation`-Tab via `NennungViewModel` und Masterdata-API.
- **Frontend:** State-Management für Stammdaten-Editoren im `NennungViewModel`.
- **Fix:** Kompilierungsfehler in `ScreenPreviews.kt` behoben (fehlende Interface-Methoden in Mocks).
- **Fix (Desktop Shell):** Fehlendes `turnierFeatureModule` in `main.kt` registriert und Login-Gate in `DesktopApp.kt` optimiert.
### Hinzugefügt
- **Phase 10 (Series-Context & Stammdaten) - 11.04.2026:**
- **Frontend:** Stammdaten-Infrastruktur im `turnier-feature` (Repositories, DTOs, Domänenmodelle) für Reiter, Pferde, Funktionäre und Vereine.
- **Frontend:** `NennungViewModel` zur Steuerung der Suche und Status-Verwaltung von Nennungen.
- **Frontend:** Funktionalisierung des `Nennungen`-Tabs (Suche, Echt-Datenanbindung) und Vorbereitung des `Organisation`-Tabs.
- **Frontend:** `DefaultMasterdataRepository` zur Suche in Reitern, Pferden und Funktionären via Backend-API.
- **Netzwerk:** Erweiterung der `ApiRoutes` um Endpunkte für Masterdata und Nennungen.
- **Phase 10 (Series-Context) Vorbereitung:**
- **Frontend:** Neuer `SeriesScreen.kt` für die Verwaltung von Cups und Meisterschaften (konfigurierbare Reglements).
- **Frontend:** Erweiterung des `AdminUebersichtScreen` (Cockpit) um KPI-Kacheln mit Direkt-Links zu Cups und Meisterschaften.
- **Frontend:** Integration der Series-Navigation in die Breadcrumbs und das globale Routing (`Meisterschaften`, `Cups`).
- **Turnier-Feature Hardening:**
- **Frontend:** `STARTLISTEN` und `ERGEBNISLISTEN` Tabs vollständig an das `BewerbViewModel` angebunden (Bewerbs-Auswahl mit echten Daten).
- **Frontend:** Implementierung der Starter-Anzeige in der Startliste (LazyColumn).
### Geändert
- **Turnier-Feature:** Sichtbarkeit von `BewerbViewModel.generateStartliste()` auf `public` geändert, um den Aufruf aus dem Tab zu ermöglichen.
- **Frontend (Desktop):** `ScreenPreviews.kt` aktualisiert zur Berücksichtigung der neuen ViewModel-Abhängigkeiten (`NennungViewModel`, `MasterdataRepository`).
### [Phase 9] - 11.04.2026
- **Frontend:** Interaktiver Drag & Drop Zeitplan mit automatischem 5-Minuten-Snapping und Konflikt-Visualisierung.
- **Frontend:** "B-Satz Export (ZNS)" Toolbar-Aktion mit integriertem Vorschau-Dialog.
- **Frontend:** "Änderungs-Historie" (Audit-Log) Sektion zur Nachverfolgung von Zeitplan-Anpassungen.
- **Backend:** `audit_log` Persistenz und Abfrage-API für manuelle Eingriffe in Bewerbe.
- **Backend:** ZNS B-Satz Export Endpunkt (`/export/zns/b-satz`) zur Generierung von `BBEWERBE` Datensätzen.
- **Core:** `FixedWidthLineBuilder` zur präzisen Generierung von ZNS-konformen Festbreiten-Formaten.
### Behoben
- **Infrastruktur:** Veraltete `newSuspendedTransaction` in `DatabaseFactory.kt` durch moderne `suspendTransaction` (Exposed v1) ersetzt.
- **Frontend (Desktop):** Kompilierfehler in `ScreenPreviews.kt` behoben, indem fehlende Interface-Methoden im Mock-Repository implementiert wurden.
- **Backend (Tests):** `JdbcSQLSyntaxErrorException` im `BewerbeZeitplanIntegrationTest` durch Korrektur des Schema-Setups (Audit-Log Tabelle) gelöst.
### Hinzugefügt
- **Bugfix**: Behebung von Build-Fehlern im `veranstalter-feature` nach der Paket-Konsolidierung.
- **Frontend**: `FakeVeranstalterRepository` in `commonMain` implementiert, um saubere KMP-DI zu ermöglichen.
- **Frontend**: Veraltete Imports und Referenzen im `meldestelle-desktop` Shell und Previews korrigiert.
- **Architektur:** Fachliches Konzept für Zeitplan-Optimierung (Drag & Drop) erstellt (`konzept-zeitplan-optimierung-de.md`).
- **Architektur:** Spezifikation des Status-Automaten für Nennungen und Synchronisations-Logik (`status-automat-nennungen-de.md`).
- **Rulebook:** Überprüfung und Spezifikation der Parcoursbesichtigung zu Pferd (§43 ÖTO) inkl. 5-Minuten-Puffer-Regel.
- **Backend (Entries):** Erweiterung der Domain-Modelle `Bewerb` und `Abteilung` um Besichtigungs- und Pausen-Konfigurationen.
- **Backend (Entries):** Neues Datenmodell `BesichtigungsBlock` für wettbewerbsübergreifende Parcoursbesichtigungen.
- **Backend (Entries):** API-Endpunkt `PATCH /bewerbe/{id}/zeitplan` für schnelle Zeitplan-Updates implementiert.
- **Backend (Entries):** `StartlistenService` um ÖTO-konforme Zeitberechnung (Besichtigungs-Puffer, Pausen-Intervalle) erweitert.
### Geändert
- Masterdata/Domain: Umbenennungen zur Vereinheitlichung der Terminologie (DE):
- `MasterdataLicenseRepository``LizenzRepository`
- `LicenseMatrixService``LizenzMatrixService`
- `LicenseMatrixServiceImpl``LizenzMatrixServiceImpl`
- Test: `LicenseMatrixServiceTest``LiznezMatrixServiceTest` (exakt nach Vorgabe)
- Infrastructure (Exposed): `LicenseTable``LizenzTable`
- Docs: Begriff „reit_lizenzen“ → „reiterlizenzen“ in Glossar/UL konsolidiert.
### Hinzugefügt
- **Events-Service Bundle:** Vollständige Stabilisierung der `events` Services (Domain, Infrastructure, API, Service).
- **Domain:** Umstellung auf `kotlin.time.Instant` zur Vermeidung von Deprecation-Warnungen (Kotlin 2.1.20+) und Harmonisierung mit dem Rulebook-Expert.
- **Infrastructure:** Anpassung an den `org.jetbrains.exposed.v1` Namespace und Implementierung von UUID-Konvertierungen zwischen `kotlin.uuid.Uuid` (Domain) und `java.util.UUID` (DB).
- **API:** Refactoring des `VeranstaltungController` zur direkten Repository-Nutzung (Alignment mit `entries` Service).
- **Service-Config:** Umstellung auf Flyway-basiertes Tenant-Schema-Management in `EventsDatabaseConfiguration`.
- **Build:** Behebung des `shadowJar` Fehlers in `events-infrastructure` durch Entfernen des unnötigen `ktor` Plugins in der Library-Schicht.
- Masterdata: Automatisches Seeding aller Reiterlizenzen (license_matrix) beim Start des `masterdata-service` via `ReiterlizenzenSeeder` (idempotent; SPRINGEN: LIZENZFREI,R1R4; DRESSUR: LIZENZFREI,RD1RD3).
- **ZNS-Import (LIZENZ01.dat):** Robuster Lizenz-Tokenizer und Normalizer implementiert.
- Erkennung: `RD1..RD4`, `R1..R4`, `S1..S4`, `D2..D4`, Kombis `R{n}D{m}`, `R{n}S{k}`, `RDS4` (rechts-/letztes Vorkommen gewinnt).
- Normalisierung: `S*→R*`, `D*→RD*`, `RD4→RD3` (bis Enum verfügbar), `R{n}S{k}→Rmax(n,k)`, `R{n}D{m}→R{n}+RD{m}`.
- Integration: `ZnsReiterParser` füllt `lizenzen`-Liste (1:n) entsprechend und leitet `lizenzKlasse` bei fehlendem 4SpaltenCode aus Token ab.
- QA: Neue Unit-Tests (Tokenizer) für Beispiele `R2S3`, `R2D4`, `RD2` u. a.; alle Parser-Tests grün.
- **Core:** Modularisierte ZNS-Parser eingeführt (`ZnsVereinParser`, `ZnsReiterParser`, `ZnsPferdParser`, `ZnsFunktionaerParser`) zur Verbesserung der Wartbarkeit und Unterstützung von Einzelimporten.
- **Fix:** SQL-Migrationsfehler in `V010` behoben, indem die Umbenennung der Spalte `name` in `verein_name` durch einen idempotenten `DO`-Block abgesichert wurde (behebt "Unable to resolve column 'name'").
- **Infrastructure:** Datenbank-Migration `V010` hinzugefügt, um das Schema final mit den `Exposed`-Modellen zu synchronisieren.
- **Infrastructure:** Datei-Archivierung für hochgeladene ZNS-ZIP-Dateien im `ZnsImportOrchestrator` implementiert.
- **Infrastructure:** `ZnsImportService` vollständig auf die neuen spezialisierten Parser umgestellt und als Spring-Bean im Backend registriert.
- **QA:** Umfassende Test-Suite `ZnsParserTest.kt` mit realen ZNS-Daten (Hämmerle, Neuwirth, etc.) erstellt; Korrektur der Extraktions-Logik für Mitgliedsnummern (Position 147) und Funktionär-Daten (RICHT01).
- **QA:** Neue Betriebsanleitung für ZNS-Importer Tests erstellt: `docs/07_Infrastructure/runbooks/ZNS_Importer_Test_Manual.md`.
- **Infrastructure:** `MasterdataDatabaseConfiguration` korrigiert: Expliziter Aufruf von `Database.connect()` hinzugefügt, um Abstürze beim Anwendungsstart ("No database specified") zu beheben.
- **Infrastructure:** `application.yml` im `masterdata-service` vervollständigt (DataSource-Konfiguration mit `pg-user`/`pg-password` und Flyway-Aktivierung).
- **Domain:** Legacy-Spezifikationen für ZNS-Schnittstellen (Import/Export) formalisiert:
- `docs/03_Domain/02_Reference/Legacy_Specs/OETO-2026_Meldestelle_Pflichtenheft_V2.4.md` (Basis-Satzarten A-N)
- `docs/03_Domain/02_Reference/Legacy_Specs/OETO-2026_Meldestelle_Erweiterung-Schnittstelle_2014.md` (XML-Erweiterung, LinkID-Logik)
- **QA B-2:** `OnboardingValidator`-Objekt extrahiert; `OnboardingValidatorTest.kt` (17 Unit-Tests: Pflichtfeld-Guard,
Doppelklick-Schutz, Abbrechen-Reset, rememberSaveable-Regression)
- **QA B-3:** `AbteilungsRegelServiceTest.kt` um 14 Tests erweitert: CSN-C-NEU ≤95 cm / ≥100 cm Pflicht-Teilung,
ORGANISATORISCH, SEPARATE_SIEGEREHRUNG, Caprilli-Regression, Grenzfälle 90/110 cm
- **Domain:** `AbteilungsTeilungsTypE` um `ORGANISATORISCH` und `SEPARATE_SIEGEREHRUNG` erweitert
### Behoben
- **Masterdata/Infrastructure:** Kompilierfehler in `AltersklasseRepositoryImpl` durch Vereinheitlichung der Exposed-Tabellendefinition behoben:
- `AltersklassenTable``AltersklasseTable`
- Spalte `altersklassen_code``altersklasse_code`
- Tabellenname `altersklassen``altersklasse`
- **Masterdata/API:** Fehlendes Interface-Mapping ergänzt: `RegulationRepository` enthält nun `findAllTurnierklassen()`; `ExposedRegulationRepository` implementiert die Methode und `RegulationController` kompiliert wieder.
- **ZNS-Import:** `AltersklassenExposedRepository` korrigiert (richtiger Domain-Typ `AltersklasseDefinition`, Mapping von `SparteE` und Zeitstempeln).
- **Migration V013:** Idempotent und robust gemacht. Alle `ALTER TABLE ... RENAME`-Operationen laufen nun nur, wenn die Quell-Tabelle existiert (Fix für "Unable to resolve table 'bundesland'/'turnierklasse'").
- **Lizenz-Validierung:** `LicenseMatrixServiceImpl` um Cross-Discipline-Mapping R↔RD (ÖTO-Äquivalenzen) erweitert. Damit funktionieren Fälle wie Dressur-Starts mit Spring-Lizenz (R1→RD1, R2→RD2, R3/R4→RD3) bzw. umgekehrt konsistent.
- **Domain:** Striktere Spartenlizenz-Prüfung in `Reiter.hasLizenzForSparte` implementiert (RD1..RD3 nur DRESSUR; R1..R4 nur SPRINGEN). Behebt Testfehler „isEligible verweigert Start ohne passende Spartenlizenz“ im `LicenseMatrixServiceTest`.
### Behoben
- **Backend (Entries):** Fehlschlagenden Unit-Test `berechneStartzeiten sollte Zeiten korrekt aufsummieren` korrigiert; der Test berücksichtigt nun den neuen 5-minütigen ÖTO-konformen Puffer nach der Parcoursbesichtigung (§43).
- **Frontend (Desktop):** Build-Fehler ("No matching variant") beim `funktionaer-feature` behoben; fehlendes `build.gradle.kts` mit JVM-Target und Compose/Koin-Abhängigkeiten ergänzt.
- **Frontend (Desktop):** Massive Inkonsistenzen in der Paketstruktur des `veranstalter-feature` bereinigt; alle Komponenten (ViewModel, Screens, Mocks) auf das Standardpaket `at.mocode.frontend.features.veranstalter` konsolidiert, um Redeklarationen und Import-Fehler zu beheben.
- **Frontend (Desktop):** Kompilierfehler im `VeranstalterDetailScreen` durch korrekte Paket-Referenzierung des `FakeVeranstaltungStore` gelöst.
### Dokumentation
- **Masterdata/Docs:** `REITER_LIZENZEN.md` überarbeitet:
- Strikte Sparten-Trennung dokumentiert (RD1..RD3 nur Dressur; R1..R4 nur Springen).
- Dressur-Tabelle korrigiert (R-Lizenzen entfernen; RD-Pflicht je Klasse).
- Validierungslogik ergänzt (2-stufig: Spartenlizenz → Max-Turnierklasse; R↔RD Mapping nur zur Kappung, nicht zur Eligibility).
- Vielseitigkeit (CCN/CCI) ergänzt: kumulative Anforderungen (Dressur RD* UND Springen R* je Klasse); Startkartenregel für Einsteiger.
- Fahren (CAN/CAI) ergänzt: aktueller Systemzustand ohne `F*`Lizenzen dokumentiert; Teilnahme über Startkarte/Ausschreibung, geplante EnumErweiterung vermerkt.
- §15Tabelle (kompakt) integriert und auf ÖTOReferenz verlinkt; Bedeutungen „B,C“ und „LP“ erläutert. Hinweis aufgenommen, dass `RD4` derzeit nicht als Enum vorhanden ist und wie `RD3` behandelt wird.
- Kombinationsreihen gemäß §15 ergänzt: `R1S2`, `R1S3`, `R1S4`, `R2S3`, `R2S4`, `R3S4` (neuer Unterabschnitt 2.6 mit Tabelle, identische Spalten wie 2.5).
### Behoben
- **Masterdata:** Qualifikations-Management für Funktionäre (Richter/Parcoursbauer) professionalisiert: Umstellung von unstrukturiertem Text auf offizielle ÖTO/FEI Master-Daten Referenzen (`QualifikationMasterTable`).
- **Masterdata:** Fehlende Tabelle `funktionaer_qualifikation` in der Initialisierung beider Services (`masterdata` und `zns-import`) ergänzt, um `PSQLException` während des ZNS-Imports zu beheben.
- **Infrastructure:** Start-Probleme des `masterdata-service` endgültig behoben: Port-Konflikt zwischen Spring Boot (Management/Actuator) und dem Gateway (8081) durch Umzug auf Port 8086 (gemäß Infrastruktur-Vorgaben) gelöst.
- **Infrastructure:** Port-Konflikt im `masterdata-service` durch Trennung der Bind-Adressen (Spring: 127.0.0.1, Ktor: 0.0.0.0) und Bereinigung verwaister Prozesse stabilisiert.
- **Core:** Veraltete `ZnsLegacyParsersTest.kt` entfernt; alle Tests sind nun in `ZnsParserTest.kt` konsolidiert.
- **Domain:** Fehlschlagenden `LicenseMatrixServiceTest` behoben; fehlende `reiterLizenz`-Daten in Test-Reitern ergänzt und Fallback-Logik in `LicenseMatrixServiceImpl` für spartenübergreifende Lizenzen (z.B. Springlizenz für Dressur-Basis) stabilisiert.
- **Infrastructure:** Fehlschlagenden `RegulationSeedVerificationTest` behoben; Testdaten an das neue Modell (`reiterLizenz` Feld) angepasst.
- **Infrastructure:** Kompilierfehler 'Unresolved reference lizenzKlasse' in `ReiterExposedRepository` behoben; fehlendes Feld `lizenzKlasse` zu `ReiterTable` und Datenbank-Migration `V010` hinzugefügt.
- **Onboarding:** `remember``rememberSaveable` für `geraetName`, `sharedKey`, `znsStatus` in `OnboardingScreen.kt` (
Felder gingen bei Zurück-Navigation verloren)
- **AbteilungsRegelService:** CSN-C-NEU Pflicht-Teilungslogik implementiert (≤95 cm: ohne/mit Lizenz; ≥100 cm: R1/R2+);
`SparteE`-Import ergänzt
- Desktop-Packaging konfiguriert: `.deb` (Linux), `.msi` (Windows), `.dmg` (macOS)
- Zentrale Versionsdatei `version.properties` (Single Source of Truth für SemVer)
- Automatisches Git-Tagging via CI/CD (`release.yml` Gitea Actions Workflow)
- `CHANGELOG.md` eingeführt (dieses Dokument)
---
## [1.0.6-SNAPSHOT] — 2026-04-10
### [1.0.6-SNAPSHOT] — 2026-04-10
### Hinzugefügt
- **Entries-Domain:** Strukturiertes Abteilungs-Warnungssystem gemäß ÖTO § 39 implementiert.
+12 -6
View File
@@ -13,14 +13,14 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
**Starte hier:** [**→ docs/README.md**](./docs/README.md)
| Bereich | Inhalt |
|-----------------------------------------------|---------------------------------------------|
| Bereich | Inhalt |
|-----------------------------------------------|---------------------------------------------------|
| [01_Architecture](./docs/01_Architecture) | Master Roadmap, ADRs, C4Modelle, DesktopKonzept |
| [02_Guides](./docs/02_Guides) | Setup-Anleitungen, Entwickler-Guidelines |
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
| [02_Guides](./docs/02_Guides) | Setup-Anleitungen, Entwickler-Guidelines |
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md)
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/Concepts/konzept-offline-first-desktop-backend-de.md)
---
@@ -113,3 +113,9 @@ Beiträge sind willkommen. Bitte lies zunächst die Entwickler-Guides unter [`do
## 📜 Lizenz
Dieses Projekt steht unter der [MIT License](LICENSE).
---
## Test
Das ist der 2. Versuch über Remote zu Committen
@@ -8,7 +8,7 @@ import io.valkey.springframework.data.valkey.core.ValkeyTemplate
import io.valkey.springframework.data.valkey.serializer.StringValkeySerializer
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.testcontainers.containers.GenericContainer
@@ -70,7 +70,7 @@ class ValkeyDistributedCachePerformanceTest {
}
@Test
fun `test cache performance with high concurrent access`() = runTest {
fun `test cache performance with high concurrent access`() = runBlocking {
logger.info { "Starting concurrent access test" }
val numberOfCoroutines = 100
val operationsPerCoroutine = 50
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
@@ -2,6 +2,7 @@
package at.mocode.zns.importer
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.*
import at.mocode.zns.parser.ZnsFunktionaerParser
import at.mocode.zns.parser.ZnsPferdParser
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -4,8 +4,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
@@ -3,6 +3,7 @@
package at.mocode.masterdata.domain.model
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.LocalDateSerializer
@@ -14,16 +15,6 @@ import kotlin.time.Clock
import kotlin.time.Instant
import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
/**
* Domain model representing a rider (Reiter) in the actor-context.
*
@@ -4,10 +4,10 @@ package at.mocode.masterdata.infrastructure.persistence.reiter
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterAltersKlasseE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.ReiterRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.and
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+2 -2
View File
@@ -5,8 +5,8 @@
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
ARG GRADLE_VERSION=9.4.1
ARG JAVA_VERSION=25
ARG GRADLE_VERSION=9.5.0
ARG JAVA_VERSION=25.0.2
ARG BUILD_DATE
ARG VERSION=1.0.0-SNAPSHOT
+51 -30
View File
@@ -38,7 +38,7 @@ plugins {
// ### ALLPROJECTS CONFIGURATION ###
// ##################################################################
val isWasmEnabled = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
val isWasmEnabled: Boolean = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
// ---------------------------------------------------------------
// Zentrale Versionierung — liest version.properties (SemVer)
@@ -47,10 +47,10 @@ val versionProps =
java.util.Properties().also { props ->
rootProject.file("version.properties").inputStream().use { props.load(it) }
}
val vMajor = versionProps.getProperty("VERSION_MAJOR", "1")
val vMinor = versionProps.getProperty("VERSION_MINOR", "0")
val vPatch = versionProps.getProperty("VERSION_PATCH", "0")
val vQualifier = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
val vMajor: String = versionProps.getProperty("VERSION_MAJOR", "1")
val vMinor: String = versionProps.getProperty("VERSION_MINOR", "0")
val vPatch: String = versionProps.getProperty("VERSION_PATCH", "0")
val vQualifier: String = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier"
allprojects {
@@ -90,7 +90,7 @@ subprojects {
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
// Suppress ByteBuddy/Mockito dynamic agent loading warnings (Java 21+)
jvmArgs("-XX:+EnableDynamicAgentLoading")
// Increase test JVM memory with a stable configuration
jvmArgs("--enable-native-access=ALL-UNNAMED")
minHeapSize = "512m"
maxHeapSize = "2g"
// Parallel test execution for better performance
@@ -113,7 +113,7 @@ subprojects {
// (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings)
// to avoid compiler-flag incompatibilities across toolchains.
// (B) Conditional Wasm/JS Target handling based on `enableWasm` property
// (B) Conditional Wasm/JS Target handling based on the ` enableWasm ` property
// This significantly reduces build times during Desktop development.
// Flag is defined at the beginning of the script.
@@ -166,6 +166,7 @@ subprojects {
jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false")
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
jvmArgs("-XX:+EnableDynamicAgentLoading")
jvmArgs("--enable-native-access=ALL-UNNAMED")
maxHeapSize = "2g"
dependsOn("testClasses")
}
@@ -175,20 +176,30 @@ subprojects {
// Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin)
tasks.withType<Exec>().configureEach {
// Merge existing NODE_OPTIONS with --no-deprecation
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged)
// Also set the legacy switch to silence warnings entirely
environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
}
// ------------------------------
// Detekt & Ktlint default setup
// ------------------------------
// PERFORMANCE: Deaktiviert standardmäßig in jedem Build, nur explizit ausführen
tasks.withType<Detekt>().configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
tasks.matching { it.name == "ktlintCheck" }.configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
plugins.withId("io.gitlab.arturbosch.detekt") {
extensions.configure(DetektExtension::class.java) {
buildUponDefaultConfig = true
@@ -267,7 +278,6 @@ tasks.register("checkBundleBudget") {
}
shells.forEach { shell ->
val key = shell.path.trimStart(':').replace(':', '/') // or use a colon form for budgets keys below
val colonKey = shell.path.trimStart(':').replace('/', ':').trim() // ensure ":a:b:c"
// Budgets are keyed by a Gradle path with colons but without leading colon in config for readability
val budgetKeyCandidates =
@@ -362,8 +372,8 @@ tasks.register("staticAnalysis") {
// Apply Dokka (V2) automatically to Kotlin subprojects
subprojects {
plugins.withId("org.jetbrains.kotlin.jvm") { apply(plugin = "org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.multiplatform") { apply(plugin = "org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.jvm") { pluginManager.apply("org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.multiplatform") { pluginManager.apply("org.jetbrains.dokka") }
}
// Aggregate tasks to build multi-module docs in Markdown (GFM) and HTML
@@ -372,27 +382,36 @@ val dokkaAll =
tasks.register("dokkaAll") {
group = "documentation"
description = "Builds Dokka (V2) for all modules and aggregates outputs under build/dokka/all"
// Trigger Dokka generation in all subprojects that have the Dokka plugin
dependsOn(
// PERFORMANCE: Nur ausführen wenn explizit gefordert
enabled = project.hasProperty("runDokka")
// Capture required values for configuration cache
val rootBuildDir = layout.buildDirectory.get().asFile
val subprojectData =
subprojects
.filter { it.plugins.hasPlugin("org.jetbrains.dokka") }
.map { "${it.path}:dokkaGenerate" },
)
.map { p ->
Triple(p.path, p.name, p.layout.buildDirectory.get().asFile)
}
// Trigger Dokka generation in all subprojects that have the Dokka plugin
dependsOn(subprojectData.map { "${it.first}:dokkaGenerate" })
doLast {
val dest = layout.buildDirectory.dir("dokka/all").get().asFile
val dest = File(rootBuildDir, "dokka/all")
if (dest.exists()) dest.deleteRecursively()
dest.mkdirs()
val modules = mutableListOf<Pair<String, String>>()
subprojects.filter { it.plugins.hasPlugin("org.jetbrains.dokka") }.forEach { p ->
subprojectData.forEach { (pPath, pName, pBuildDir) ->
// Dokka V2 writes into build/dokka/html
val outHtml = p.layout.buildDirectory.dir("dokka/html").get().asFile
val outHtml = File(pBuildDir, "dokka/html")
if (outHtml.exists()) {
val modulePath = p.path.trimStart(':').replace(':', '/')
val modulePath = pPath.trimStart(':').replace(':', '/')
val targetDir = File(dest, modulePath)
outHtml.copyRecursively(targetDir, overwrite = true)
modules.add(p.name to modulePath)
modules.add(pName to modulePath)
}
}
@@ -451,17 +470,19 @@ tasks.register("docs") {
// Apply Node warning suppression on root project Exec tasks as well
// Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env
tasks.withType<Exec>().configureEach {
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged)
environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
}
tasks.wrapper {
gradleVersion = "9.4.1"
gradleVersion = "9.5.0"
distributionType = Wrapper.DistributionType.BIN
}
+46
View File
@@ -0,0 +1,46 @@
include required("/stdlib/jdk/21/amazon.conf")
include required("https://raw.githubusercontent.com/hydraulic-software/conveyor/master/configs/jvm/extract-native-libraries.conf")
app {
display-name = "Meldestelle"
rdns-name = "at.mocode.meldestelle"
vendor = "mo-code.at"
contact-email = "support@mo-code.at"
version = "1.0.1"
description = "ÖTO-konforme Turnier-Meldestelle Profi Desktop App"
# Ziel-Plattformen: Windows und Linux
machines = [ windows.amd64, linux.amd64.glibc ]
site.base-url = "localhost"
# Icons werden im Ordner gesucht
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources/icon.png"
jvm {
gui {
main-class = "at.mocode.frontend.shell.desktop.MainKt"
}
jvm-options = [
"-Xms256m",
"-Xmx1024m",
"-Dfile.encoding=UTF-8",
"--enable-native-access=ALL-UNNAMED"
]
}
# JARs aus dem Gradle-Build
inputs += "frontend/shells/meldestelle-desktop/build/libs/*.jar"
windows {
upgrade-uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
menu-group = "Meldestelle"
desktop-shortcut = true
}
linux {
debian.control.depends = "libasound2, libgl1-mesa-glx, libx11-6"
}
}
conveyor.compatibility-level = 22
@@ -0,0 +1,19 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.domain.model
import at.mocode.core.domain.serialization.LocalDateSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
@@ -1,10 +1,10 @@
package at.mocode.zns.parser
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.parser.FixedWidthLineReader
import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
+20 -20
View File
@@ -12,8 +12,8 @@ services:
context: .
dockerfile: backend/infrastructure/gateway/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -102,8 +102,8 @@ services:
context: .
dockerfile: backend/services/ping/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -179,8 +179,8 @@ services:
context: .
dockerfile: backend/services/masterdata/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -256,8 +256,8 @@ services:
context: .
dockerfile: backend/services/events/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -331,8 +331,8 @@ services:
context: .
dockerfile: backend/services/zns-import/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -407,8 +407,8 @@ services:
context: .
dockerfile: backend/services/results/results-service/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -482,8 +482,8 @@ services:
context: .
dockerfile: backend/services/billing/billing-service/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -555,8 +555,8 @@ services:
context: .
dockerfile: backend/services/mail/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -627,8 +627,8 @@ services:
context: .
dockerfile: backend/services/scheduling/scheduling-service/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
@@ -700,8 +700,8 @@ services:
context: .
dockerfile: backend/services/series/series-service/Dockerfile
args:
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.4.1}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.5.0}"
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25.0.2}"
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
BUILD_DATE: "${DOCKER_BUILD_DATE}"
labels:
+4 -4
View File
@@ -1,9 +1,9 @@
name: "${PROJECT_NAME:-meldestelle}"
services:
# ==========================================
# 3. FRONTEND (UI)
# ==========================================
# services:
# # ==========================================
# # 3. FRONTEND (UI)
# # ==========================================
# --- WEB-APP ---
# web-app:
+1 -1
View File
@@ -3,7 +3,7 @@ name: "${PROJECT_NAME:-meldestelle}"
include:
- dc-infra.yaml
- dc-backend.yaml
- dc-gui.yaml
#- dc-gui.yaml
- dc-ops.yaml
# Globale Definitionen, falls nötig (meistens reichen die in den Teil-Dateien,
@@ -1,71 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-15
---
# Frontend-Architektur & Modularisierungsstrategie
**Status:** ENTWURF
**Zuletzt aktualisiert:** 2026-01-19
**Kontext:** Migration zu Clean Architecture & Feature-Modulen
---
## 1. Übersicht
Die Frontend-Architektur von **Meldestelle** basiert auf **Kotlin Multiplatform (KMP)** mit **Compose Multiplatform** für die Benutzeroberfläche. Wir folgen einem strikten **Clean Architecture**-Ansatz, um Testbarkeit, Skalierbarkeit und Trennung der Zuständigkeiten sicherzustellen.
## 2. Modulstruktur
Das Projekt ist in folgende Schichten unterteilt:
### 2.1 Core-Module (`frontend/core`)
Wiederverwendbare Komponenten, die unabhängig von spezifischen Geschäftsfunktionen sind.
* `core-network`: Zentrale HTTP-Client-Konfiguration (Auth, Logging, ContentNegotiation).
* `core-sync`: Generische Synchronisierungslogik (`SyncManager`, `SyncableRepository`).
* `core-ui`: Gemeinsame UI-Komponenten und Design-System.
### 2.2 Feature-Module (`frontend/features`)
Jede Geschäftsdomäne (z.B. `ping`, `auth`, `events`) liegt in ihrem eigenen Modul.
Ein Feature-Modul MUSS die **Clean Architecture** Paketstruktur einhalten:
* `at.mocode.{feature}.feature.domain`
* **Entitäten:** Reine Datenklassen.
* **Interfaces:** Repository-Interfaces, Service-Interfaces.
* **Use Cases:** Geschäftslogik (optional, für komplexe Logik).
* `at.mocode.{feature}.feature.data`
* **Implementierungen:** Repository-Implementierungen, API-Clients.
* **DTOs:** Data Transfer Objects (wenn von Domain-Entitäten abweichend).
* `at.mocode.{feature}.feature.presentation`
* **ViewModels:** Zustandsverwaltung.
* **Screens:** Composable-Funktionen.
* `at.mocode.{feature}.feature.di`
* **Koin-Modul:** Konfiguration der Dependency Injection.
### 2.3 Shells (`frontend/shells`)
Anwendungs-Einstiegspunkte, die alles zusammenführen.
* `meldestelle-portal`: Die Haupt-Web-/Desktop-Anwendung.
## 3. Migrationsstrategie (Übergangsphase)
Wir migrieren aktuell von einer monolithischen `clients`-Paketstruktur zu modularen Feature-Modulen.
**Regeln für die Migration:**
1. **Neue Features:** Müssen direkt in `frontend/features/{name}` unter Verwendung der Clean Architecture-Struktur implementiert werden.
2. **Bestehende Features:** Werden schrittweise migriert.
3. **Koexistenz:** Während des Übergangs ist Legacy-Code in `clients/` erlaubt, aber als veraltet markiert.
4. **Dependency Injection:** Legacy-Code muss die neuen Koin-Module verwenden, sofern verfügbar.
5. **Keine Ghost-Klassen:** Klassen nicht duplizieren. Wenn eine Klasse in ein Feature-Modul verschoben wird, muss die alte in `clients/` gelöscht werden.
## 4. Wichtige Entscheidungen (ADRs)
### ADR-001: Entkopplung der Sync-Logik
* **Entscheidung:** ViewModels dürfen nicht direkt vom `SyncManager` abhängen.
* **Begründung:** Um einfacheres Testen zu ermöglichen und die Komplexität des generischen Sync-Mechanismus zu verbergen.
* **Umsetzung:** Ein Domain-Service-Interface (z.B. `PingSyncService`) einführen, das den `SyncManager`-Aufruf kapselt.
### ADR-002: Feature-Modul-Isolation
* **Entscheidung:** Feature-Module sollten nach Möglichkeit nicht direkt voneinander abhängen.
* **Kommunikation:** Gemeinsame Core-Module oder lose Kopplung über Interfaces/Events verwenden, wenn modulübergreifende Kommunikation nötig ist.
---
**Freigegeben von:** Lead Architect
@@ -1,51 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
---
# Open-Source-Konformität & Lizenz-Checkliste
Dieses Dokument dient der Überwachung und Sicherstellung der Open-Source-Konformität des Projekts **Meldestelle**. Es wird vom Lead Architect gepflegt.
## Status der Kern-Komponenten (Stand: Januar 2026)
| Komponente | Lizenz | Status | Risiko | Maßnahme / Kommentar |
| :--- | :--- | :--- | :--- | :--- |
| **Kotlin / JVM** | Apache 2.0 / GPLv2+CE | ✅ OK | Sehr gering | Standard-Stack. |
| **Spring Boot / Cloud** | Apache 2.0 | ✅ OK | Sehr gering | |
| **PostgreSQL** | PostgreSQL (BSD-like) | ✅ OK | Sehr gering | |
| **Redis** | **RSALv2 / SSPL** | ⚠️ KRITISCH | Hoch | **Umstieg auf Valkey (BSD) geplant.** |
| **Consul** | **BSL 1.1** | ⚠️ BEOBACHTEN | Mittel | Lizenzänderung durch HashiCorp. Für interne Nutzung aktuell unkritisch. |
| **Keycloak** | Apache 2.0 | ✅ OK | Gering | |
| **SQLDelight** | Apache 2.0 | ✅ OK | Sehr gering | |
| **Redisson** | Apache 2.0 (Core) | ✅ OK | Gering | Sicherstellen, dass keine PRO-Features genutzt werden. |
---
## Checkliste für neue Abhängigkeiten
Bevor eine neue Bibliothek oder Infrastruktur-Komponente hinzugefügt wird, muss sie folgende Kriterien erfüllen:
1. **Lizenz-Typ:**
* Bevorzugt: Apache 2.0, MIT, BSD (3-Clause).
* Akzeptabel: MPL 2.0.
* Einzelfallprüfung: LGPL (nur als dynamische Bibliothek).
* **Verboten:** AGPL, SSPL, RSAL, BSL (sofern nicht explizit vom Architect freigegeben).
2. **Community & Governance:**
* Wird das Projekt von einer neutralen Foundation (Apache, CNCF, Linux Foundation) verwaltet?
* Gibt es eine "Single Vendor" Abhängigkeit (Risiko einer plötzlichen Lizenzänderung)?
3. **Transitive Abhängigkeiten:**
* Bringt die Bibliothek "versteckte" Copyleft-Lizenzen mit? (Check via Gradle License Plugin).
---
## TODOs & Strategische Entscheidungen
- [ ] **Migration Redis -> Valkey:** Umstellung der Docker-Images und Test der Kompatibilität.
- [ ] **Consul Review:** Jährliche Prüfung der BSL-Auswirkungen auf unser Deployment-Modell.
- [ ] **Automatisierung:** Integration eines License-Check-Plugins in den CI-Build (z.B. `com.github.jk1.dependency-license-report`).
---
*Dieses Dokument ist Teil der "Docs-as-Code" Strategie und muss bei jeder Änderung am Tech-Stack aktualisiert werden.*
@@ -0,0 +1,54 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
---
# Open-Source-Konformität & Lizenz-Checkliste
Dieses Dokument dient der Überwachung und Sicherstellung der Open-Source-Konformität des Projekts **Meldestelle**. Es
wird vom Lead Architect gepflegt.
## Status der Kern-Komponenten (Stand: Januar 2026)
| Komponente | Lizenz | Status | Risiko | Maßnahme / Kommentar |
|:------------------------|:----------------------|:--------------|:------------|:------------------------------------------------------------------------|
| **Kotlin / JVM** | Apache 2.0 / GPLv2+CE | ✅ OK | Sehr gering | Standard-Stack. |
| **Spring Boot / Cloud** | Apache 2.0 | ✅ OK | Sehr gering | |
| **PostgreSQL** | PostgreSQL (BSD-like) | ✅ OK | Sehr gering | |
| **Redis** | **RSALv2 / SSPL** | ⚠️ KRITISCH | Hoch | **Umstieg auf Valkey (BSD) geplant.** |
| **Consul** | **BSL 1.1** | ⚠️ BEOBACHTEN | Mittel | Lizenzänderung durch HashiCorp. Für interne Nutzung aktuell unkritisch. |
| **Keycloak** | Apache 2.0 | ✅ OK | Gering | |
| **SQLDelight** | Apache 2.0 | ✅ OK | Sehr gering | |
| **Redisson** | Apache 2.0 (Core) | ✅ OK | Gering | Sicherstellen, dass keine PRO-Features genutzt werden. |
---
## Checkliste für neue Abhängigkeiten
Bevor eine neue Bibliothek oder Infrastruktur-Komponente hinzugefügt wird, muss sie folgende Kriterien erfüllen:
1. **Lizenz-Typ:**
* Bevorzugt: Apache 2.0, MIT, BSD (3-Clause).
* Akzeptabel: MPL 2.0.
* Einzelfallprüfung: LGPL (nur als dynamische Bibliothek).
* **Verboten:** AGPL, SSPL, RSAL, BSL (sofern nicht explizit vom Architect freigegeben).
2. **Community & Governance:**
* Wird das Projekt von einer neutralen Foundation (Apache, CNCF, Linux Foundation) verwaltet?
* Gibt es eine "Single Vendor" Abhängigkeit (Risiko einer plötzlichen Lizenzänderung)?
3. **Transitive Abhängigkeiten:**
* Bringt die Bibliothek "versteckte" Copyleft-Lizenzen mit? (Check via Gradle License Plugin).
---
## TODOs & Strategische Entscheidungen
- [ ] **Migration Redis -> Valkey:** Umstellung der Docker-Images und Test der Kompatibilität.
- [ ] **Consul Review:** Jährliche Prüfung der BSL-Auswirkungen auf unser Deployment-Modell.
- [ ] **Automatisierung:** Integration eines License-Check-Plugins in den CI-Build (z.B.
`com.github.jk1.dependency-license-report`).
---
*Dieses Dokument ist Teil der "Docs-as-Code" Strategie und muss bei jeder Änderung am Tech-Stack aktualisiert werden.*
@@ -3,6 +3,7 @@
Status: April 2026
## ✅ Abgeschlossene Migrationen (Feature-Module)
- `billing-feature`: `at.mocode.frontend.features.billing` (KMP)
- `verein-feature`: `at.mocode.frontend.features.verein` (KMP)
- `nennung-feature`: `at.mocode.frontend.features.nennung` (KMP)
@@ -13,11 +14,14 @@ Status: April 2026
- `ping-feature`: `at.mocode.ping.feature` (muss noch auf `at.mocode.frontend.features.ping` vereinheitlicht werden)
## 🚧 Ausstehende Migrationen (von `at.mocode.desktop.v2` zu Features)
Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/` basieren noch auf `StoreV2` (In-Memory Mock) und sollten in KMP-Module überführt werden:
Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/` basieren noch auf
`StoreV2` (In-Memory Mock) und sollten in KMP-Module überführt werden:
1. **Onboarding**: `OnboardingScreen.kt` -> Design-System Integration erfolgt, KMP-Modul folgt.
## 🧹 Architektur-Cleanup
- [ ] `at.mocode.desktop.v2.StoreV2` entfernen, sobald alle Screens auf ViewModels und API-Repositories umgestellt sind.
- [ ] `at.mocode.desktop.v2.TurnierStoreV2` konsolidieren mit dem `turnier-feature`.
- [ ] Paketnamen vereinheitlichen: `at.mocode.ping.feature` -> `at.mocode.frontend.features.ping`.
@@ -26,6 +30,7 @@ Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/d
- [ ] `DesktopMainLayout.kt`: Die `when`-Zweige für `v2` Screens aufräumen, sobald die Module bereit sind.
## ✅ Abgeschlossen am 11.04.2026
- Migration `pferde-feature`, `reiter-feature`, `funktionaer-feature`, `veranstalter-feature`.
- Integration in `DesktopMainLayout` und `AppScreen`.
- Bereinigung der Repository-Pakete.
@@ -9,7 +9,9 @@ last_update: 2026-04-03
## Ziel und Rahmen
Dieses Dokument definiert das Synchronisations-Konzept zwischen der Compose Desktop App (Meldestelle-Zentrale) und dem Backend in einem Offline-First Szenario. Es baut auf ADR-0021 (Tenant-Isolation) und ADR-0022 (LAN-Sync mit Lamport-Uhren) auf und erweitert sie um die WAN/Backend-Synchronisation.
Dieses Dokument definiert das Synchronisations-Konzept zwischen der Compose Desktop App (Meldestelle-Zentrale) und dem
Backend in einem Offline-First Szenario. Es baut auf ADR-0021 (Tenant-Isolation) und ADR-0022 (LAN-Sync mit
Lamport-Uhren) auf und erweitert sie um die WAN/Backend-Synchronisation.
Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb des Veranstaltungsbetriebs.
@@ -18,32 +20,38 @@ Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb
1. Offline-First: Die Desktop-App ist voll funktionsfähig ohne Netzwerk; Synchronisation erfolgt opportunistisch.
2. Event-isoliert: Pro Veranstaltung eigener Datenraum (gemäß ADR-0021). Keine Vermischung von Events.
3. Einheitliches Änderungsmodell: Wiederverwendung des `SyncEvent`-Logs (ADR-0022) für Desktop↔Backend.
4. Domänen-Mastership: Klare Schreibhoheiten reduzieren Konflikte, fachliche Regeln haben Vorrang vor rein technischen Timestamps.
4. Domänen-Mastership: Klare Schreibhoheiten reduzieren Konflikte, fachliche Regeln haben Vorrang vor rein technischen
Timestamps.
5. Deterministische Konfliktauflösung: Lamport-Uhren + Regel-Matrix; keine Abhängigkeit von Systemuhren.
## Topologie & Rollen
- Backend (Zentrale Plattform):
- Master für: Stammdaten (Reiter, Pferde, Vereine, Funktionäre), Identität/Rollen, Gebührenkataloge, globale Referenzen.
- Master für: Stammdaten (Reiter, Pferde, Vereine, Funktionäre), Identität/Rollen, Gebührenkataloge, globale
Referenzen.
- Aggregations-/Archiv-Quelle nach Veranstaltungsende (finale Ergebnisse, Abrechnungen).
- Desktop (Meldestelle-Zentrale):
- Master während der Veranstaltung für: Nennungen (operativ), Startreihenfolgen, Startlisten-Status, Ergebnisse/Protokolle (falls Richter nicht direkt am Backend), Kassa-Operationen vor Ort.
- Hält lokales `SyncEvent`-Log + Snapshots (vgl. ADR-0022) und synchronisiert mit Backend, sobald Konnektivität besteht.
- Master während der Veranstaltung für: Nennungen (operativ), Startreihenfolgen, Startlisten-Status,
Ergebnisse/Protokolle (falls Richter nicht direkt am Backend), Kassa-Operationen vor Ort.
- Hält lokales `SyncEvent`-Log + Snapshots (vgl. ADR-0022) und synchronisiert mit Backend, sobald Konnektivität
besteht.
Hinweis Mehrfach-Desktops: Genau eine „Zentrale“ pro Veranstaltung besitzt Schreibhoheit (Konfig-Flag `isEventAuthority=true`). Weitere Geräte sind Replikate/Clients.
Hinweis Mehrfach-Desktops: Genau eine „Zentrale“ pro Veranstaltung besitzt Schreibhoheit (Konfig-Flag
`isEventAuthority=true`). Weitere Geräte sind Replikate/Clients.
## Datenkategorien & Mastership
| Kategorie | Master | Desktop Rechte | Backend Rechte |
|--------------------------|----------------|--------------------------------|-----------------------------------|
| Stammdaten (Actor) | Backend | Lesen, lokal „provisional“ anlegen (Temp-ID) | Vollzugriff, ID-Zuteilung, Merge |
| Veranstaltungs-Stammdaten| Backend | Lesen | Vollzugriff |
| Nennungen operativ | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Startreihenfolge/Status | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Bewertungen/Ergebnisse | Desktop/Richter| Vollzugriff (Eventzeitraum) | Lesen, Publikation/Archiv |
| Kassa/Finanzen vor Ort | Desktop | Vollzugriff | Lesen, Abgleich Summen |
| Kategorie | Master | Desktop Rechte | Backend Rechte |
|---------------------------|-----------------|----------------------------------------------|----------------------------------|
| Stammdaten (Actor) | Backend | Lesen, lokal „provisional“ anlegen (Temp-ID) | Vollzugriff, ID-Zuteilung, Merge |
| Veranstaltungs-Stammdaten | Backend | Lesen | Vollzugriff |
| Nennungen operativ | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Startreihenfolge/Status | Desktop | Vollzugriff | Lesen, Import nach Sync |
| Bewertungen/Ergebnisse | Desktop/Richter | Vollzugriff (Eventzeitraum) | Lesen, Publikation/Archiv |
| Kassa/Finanzen vor Ort | Desktop | Vollzugriff | Lesen, Abgleich Summen |
Konflikte über Kategoriegrenzen werden durch Mastership-Regeln verhindert; verbleibende Konflikte werden per Regel-Matrix gelöst.
Konflikte über Kategoriegrenzen werden durch Mastership-Regeln verhindert; verbleibende Konflikte werden per
Regel-Matrix gelöst.
## Änderungsmodell (Wiederverwendung `SyncEvent`)
@@ -71,11 +79,13 @@ data class SyncEvent(
## Lamport-Uhren & Vector-Clock (Optional)
- Primär: Lamport-Uhren wie ADR-0022. Gleichstand → lexikografisch größere `originNodeId` gewinnt (Determinismus).
- Optional für feingranulare Erkennung: Per-Aggregat Vector-Clock (`Map<nodeId, lamport>`) zur Diagnose; Entscheidungsgrundlage bleibt Lamport + Fachregeln.
- Optional für feingranulare Erkennung: Per-Aggregat Vector-Clock (`Map<nodeId, lamport>`) zur Diagnose;
Entscheidungsgrundlage bleibt Lamport + Fachregeln.
## Sync-Protokoll Desktop ↔ Backend (HTTPS)
Transport: HTTPS (HTTP/2), JSON oder Protobuf, idempotente Endpunkte. Auth: mTLS zwischen Desktop und Backend ODER OAuth2 Client Credentials + Signatur der Batch-Payload.
Transport: HTTPS (HTTP/2), JSON oder Protobuf, idempotente Endpunkte. Auth: mTLS zwischen Desktop und Backend ODER
OAuth2 Client Credentials + Signatur der Batch-Payload.
Empfohlene Endpunkte (pro `eventId`):
@@ -94,42 +104,55 @@ Idempotenz: Jeder `SyncEvent` wird durch `(eventId, originNodeId, sequenceNumber
## Konfliktauflösung
1) Strukturkonflikte (gleiches Aggregat, konkurrierende Events):
- Wenn eine Seite nicht Master ist → Event wird angenommen, aber als `PENDING_REVIEW` markiert; fachliche Entscheidung erforderlich (Backend-UI oder Desktop-Review-Queue).
- Wenn eine Seite nicht Master ist → Event wird angenommen, aber als `PENDING_REVIEW` markiert; fachliche Entscheidung
erforderlich (Backend-UI oder Desktop-Review-Queue).
- Beide Master (Sonderfälle, z. B. Ergebnisse während parallelem Backend-Fix):
- Lamport höher gewinnt.
- Gleichstand → `originNodeId`-Tiebreaker.
- Zusätzlich fachliche Heuristik optional: „Korrektur-Events“ (z. B. `ErgebnisKorrigiert`) schlagen normale `ErgebnisErfasst` bei gleichem Lamport.
- Zusätzlich fachliche Heuristik optional: „Korrektur-Events“ (z. B. `ErgebnisKorrigiert`) schlagen normale
`ErgebnisErfasst` bei gleichem Lamport.
2) Identitätskonflikte (provisionale Stammdaten):
- Desktop darf temporäre Einträge (Temp-ID `tmp-...`) erzeugen.
- Beim Push führt Backend `Upsert+Merge` aus, weist finale IDs zu und liefert `IdMapping { tmpId -> finalId }` zurück.
- Desktop ersetzt Referenzen transaktional und emittiert ein lokales `IdRemapped`-Event (kein Re-Upload nötig, außer für Diagnose).
- Desktop ersetzt Referenzen transaktional und emittiert ein lokales `IdRemapped`-Event (kein Re-Upload nötig, außer für
Diagnose).
3) Reihenfolge-/Kausalitätskonflikte:
- Bei fehlenden Vorgänger-Events antwortet Backend mit `rejected: [id]` und `requiredSinceSeq`. Desktop zieht Delta (`pull`) und wiederholt den `push`.
- Bei fehlenden Vorgänger-Events antwortet Backend mit `rejected: [id]` und `requiredSinceSeq`. Desktop zieht Delta (
`pull`) und wiederholt den `push`.
## Snapshots & Recovery
- Snapshot-Intervall: standardmäßig 100 Events pro `(aggregateType, scope)` (wie ADR-0022), für WAN-Sync zusätzlich Full-State-Snapshot pro Veranstaltung vor Event-Abschluss.
- Recovery: Desktop kann mit leerem Log starten → `snapshot/request` Full-State + `snapshotSeq` → weitere Deltas über `pull`.
- USB-Fallback (Notbetrieb): Export/Import von `sync_events` und `sync_snapshots` als verschlüsselte Archive (`.msync`). Offene Spezifikation; separater PoC.
- Snapshot-Intervall: standardmäßig 100 Events pro `(aggregateType, scope)` (wie ADR-0022), für WAN-Sync zusätzlich
Full-State-Snapshot pro Veranstaltung vor Event-Abschluss.
- Recovery: Desktop kann mit leerem Log starten → `snapshot/request` → Full-State + `snapshotSeq` → weitere Deltas über
`pull`.
- USB-Fallback (Notbetrieb): Export/Import von `sync_events` und `sync_snapshots` als verschlüsselte Archive (`.msync`).
Offene Spezifikation; separater PoC.
## Sicherheit
- Mandantentrennung: Jeder Request trägt `X-Event-Id` (ADR-0021). Backend validiert gegen `control.tenants`.
- Transport: `https` + mTLS (bevorzugt) oder `https` + OAuth2 Client Credentials. Payload-Signatur (HMAC-SHA256) empfohlen.
- Transport: `https` + mTLS (bevorzugt) oder `https` + OAuth2 Client Credentials. Payload-Signatur (HMAC-SHA256)
empfohlen.
- Integrität: `checksum` pro Event wird serverseitig geprüft; Mismatch → Reject.
- Rechte: Backend erzwingt Mastership-Regeln serverseitig; Verstöße → `PENDING_REVIEW` + Audit-Log.
## Fehlerfälle & Resilienz
- Netzwerkfehler: Exponentielles Backoff (bis 5 min), Offline-Queue unbegrenzt (bounded by disk quota), Telemetrie im UI.
- Netzwerkfehler: Exponentielles Backoff (bis 5 min), Offline-Queue unbegrenzt (bounded by disk quota), Telemetrie im
UI.
- Schema-Divergenz: `minSupportedSchema` aus `hello`; Desktop migriert vor weiterem Sync oder schaltet in Read-Only.
- Duplikate: Idempotenz-Keys verhindern Doppelverarbeitung. ACK enthält höchste verarbeitete `sequenceNumber`.
## Observability
- Metriken: `sync_push_events_total`, `sync_pull_events_total`, `sync_rejected_total`, `sync_latency_ms` (p50/p95), `offline_duration_s`.
- Metriken: `sync_push_events_total`, `sync_pull_events_total`, `sync_rejected_total`, `sync_latency_ms` (p50/p95),
`offline_duration_s`.
- Logs: pro Event `tenant`, `originNodeId`, `seq`, `aggType`, `eventType`, `result`.
- UI: Status-Anzeige (Verbunden, Getrennt, Ausstehend X), Konflikt-Review-Queue.
@@ -5,72 +5,96 @@
> **Kontext:** Phase 9 — Zeitplan & Protokollierung
## 1. Vision & Zielsetzung
Die Zeitplan-Optimierung ist das zentrale Werkzeug für die Meldestelle, um den Turnierablauf dynamisch an die Gegebenheiten vor Ort anzupassen. Ziel ist eine intuitive, visuelle Oberfläche (Kalender-Ansicht), in der Bewerbe und Abteilungen per Drag & Drop verschoben werden können, wobei das System automatisch Auswirkungen auf Folge-Bewerbe berechnet und vor Konflikten warnt.
Die Zeitplan-Optimierung ist das zentrale Werkzeug für die Meldestelle, um den Turnierablauf dynamisch an die
Gegebenheiten vor Ort anzupassen. Ziel ist eine intuitive, visuelle Oberfläche (Kalender-Ansicht), in der Bewerbe und
Abteilungen per Drag & Drop verschoben werden können, wobei das System automatisch Auswirkungen auf Folge-Bewerbe
berechnet und vor Konflikten warnt.
## 2. Fachliche Anforderungen (Use Cases)
### UC-1: Verschieben eines Bewerbs/einer Abteilung
- Ein Benutzer zieht einen Bewerb oder eine Abteilung auf eine neue Startzeit oder einen anderen Austragungsplatz.
- **System-Reaktion:**
- Neuberechnung der Endzeit basierend auf `reitdauerMinuten * starterAnzahl + besichtigungMinuten + umbauMinuten`.
- Prüfung auf Überschneidungen am selben Austragungsplatz.
- Warnung bei Konflikten (z.B. Richter-Doppelbelegung).
- Neuberechnung der Endzeit basierend auf `reitdauerMinuten * starterAnzahl + besichtigungMinuten + umbauMinuten`.
- Prüfung auf Überschneidungen am selben Austragungsplatz.
- Warnung bei Konflikten (z.B. Richter-Doppelbelegung).
### UC-2: Dynamische Zeitplan-Anpassung („Anschließend“)
- Bewerbe können als `ANSCHLIESSEND` markiert werden (`beginnZeitTyp`).
- **System-Reaktion:** Wenn der vorangehende Bewerb verschoben wird oder länger dauert, verschiebt sich der anschließende Bewerb automatisch mit.
- **System-Reaktion:** Wenn der vorangehende Bewerb verschoben wird oder länger dauert, verschiebt sich der
anschließende Bewerb automatisch mit.
### UC-3: Drag & Drop in der Startliste
- Innerhalb einer Startliste können Teilnehmer per Drag & Drop umsortiert werden.
- **System-Reaktion:** Automatische Aktualisierung der Kopfnummern (Startnummern) und Neuberechnung der individuellen Startzeiten.
- **System-Reaktion:** Automatische Aktualisierung der Kopfnummern (Startnummern) und Neuberechnung der individuellen
Startzeiten.
### UC-4: Protokollierung (Audit Log)
- Jede manuelle Änderung am Zeitplan oder der Startlisten-Reihenfolge muss protokolliert werden.
- **Grund:** Nachvollziehbarkeit bei Einsprüchen und Synchronisation zwischen verschiedenen Arbeitsplätzen (Meldestelle ↔ Richterturm).
- **Grund:** Nachvollziehbarkeit bei Einsprüchen und Synchronisation zwischen verschiedenen Arbeitsplätzen (
Meldestelle ↔ Richterturm).
## 3. Datenmodell-Erweiterungen & Logik
### 3.1 Erweiterung `Bewerb` & `Abteilung`
Das bestehende Modell in `entries-domain` deckt bereits viele Felder ab. Für die Optimierung präzisieren wir:
- **`Umbauzeit`:** Zeit zwischen zwei Abteilungen oder Bewerben.
- **`Pausen`:** Geplante Unterbrechungen (z.B. Mittagspause, Platzpflege) werden als spezielle „Blocker-Events“ im Zeitplan geführt.
- **`Pausen`:** Geplante Unterbrechungen (z.B. Mittagspause, Platzpflege) werden als spezielle „Blocker-Events“ im
Zeitplan geführt.
- **`BesichtigungsBlock` (NEU):** Eigenständiges Objekt für Parcoursbesichtigungen.
- Kann mit mehreren Bewerben/Abteilungen verknüpft werden (Cross-Competition Inspection).
- Unterstützt Typen: `ZU_FUSS` (Standard) und `ZU_PFERD` (Spezialfall für Springpferde bis 110cm gemäß ÖTO).
- Validierung: Mindestens 5 Min. Puffer vor dem ersten Start (ÖTO §43).
- Kann mit mehreren Bewerben/Abteilungen verknüpft werden (Cross-Competition Inspection).
- Unterstützt Typen: `ZU_FUSS` (Standard) und `ZU_PFERD` (Spezialfall für Springpferde bis 110cm gemäß ÖTO).
- Validierung: Mindestens 5 Min. Puffer vor dem ersten Start (ÖTO §43).
### 3.2 Zeitberechnungs-Algorithmus (Präzisierung)
Die Logik in `StartlistenService.berechneStartzeiten` wird erweitert:
1. **Basis:** `Startzeit` der Abteilung.
2. **Vorlauf:** `besichtigungMinuten`.
3. **Starter-Loop:**
- `individuelleStartzeit = aktuelleZeit`.
- `aktuelleZeit += bewerb.reitdauerMinuten`.
- *Neu:* Berücksichtigung von festen Pausen nach X Startern (z.B. 10 Min. Pause alle 20 Starter).
- `individuelleStartzeit = aktuelleZeit`.
- `aktuelleZeit += bewerb.reitdauerMinuten`.
- *Neu:* Berücksichtigung von festen Pausen nach X Startern (z.B. 10 Min. Pause alle 20 Starter).
4. **Nachlauf:** `umbauMinuten` am Ende der Abteilung/des Bewerbs.
### 3.3 Drag & Drop Logik (Frontend & Backend)
- **Frontend (Compose Desktop):**
- Implementierung eines `DraggableBewerbItem`.
- Visuelle Darstellung von Konflikten (Rote Markierung bei Überlappung).
- Implementierung eines `DraggableBewerbItem`.
- Visuelle Darstellung von Konflikten (Rote Markierung bei Überlappung).
- **Backend (API):**
- Neuer Endpunkt `PATCH /bewerbe/{id}/zeitplan` für schnelle Updates.
- Validierung der neuen Zeiten gegen den `austragungsplatzId` und `richterEinsaetze`.
- Neuer Endpunkt `PATCH /bewerbe/{id}/zeitplan` für schnelle Updates.
- Validierung der neuen Zeiten gegen den `austragungsplatzId` und `richterEinsaetze`.
## 4. Konflikt-Management
Das System arbeitet nach dem Prinzip **„Warnen statt Blockieren“** (ADR-0016):
- **Harte Fehler:** Nur bei technischer Unmöglichkeit (z.B. Datum in der Vergangenheit bei Live-Betrieb).
- **Warnungen:**
- Überlappung auf dem Platz.
- Richter hat gleichzeitig Einsatz in anderem Bewerb.
- Zeitunterschreitung für Reiter (Reiter startet in zwei kurz aufeinanderfolgenden Bewerben).
- Überlappung auf dem Platz.
- Richter hat gleichzeitig Einsatz in anderem Bewerb.
- Zeitunterschreitung für Reiter (Reiter startet in zwei kurz aufeinanderfolgenden Bewerben).
## 5. Synchronisation (Offline-First)
Änderungen am Zeitplan erzeugen `SyncEvents` (gemäß ADR-0022).
- **Lamport-Uhren:** Stellen sicher, dass bei gleichzeitigen Änderungen an zwei Laptops die zeitlich spätere Änderung (oder die mit höherer Priorität) gewinnt.
- **Echtzeit-Update:** Über WebSockets werden Zeitplan-Änderungen sofort an alle verbundenen Clients (z.B. Anzeige-Monitor, Richter-Tablet) gepusht.
- **Lamport-Uhren:** Stellen sicher, dass bei gleichzeitigen Änderungen an zwei Laptops die zeitlich spätere Änderung (
oder die mit höherer Priorität) gewinnt.
- **Echtzeit-Update:** Über WebSockets werden Zeitplan-Änderungen sofort an alle verbundenen Clients (z.B.
Anzeige-Monitor, Richter-Tablet) gepusht.
## 6. Nächste Schritte
1. **Backend:** ✅ Implementiert (BewerbService, API, Zeitberechnungs-Pausen).
2. **Frontend:** Prototyping der Kalender-Ansicht mit Compose Desktop.
3. **QA:** Test-Szenarien für komplexe Verschiebungen (Kettenreaktionen bei „Anschließend“).
@@ -5,42 +5,63 @@
> **Kontext:** Zeitplan-Optimierung & Praxis-Szenarien
## 1. Parcoursbesichtigung zu Pferd
Die Aussage des Users wurde geprüft und bestätigt.
### 1.1 Regelwerks-Referenz (ÖTO 2026)
Gemäß **ÖTO Teil B, § 43 (Abweichungen)** gilt:
- **Normalfall:** Parcoursbesichtigung erfolgt zu Fuß.
- **Springpferde- & Jungpferdeprüfungen (bis 110 cm):** Eine Besichtigung **zu Pferd im Schritt** kann von der Richtergruppe erlaubt werden.
- **Zweck:** Junge, unerfahrene Pferde sollen stressfrei an optische Reize (Fangständer, Farben, Unterbauten) herangeführt werden.
- **Springpferde- & Jungpferdeprüfungen (bis 110 cm):** Eine Besichtigung **zu Pferd im Schritt** kann von der
Richtergruppe erlaubt werden.
- **Zweck:** Junge, unerfahrene Pferde sollen stressfrei an optische Reize (Fangständer, Farben, Unterbauten)
herangeführt werden.
### 1.2 Organisatorische Implikationen
- **Dauer:** Die Besichtigung zu Pferd benötigt oft etwas mehr Zeit für die Koordination am Einlass (15-20 Min. sind praxisnah).
- **Sicherheit:** Da Pferde im Parcours sind, während andere Reiter eventuell noch draußen warten, muss der Zeitplan einen Puffer von mindestens **5 Minuten** zwischen Ende Besichtigung und erstem Start vorsehen (ÖTO Vorschrift).
- **Dauer:** Die Besichtigung zu Pferd benötigt oft etwas mehr Zeit für die Koordination am Einlass (15-20 Min. sind
praxisnah).
- **Sicherheit:** Da Pferde im Parcours sind, während andere Reiter eventuell noch draußen warten, muss der Zeitplan
einen Puffer von mindestens **5 Minuten** zwischen Ende Besichtigung und erstem Start vorsehen (ÖTO Vorschrift).
## 2. Zusammengelegte Besichtigungen (Cross-Competition Inspection)
In der Praxis üblich, wenn der Parcours für aufeinanderfolgende Bewerbe identisch bleibt.
### 2.1 Szenario
- **Bewerb A:** Springpferdeprüfung 105cm (Besichtigung zu Pferd erlaubt).
- **Bewerb B:** Standardspringprüfung 105cm (Besichtigung zu Fuß).
- **Lösung:** Eine gemeinsame Besichtigungszeit vor Bewerb A.
### 2.2 Regelwerks-Konformität
- Es gibt kein Verbot für gemeinsame Besichtigungen, solange die Teilnehmer beider Bewerbe die Möglichkeit haben, den Parcours regelkonform zu besichtigen.
- **Wichtig:** Wenn Bewerb B erst 2 Stunden später startet, muss für Teilnehmer von Bewerb B theoretisch eine zweite Besichtigungsmöglichkeit (oder ein "Refresh") angeboten werden, falls der Parcours zwischenzeitlich verändert wurde. Wenn er identisch bleibt, reicht die einmalige Bekanntgabe.
- Es gibt kein Verbot für gemeinsame Besichtigungen, solange die Teilnehmer beider Bewerbe die Möglichkeit haben, den
Parcours regelkonform zu besichtigen.
- **Wichtig:** Wenn Bewerb B erst 2 Stunden später startet, muss für Teilnehmer von Bewerb B theoretisch eine zweite
Besichtigungsmöglichkeit (oder ein "Refresh") angeboten werden, falls der Parcours zwischenzeitlich verändert wurde.
Wenn er identisch bleibt, reicht die einmalige Bekanntgabe.
## 3. Anforderungen für die Software (Zeitplan-Modul)
### 3.1 Datenmodell
- `Abteilung` oder `Bewerb` benötigt ein Flag `besichtigungZuPferdErlaubt` (Boolean).
- `BesichtigungsBlock` als eigenständiges Entitätsobjekt im Zeitplan, das mit **mehreren** Bewerben/Abteilungen verknüpft werden kann.
- `BesichtigungsBlock` als eigenständiges Entitätsobjekt im Zeitplan, das mit **mehreren** Bewerben/Abteilungen
verknüpft werden kann.
### 3.2 Validierung & Warnungen
- **Warnung:** Wenn ein Besichtigungsblock mit "zu Pferd" markiert ist, aber ein verbundener Bewerb (z.B. L-Springen) dies laut ÖTO normalerweise nicht vorsieht (Diskretionsspielraum der Richter).
- **Puffer-Check:** Automatische Prüfung, ob zwischen `Ende Besichtigung` und `Start Erster Reiter` mindestens 5 Minuten liegen.
- **Warnung:** Wenn ein Besichtigungsblock mit "zu Pferd" markiert ist, aber ein verbundener Bewerb (z.B. L-Springen)
dies laut ÖTO normalerweise nicht vorsieht (Diskretionsspielraum der Richter).
- **Puffer-Check:** Automatische Prüfung, ob zwischen `Ende Besichtigung` und `Start Erster Reiter` mindestens 5 Minuten
liegen.
## 4. Fazit für Architect & Entwickler
Die "Besichtigung zu Pferd" ist ein valider Spezialfall für Springpferdeprüfungen. Die Software muss erlauben, Besichtigungszeiten flexibel vor einen oder mehrere Bewerbe zu lagern und den Typ (Fuß/Pferd) zu kennzeichnen.
Die "Besichtigung zu Pferd" ist ein valider Spezialfall für Springpferdeprüfungen. Die Software muss erlauben,
Besichtigungszeiten flexibel vor einen oder mehrere Bewerbe zu lagern und den Typ (Fuß/Pferd) zu kennzeichnen.
---
*Geprüft durch den 📜 ÖTO/FEI Rulebook Expert am 11.04.2026*
@@ -0,0 +1,62 @@
# 🤖 Konzept: Status-Automat für Nennungen & Zeitplan-Synchronisation
Dieses Dokument spezifiziert die Logik des Status-Automaten für Nennungen (Sprint C-1) und dessen Auswirkungen auf den
dynamischen Zeitplan.
## 1. Status-Definitionen (NennStatusE)
Basierend auf `core-domain/Enums.kt`:
| Status | Bedeutung | Auswirkung auf Zeitplan |
|:-------------------|:--------------------------------------------------|:--------------------------------------------------------|
| `EINGEGANGEN` | Nennung wurde erstellt (Initialzustand) | Belegt Zeitslot (basierend auf `reitdauerMinuten`) |
| `BESTAETIGT` | Meldestelle hat Nennung geprüft | Belegt Zeitslot |
| `NACHNENNUNG` | Nennung nach Nennschluss | Belegt Zeitslot (ggf. am Ende der Liste) |
| `TRANSFERIERT` | Nennung wurde auf anderes Paar übertragen | **Inaktiv** (Original-Eintrag wird durch neuen ersetzt) |
| `ZURUECKGEZOGEN` | Reiter hat abgemeldet (vor Startlistenerstellung) | **Inaktiv** (Slot wird frei) |
| `GESTARTET` | Paar ist in die Prüfung eingeritten | Startzeitpunkt fixiert, Folgestarts ggf. anpassen |
| `NICHT_ANGETRETEN` | Paar ist zum Startzeitpunkt nicht erschienen | **Zeitslot verfällt** oder Folgestarts rücken nach |
## 2. Status-Übergänge & Validierung
### 2.1 Gültige Übergänge (Beispiele)
- `EINGEGANGEN` -> `BESTAETIGT` (Normalfall)
- `EINGEGANGEN` -> `ZURUECKGEZOGEN` (Abmeldung)
- `BESTAETIGT` -> `TRANSFERIERT` (Reitertausch)
- `BESTAETIGT` -> `GESTARTET` (Während des Turniers)
### 2.2 Side-Effects (Side-Effect-Engine)
Wenn sich der Status einer Nennung ändert, müssen folgende Systeme informiert werden:
1. **Billing-Service:** Bei `ZURUECKGEZOGEN` ggf. Stornogebühren prüfen. Bei `TRANSFERIERT` Guthaben übertragen.
2. **Startlisten-Service:** Bei `ZURUECKGEZOGEN` nach Veröffentlichung der Startliste -> Eintrag als
`istGestrichen = true` markieren.
3. **Zeitplan-Optimierung:** Bei `NICHT_ANGETRETEN` -> Alle folgenden Startzeiten rücken um `reitdauerMinuten` nach
vorne (sofern im Kalender-Modus "Dynamisch" aktiv ist).
## 3. Dynamische Zeitplan-Anpassung (C-1 Extension)
Der `StartlistenService` muss eine Methode `aktualisiereZeitplanNachStatusAenderung` erhalten:
- **Szenario A (Nicht angetreten):** Wenn Nennung X `NICHT_ANGETRETEN` wird, rücken alle folgenden Nennungen in der
Abteilung nach vorne.
- **Szenario B (Verspätung):** Wenn Nennung X `GESTARTET` wird, aber 2 Minuten später als geplant, verschieben sich alle
Folgetermine um +2 Minuten (Kettenreaktion).
### Puffer-Regel (ÖTO-Konformität)
- Eine dynamische Verschiebung nach *vorne* darf nie dazu führen, dass ein Reiter vor seiner ursprünglich kommunizierten
Startzeit (oder einem definierten Puffer-Zeitraum von z.B. 15 Minuten) starten muss, ohne dass dies explizit bestätigt
wurde.
## 4. Implementierungs-Leitfaden für Backend (C-1)
1. Erweiterung von `NennungUseCases.statusAendern` um Aufrufe der Side-Effect-Handler.
2. Implementierung des `NennungStatusListener` in `entries-service`.
3. Anbindung an den `StartlistenService` zur Zeitre-Kalkulation.
---
**Status:** Entwurf (Lead Architect)
**Datum:** 11. April 2026
+85 -360
View File
@@ -2,12 +2,12 @@
type: Roadmap
status: ACTIVE
owner: Lead Architect
last_update: 2026-04-21
last_update: 2026-05-06
---
# MASTER ROADMAP: Meldestelle
🏗️ **[Lead Architect]** | 20. April 2026
🏗️ **[Lead Architect]** | 30. April 2026
**Strategisches Ziel:**
Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP).
@@ -17,7 +17,7 @@ Vollständige Self-Hosted Infrastruktur (Gitea, Pangolin, Zora). Datensouveräni
- Desktop-App ist der primäre Client (Compose Desktop, KMP) — „Desktop-First“ gilt für UX und Architektur.
- Offline-First Betrieb mit lokaler Persistenz und opportunistischer Synchronisation.
**Aktueller technischer Stand (30.03.2026):**
**Aktueller technischer Stand (30.04.2026):**
* **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen.
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
* **CI/CD:** ✅ Gitea Actions mit ARM64-Runner (VM 102) aktiv. Docker-Publish Pipeline grün.
@@ -51,403 +51,128 @@ und über definierte Schnittstellen kommunizieren.
---
## 1. Abgeschlossene Phasen
## 1. Abgeschlossene Phasen (Verifiziert)
### PHASE 1: Documentation Cleanup ✅ ABGESCHLOSSEN
*Ziel: Eine einzige, vertrauenswürdige Quelle der Wahrheit (SSOT) schaffen.*
### PHASE 1: Domain-Design & Ubiquitous Language ✅
#### 🧹 Agent: Curator
* [x] **Archivierung:** Veraltete Docs (Cloudflare, GitHub-Workflows, alte Roadmaps) nach `docs/_archive/` verschoben.
* [x] **Konsolidierung:** `Zora_System_Architektur.md` als zentrale Infrastruktur-Doku etablieren.
* [x] **Struktur:** `docs/` Ordner aufräumen (unnötige Root-Files in Unterordner).
* [x] **Index:** `README.md` im Root als Einstiegspunkt aktualisieren.
*Status: Fachliche Grundlage vorhanden.*
### PHASE 2: Infrastructure Hardening ✅ ABGESCHLOSSEN
*Ziel: Stabilisierung der neuen Self-Hosted Umgebung.*
* [x] **DDD-Analyse:** 6 Bounded Contexts (SCS-Architektur) definiert.
* [x] **Terminologie:** `Veranstaltung``Turnier` gemäß ÖTO § 2 Abs. 1 festgelegt.
* [x] **Ubiquitous Language:** Offizielle Domänen-Terminologie erstellt.
#### 🐧 Agent: DevOps Engineer
### PHASE 2: Infrastruktur & ZNS-Importer (Prototyp) ✅
* [x] **Keycloak Fix:** Verbindungsprobleme innerhalb des Docker-Netzwerks behoben (Alias `auth.mo-code.at`).
* [x] **Backup Strategy:** Automatisierte Backups für Gitea & Datenbanken auf Zora (`config/scripts/backup.sh`).
* [x] **Monitoring:** Prometheus/Grafana Dashboard für Zora finalisiert (`dc-ops.yaml`).
* [x] **Deployment:** Git-basiertes Deployment-Skript (`config/scripts/deploy.sh`) erstellt.
*Status: Grundgerüst steht, Performance-Probleme bekannt.*
### PHASE 3: Domain-Design & Ubiquitous Language ✅ ABGESCHLOSSEN
*Ziel: Fachliche Grundlage für die Implementierung schaffen.*
#### 🏗️ Agent: Lead Architect
* [x] **DDD-Analyse:** 6 Bounded Contexts (SCS-Architektur) definiert und priorisiert.
* [x] **Terminologie:** `Veranstaltung``Turnier` gemäß ÖTO § 2 Abs. 1 festgelegt (ADR).
* [x] **Design-Baseline:** Vision_03 (Figma) als offizieller Design-Baseline festgelegt.
* [x] **Technologie:** Desktop-First-Strategie mit KMP/Compose Desktop beschlossen.
#### 📜 Agent: ÖTO/FEI Rulebook Expert
* [x] **Ubiquitous Language:** Offizielle Domänen-Terminologie mit ÖTO-Referenzen erstellt.
* [x] **Abteilungs-Schwellenwerte:** Alle Trennungs-Schwellenwerte (§ 39 + spartenspezifisch) dokumentiert.
`docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md`
#### 👷 Agent: Backend Developer
* [x] **Enums:** `SparteE`, `TurnierkategorieE`, `VeranstaltungsTypE`, `LizenzKlasseE`, `NennungsStatusE`,
`StartwunschE` ÖTO-konform.
* [x] **Domain-Modelle:** `DomReiter` (actor-context), `DomNennung`, `DomNennungsTransfer` (registration-context).
* [x] **Modul:** `entries-domain` als KMP-Modul aufgesetzt und in `settings.gradle.kts` registriert.
* [x] **ZNS-Parser:** Grundsätzliche Fähigkeit zum Parsen von ZNS-Daten (Reiter, Pferde, Vereine, Funktionäre).
* [x] **UI-Gerüst:** Navigation und Dialog-Hüllen in Compose Desktop vorhanden.
* [x] **Plan-B:** Rudimentärer Mail-Service für Nennungs-Versand (funktional).
---
## 2. Aktuelle Phase
## 2. Der neue Weg: Fachliche Realität (Roadmap 2026)
### PHASE 4: MVP-Implementierung ✅ ABGESCHLOSSEN
Fokus: Physische Implementierung der Turnier-Hierarchie und technisches Onboarding.
*Ziel: Lauffähiger MVP für `registration-context` und `actor-context` (P1-Contexts).*
### MEILENSTEIN 0: Technische Geräte-Initialisierung (Prio 1) 🚧 IN ARBEIT (STABILISIERUNG)
#### 🧐 Agent: QA Specialist
*Ziel: Ein stabiles, offline-fähiges technisches Fundament für die Desktop-App.*
* [x] **Actor Context Stabilization:** Funktionär-Datenmodell (Richter/Parcoursbauer) auf professionelle Master-Daten-Referenzierung umgestellt und mit Reiter-Daten verknüpft (Import-Idempotenz via `satzNummer`). Redundante Kontakt-/Adressdaten entfernt. Alle ZNS-Import-Tests (9/9) stabilisiert und verwaiste Parser-Reste entfernt.
* [x] **Masterdata Standardization:** Bereinigung und Standardisierung der Masterdaten-Tabellen (Mehrzahl-Konvention: `bundeslaender`, `funktionaers_qualifikationen`, `reit_lizenzen`, `turnier_klassen`).
* [x] **ÖTO Data Seeding:** Umfassende Seeder für Funktionärs-Qualifikationen, Turnierklassen und Turnier-Sparten gemäß ÖTO implementiert. Einführung der Tabelle `turnier_sparten`.
* [x] **ZNS-Import Optimization:** Automatische Verknüpfung von Funktionären mit Reitern (Reihenfolge: VEREIN -> LIZENZ -> PFERDE -> RICHT). `ZnsImportService` für sequentielle Imports in Tests gehärtet.
* [x] **Service Stability:** Port-Konflikt des `masterdata-service` (Spring Management Port 8081 vs. Gateway) durch Umzug auf Port 8086 und explizite Bind-Adressen (Spring: 127.0.0.1, Ktor: 0.0.0.0) dauerhaft gelöst.
* [x] **Documentation:** `CHANGELOG.md` aktualisiert und Port-Konfiguration in `application.yml` dokumentiert.
→ Note: `IdempotencyApiIntegrationTest` bleibt vorerst @Disabled, da das Hochfahren des Spring-Contexts in der
Testumgebung blockiert (unabhängig vom Plugin).
→ Task: Integration-Test Umgebung (Port-Binding/Server-Lifecycle) für `masterdata-service` untersuchen.
* [x] **App-Icons (PNG/ICO):** Implementiert (Fix für Build-Fehler).
* [x] **Docker-Fix:** "services must be a mapping" behoben (dc-gui.yaml).
* [x] **Chat-Funktion (Desktop):** MVP implementiert (Navigation & UI).
* [x] **Geführte Discovery ("Zero-Config"):** Master-Namen statt IPs, "Wait-State" für Clients.
* [x] **Native FileDialogs:** Stabile Pfad-Auswahl für Plan-USB auf allen Systemen.
* [x] **Handshake-Feedback:** Visuelle Signalisierung des Verbindungsstatus (Grün/Rot).
* [x] **Client-Konfiguration:** Master kann nun Clients in der UI hinzufügen und bearbeiten.
* [x] **Master-UX:** Konfiguration beim Start nicht mehr zwangsgesperrt.
* [x] **Cross-Packaging (Conveyor):** Windows-Build auf Linux-CI ermöglicht (x64-Abhängigkeit identifiziert).
* [x] **Build-Performance:** WASM standardmäßig deaktiviert, um Desktop-Build-Zeiten zu reduzieren (11.05.2026).
* [ ] **PoC Verifikation:** 🔴 **BLOCKIERT** (Log 483: ARM64-Runner inkompatibel mit Conveyor-Binary; Workflow auf
manuell gesetzt).
#### 🏗️ Agent: Lead Architect
### MEILENSTEIN 1: Die Basis-Hierarchie (Prio 1) ⚪ GEPLANT
* [x] **ADRs vervollständigen:** Bounded Context Mapping und Context Map dokumentieren.
`docs/01_Architecture/adr/0014-bounded-context-mapping-de.md`
`docs/01_Architecture/adr/0015-context-map-de.md`
* [x] **API-Design:** Schnittstellen zwischen den Contexts definieren (Anti-Corruption Layer).
`docs/01_Architecture/adr/0016-api-design-acl-de.md`
* [x] **ÖTO-Validation-Seeds:** Seed-Daten für Lizenz-Matrix und Altersklassen finalisiert (V008).
*Ziel: Veranstaltung -> Turnier -> Bewerb/Abteilung physisch anlegen und speichern.*
#### 👷 Agent: Backend Developer
* [ ] **Persistenz-Layer:** Implementierung der lokalen Speicherung für alle Ebenen der Hierarchie.
* [ ] **Turnier-Wizard (Echt):** Umstellung des Wizards von `println`-Dummies auf echte Datenbank-Transaktionen.
* [ ] **Validierung:** Sicherstellen, dass Pflichtfelder (Turniernummer, Sparte) korrekt erfasst werden.
* [x] **ZNS-Importer:** Support für Richter-Import (RICHT01.DAT) und Reiter-Refactoring (LIZENZ01.DAT) vervollständigt. ✓
* [x] **Masterdata:** Qualifikations-System und Personen-Referenzen (Vereine, Bundesländer, Nationen) stabilisiert (Consul & MasterdataSeeder). ✓
* [x] **Infrastruktur:** Service-Discovery (Consul) für alle Microservices (incl. Masterdata) aktiviert.
* [x] **Infrastruktur:** Bean-Definitionen und Dependency-Injection im `zns-import-service` bereinigt.
* [x] **Database:** Initialisierung der Funktionärs-Tabellen stabilisiert (PSQLException Fix).
* [x] **`actor-context`:** Domain-Modelle für `Pferd`, `Funktionaer`, `Verein` implementiert.
* [x] **`registration-context`:** `DomBewerb`, `DomAbteilung`, `DomStartliste` implementiert.
* [x] **`event-management-context`:** `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementiert.
* [x] **Persistenz:** Repository-Interfaces und erste DB-Migrationen (Flyway/Liquibase).
* [x] **API:** REST-Endpunkte für Nennungs-Workflow (Kern-Use-Cases).
* [x] **Infrastruktur-Stabilisierung:** Kompilierfehler in `masterdata-infrastructure` behoben.
* [x] **Identity-Schnittstellen:** Endpunkte für ZNS-Linking über `identity-service` bereitgestellt.
### MEILENSTEIN 2: ZNS-Performance & Daten-Qualität (Prio 2)
#### 🎨 Agent: Frontend Expert
*Ziel: Import der ZNS.zip in < 2 Minuten statt 30+ Minuten.*
* [x] **KMP/Compose Desktop:** Projektstruktur aufgesetzt (`frontend/shells/meldestelle-desktop`).
* [x] **Navigation:** Sidebar-Navigation gemäß Vision_03 implementiert (Veranstaltungen, Reiter, Pferde, Funktionäre,
Meisterschaften, Cups).
* [x] **Nennungs-Screen:** `TurnierDetailScreen` integriert `NennungsMaske` aus `nennung-feature` (Bewerbe-Tab ⭐).
* [ ] **Batch-Processing:** Umstellung des `ZnsImportService` auf Batch-Inserts (JDBC/Exposed).
* [ ] **Fortschritts-Anzeige:** Reale Rückmeldung über den Import-Status in der UI.
#### 📜 Agent: ÖTO/FEI Rulebook Expert
### MEILENSTEIN 3: Richtverfahren & Bewerbs-Konfiguration (Prio 3)
* [x] **Voltigieren (CVN):** Abteilungs-Trennungsregeln aus B-Teil § 400 ff. ausgewertet (offene Frage #3 teilweise
geklärt).
→ B IV enthält keine eigenen Regeln verweist auf OEPS-Reglement CVN. § 39 Abs. 1 gilt nicht für CVN. § 39 Abs.
2 (> 80 Starter) gilt als Fallback.
`docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` (Abschnitt 2.6)
* [x] **Fahren (CAN):** Starter-Schwellenwerte jenseits der Reitertreffen-Regel geklärt (offene Frage #4 teilweise
geklärt).
→ B VII enthält keine eigenen Regeln verweist auf OEPS-Reglement „Turnierordnung für Gespanne". § 39 Abs. 1 gilt
nicht für CAN. § 39 Abs. 2 (> 80 Starter) gilt als Fallback. Einzige gesicherte Lizenzregel: § 850 Abs. 9 (F1+ bei
Fahrertreffen).
`docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` (Abschnitt 2.5)
* [x] **Warn-Logik:** Spezifikation der `competition-context` Warn-Logik für Abteilungs-Schwellenwerte.
`docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md`
*Ziel: Bewerbe mit fachlich korrekten Regeln (ÖTO) anlegen.*
#### 🧹 Agent: Curator & Lead Architect (ZNS-Importer)
* [x] **ZNS-Importer (MVP) Phase 1 & 2:** `core:zns-parser` (KMP), `ZnsLegacyParsers` (alle 4 Dateitypen, CP850),
`ZnsImportService` (Orchestrator, ZIP in-memory, Upsert), Unit-Tests grün.
→ Detaillierte Planung: `docs/01_Architecture/Roadmap_ZNS_Importer.md`
* [x] Backend-Infrastruktur & CP850 Parser (Phase 1 Parser/Modul)
* [x] Domain-Mapping & Upsert in DB (Phase 2)
* [x] REST-API & Job-Management (Phase 1 Controller/Job-Registry)
* [x] Frontend-Integration mit File-Picker & Status-Polling (Phase 3)
* [ ] **Richtverfahren-Engine:** Validierungslogik für verschiedene Richtverfahren (Fehler/Zeit, Wertnoten).
* [ ] **Abteilungs-Logik:** Automatische Teilungsvorschläge gemäß ÖTO § 39.
---
## 3. Initiative: Wizard-Orchestrator & Offline-Drafts (Q2/Q3 2026)
## 3. Zukünftige Module (Status: Geplant / Vision)
🏗️ Verantwortlich: Lead Architect · 🎨 Frontend · 🖌️ UI/UX · 👷 Backend · 🧐 QA · 🧹 Curator
*Diese Module existieren derzeit nur als Konzepte oder leere Hüllen.*
Ziel: Konsolidierung aller „Wizards“ auf ein deklaratives Orchestrierungs-Framework (Graph + Guards + Effects), vereinheitlichte Validierung und Offline-Draft-Fähigkeit inkl. DeltaSync. Desktop-first, tastaturbedienbar, testbar.
### 3.1 Kernbausteine
- Orchestrator Runtime & DSL: `StepId`, `WizardContext`, `WizardState`, `Guard`, `Transition`, `StepEffects`.
- WizardScaffold: Breadcrumb, Kontext-Chips, Footer mit Hotkeys (Enter/Shift+Enter/Alt+S), Fehler-Summary.
- DraftStore: Autosave pro Step (`onLeave`), Resume, `flowVersion`, Konfliktanzeige.
- DevTools: strukturierte Transition-Logs, Graph-Export (DOT/PlantUML).
Referenzen/Dokumente:
- ADR0025: Wizard-Orchestrator (StateMachine, DSL, Guards, Effects) → `docs/01_Architecture/adr/0025-wizard-orchestrator-de.md`
- ADR0026: Step-Validation-Policy (sync vs. async, Fehlersichtbarkeit, Hotkeys) → `docs/01_Architecture/adr/0026-validation-policy-de.md`
- ADR0027: Draft-Domain & DeltaSync (Versionierung, Konfliktlösung, Idempotenz) → `docs/01_Architecture/adr/0027-draft-domain-and-delta-sync-de.md`
- Reference: WizardDSL README (Beispiel-Flow Event) → `docs/01_Architecture/Reference/Wizard-DSL-README.md`
### 3.2 Migrationsstrategie (Strangler)
1) Parallelbetrieb: Neuer Orchestrator in `frontend/core/wizard`; bestehende VMs delegieren schrittweise.
2) Inkrement 1: EventFlow zunächst 2 Steps (ZNS_CHECK, VERANSTALTER_SELECTION), dann alle 6 Steps.
3) FeatureFlag `WizardRuntimeEnabled` für risikoarmen Rollout.
### 3.3 Phasenplanung (Auszug)
- Phase 1 (Core & Tooling, 23 Wochen): Runtime/DSL, DevLogs, GraphExport, ScaffoldMVP, UnitTests.
- Phase 2 (EventFlow, 23 Wochen): `EventStep/Acc/Guards`, FlowDSL, VMDelegation, Validierung, Autosave/Resume.
- Phase 3 (Backend, 24 Wochen): Draft-/ValidateAPIs, OfflineQueue, DeltaSync für Turniere.
- Phase 4 (Skalierung, 610 Wochen, parallel): Weitere Flows je Bounded Context.
- Phase 57 (23 + 12 + 12 Wochen): UXHärtung, Observability/RolloutGates, Stabilisierung & Abschaltung Altlogik.
Grobe Gesamtdauer: 1729 Wochen je nach Parallelisierung.
### 3.4 Akzeptanzkriterien (DoD Initiative)
- Alle priorisierten Flows laufen über Orchestrator; Next/Back/History deterministisch; GraphExport aktuell.
- DraftStore produktiv; Resume deterministisch; DeltaSync idempotent; Konflikte nichtblockierend sichtbar.
- ValidierungsPolicy konsistent; TastaturBedienung vollständig; PerformanceGates eingehalten.
- ADR0025/0026/0027 veröffentlicht; WizardDSLReference vorhanden; CI grün; Metriken/Alerts aktiv.
### 3.5 10TageStartplan
- Tag 12: Runtime/DSLSkelett, ScaffoldMVP, FeatureFlag, README Skeleton.
- Tag 3: EventStep/Acc/Guards, EventFlow (2 Steps), VMDelegation minimal.
- Tag 4: Tests Runtime/Guards, GraphExport, DevLogs.
- Tag 56: META_DATA/ANSPRECHPERSON migrieren, ValidierungsAPI, FehlerSummary.
- Tag 7: DraftStore lokal (Autosave/Resume), PropertyTest Resume.
- Tag 8: TURNIER_ANLAGE einbetten, Sync via `onComplete`.
- Tag 9: SUMMARY + Finalisierung, Offload in OfflineQueue (Stub).
- Tag 10: ADR0025/0026/0027 Review+Merge; JournalEintrag.
Journal: `docs/99_Journal/2026-04-21_Wizard-Orchestrator_Roadmap_Anchoring.md`
* **Nennungs-Management:** Erfassung von Nennungen gegen den ZNS-Datenbestand.
* **Zeitplan:** Dynamische Zeitplanung (Drag & Drop).
* **Ergebnisse:** Erfassung von Wertungen und Platzierungsberechnung.
* **Abrechnung:** Vollständiger `billing-context`.
---
## 3. Aktuelle Phase
## 4. Archiv der fiktiven Meilensteine (Reality-Check am 28.04.2026)
### Progress Checkpoint 2026-04-21 (Wizard-Orchestrator Initiative)
*Die folgenden Einträge wurden in früheren Sitzungen als "Abgeschlossen" markiert, entsprachen aber nicht dem realen
Code-Stand.*
- Core/DSL: angelegt in `frontend/core/wizard` (Runtime, DSL), erste Tests grün.
- UI: `WizardScaffold` (MVP) + Hotkeys-Wrapper (Enter/Shift+Enter/Alt+S) vorhanden.
- Feature-Integration: Veranstaltungs-Wizard hinter Flag teilweise delegiert.
- Drafts: InMemory DraftStore (Autosave/Resume Hooks) angebunden.
- DI: Koin-Parameterübergabe für `EventWizardViewModel` vereinheitlicht.
- Flag: `WizardRuntimeEnabled = false` (Standard AUS; Dev-Verprobung manuell).
<details>
<summary>Frühere (fiktive) Meilensteine anzeigen</summary>
Nächste Schritte (Kurz): Tests für `needsContactPerson` (beide Zweige), VMDelegation für weitere Steps, FooterFehlerSummary, persistenter DraftStore, DevOverlay.
### PHASE 4: MVP-Implementierung (Früherer Status: Abgeschlossen)
### PHASE 5: P2-Contexts & Integration ✅ ABGESCHLOSSEN
* [ ] ZNS-Import Optimierung (Batching) -> In MEILENSTEIN 2 verschoben.
* [ ] `event-management-context` Implementierung -> In MEILENSTEIN 1 verschoben.
*Ziel: `competition-context` und `event-management-context` implementieren.*
### PHASE 5-13 (Früherer Status: Abgeschlossen/In Arbeit)
* [x] **`competition-context`:** Bewerbe, Startlisten, Ergebnisse, Abteilungs-Warn-Logik.
* [x] **`event-management-context`:** Veranstaltungs- und Turnier-Verwaltung, Ausschreibungs-Generator.
* [x] **ZNS-Integration:** Schnittstelle zum Zentralen Nennungs-System (A-Satz / B-Satz).
* [x] **Offline-Sync:** Offline-First-Strategie für Desktop-App implementieren.
* [ ] `competition-context` (Bewerbe, Startlisten) -> Fachlogik fehlt weitgehend.
* [ ] `billing-context` (Abrechnung) -> Nur Infrastruktur-Hülle vorhanden.
* [ ] `results-service` -> Geschäftslogik fehlt.
### PHASE 6: P3-Contexts & Billing ✅ ABGESCHLOSSEN
*Ziel: `billing-context` und `identity-context` implementieren.*
* [x] **`billing-context`:** Gebührenberechnung, Kassa, Abrechnung.
* [x] **`identity-context`:** Rollen-Modell (TBA, Veranstalter, Richter etc.) mit Keycloak.
* [x] **Reporting:** Startlisten- und Ergebnislisten-Druck (PDF).
</details>
---
## 4. Geplante Phasen
### PHASE 7: Desktop-Vernetzung & Zentrale Verwaltung ✅ ABGESCHLOSSEN
*Ziel: LAN-Kommunikation Vorbereitung und Etablierung der "Veranstaltung-Verwaltung" als zentrale Schaltstelle.*
* [x] **Zentrale Verwaltung:** Etablierung der `Veranstaltung-Verwaltung` (Zentrale) als administratives Cockpit.
* [x] **Navigation:** Implementierung eines Back-Stack-Systems für intelligente "Zurück"-Navigation.
* [x] **Domänen-Synchronisation:** Anpassung der Frontend-Stores an die Backend-Masterdata-Modelle (Reiter, Pferde,
Vereine, Funktionäre).
* [x] **ZNS-Integration (Frontend):** ZNS-Importer in die Zentrale integriert; Konzept "Globaler Pool -> Lokale
Synchronisation" gefestigt.
* [x] **Terminologie:** UI-weit Umstellung von "Event" auf "Veranstaltung" (ÖTO-konform).
* [x] **Konzept:** LAN-Discovery (mDNS) und Echtzeit-Sync (WebSockets) entworfen.
* [x] **ADR:** ADR-0020 (Lokale Netzwerk-Kommunikation) erstellt.
### PHASE 8: Bewerbe-Management & Startlisten ✅ ABGESCHLOSSEN
*Ziel: Fachliche Tiefe in den Turnieren (Import, Generierung, Zeitberechnung).*
* [x] **Konzept/ADR:** LANSync (ADR0022) und OfflineFirst Desktop↔Backend Konzept definiert und verlinkt.
* [x] **Bewerbe-Import:** Implementierung der Merge-Logik (ZNS-XML -> BewerbUiModel). ✓
* [x] **Startlisten-Automatisierung:** Generierung und Zeitberechnung (Pausen, Umbauzeiten). ✓
* [x] **Discovery:** Implementierung des mDNS-Service (JmDNS) für die Geräte-Suche. ✓
* [x] **Transport:** Aufbau der WebSocket-Infrastruktur für P2P-Sync (Ktor WebSockets, SyncManager). ✓
* [x] **Offline-First Desktop↔Backend:** Umsetzung gemäß Konzept „Offline-First Synchronisation (Desktop ↔ Backend)“ → `docs/01_Architecture/konzept-offline-first-desktop-backend-de.md`. ✓
* [x] **Regelwerks-Validierung:** Implementierung des strukturierten Abteilungs-Warnungssystems gemäß ÖTO § 39 inkl. UI-Integration. ✓
### PHASE 9: Zeitplan-Optimierung & Protokollierung ✅ ABGESCHLOSSEN
*Ziel: Dynamische Zeitplan-Anpassungen, Protokollierung von Änderungen und Export-Funktionen.*
* [x] **Billing-Service:** Initialisierung, Teilnehmer-Konten & Buchungs-Logik (v1). ✓
* [x] **Entries-Integration:** Automatische Buchung von Nenngeldern bei Nennungs-Abgabe. ✓
* [x] **ZNS-Importer:** Hardening & Integrationstests für Funktionärs-Updates. ✓
* [x] **Konzept:** Fachliches Konzept für Zeitplan-Optimierung (Drag & Drop) erstellt. ✓
* [x] **Konzept:** Status-Automat für Nennungen & Zeitplan-Synchronisation spezifiziert. ✓
* [x] **Frontend-Standardisierung:** `nennung-feature` refactored und in Desktop-Shell integriert. ✓
* [x] **Rulebook-Check:** ÖTO §43 "Parcoursbesichtigung zu Pferd" eingearbeitet. ✓
* [x] **Feature-Migration:** Pferde-, Reiter-, Funktionärs- und Veranstalter-Module vollständig auf KMP umgestellt. ✓
* [x] **Cleanup:** `FRONTEND_CLEANUP_TODO.md` für Migration von `v2` Screens weitestgehend abgeschlossen. ✓
* [x] **Zeitplan:** Dynamische Verschiebung von Bewerben (Drag & Drop im Kalender). ✓
* [x] **Protokoll:** Implementierung eines Event-Logs für manuelle Eingriffe in Startlisten (Audit-Log). ✓
* [x] **Export:** Startlisten-Export für ZNS (XML-B-Satz). ✓
### PHASE 10: Series-Context & Stammdaten ✅ ABGESCHLOSSEN
*Ziel: Stammdaten-Integration (Reiter, Pferde, Funktionäre) und Series-Context (Cups).*
* [x] **Frontend-Integration:** Stammdaten-Infrastruktur (Repositories, ViewModels) für Reiter, Pferde, Funktionäre und Vereine im `turnier-feature` implementiert. ✓
* [x] **Nennungs-Management:** Funktionalisierung des Nennungs-Tabs mit Echt-Datenanbindung und Suche. ✓
* [x] **`series-context`:** Pluggable Berechnungsmodell (Streichresultate, Alles zählt), konfigurierbare Paar-Bindung (Reiter+Pferd vs. Einzelwertung) implementiert. ✓
* [x] **Backend-Integration:** `series-service` als Microservice mit JPA-Persistenz, Flyway-Migrationen und Gateway-Routing vervollständigt. ✓
## 4. Geplante Phasen
### PHASE 11: Ergebniserfassung & Platzierung ✅ ABGESCHLOSSEN
*Ziel: Vollständige Ergebniserfassung und automatisierte Platzierungsberechnung.*
* [x] **Backend (Results):** Implementierung der Geschäftslogik für Wertnoten, Zeitfehler und ÖTO-konforme Platzierungen. ✓
* [x] **Backend-Infrastruktur:** `results-service` in Docker-Compose und API-Gateway integriert; Service-Discovery via Consul aktiviert. ✓
* [x] **Frontend UI:** `ErgebnisEditDialog` zur schnellen Ergebniserfassung und `TurnierErgebnislistenTab` zur Anzeige realer Ergebnisse. ✓
* [x] **PDF-Export:** Generierung von PDF-Ergebnislisten (Bewerbe und Serien). ✓
### PHASE 12: Abrechnung & Billing 🔵 IN ARBEIT
*Ziel: Vollständige Kassa-Funktionalität und Turnier-Abrechnung.*
* [x] **Backend-Infrastruktur:** `billing-service` initialisiert, Docker-Integration und Gateway-Routing (Port 8087) konfiguriert. ✓
* [x] **Frontend-Anbindung:** `BillingRepository` (Ktor) und `BillingViewModel` auf reale API-Kommunikation umgestellt. ✓
* [x] **Buchungs-Logik:** Implementierung von Soll/Haben-Buchungen (Startgebühren, Nenngelder, Boxen). ✓
* [x] **Offene Posten:** Liste aller unbezahlten Beträge pro Teilnehmer/Pferd. ✓
* [x] **Rechnungserstellung:** Generierung von PDF-Rechnungen und Zahlungsbestätigungen. ✓
* [x] **Kassa-Management:** Tagesabschluss, Storno-Logik und verschiedene Zahlungsarten. ✓
---
## 4. Geplante Phasen
### PHASE 13: Frontend-Modernisierung & Cleanup ✅ ABGESCHLOSSEN (20. April 2026)
*Ziel: Finalisierung der Turnier-Daten, Rückübermittlung an den OEPS und architektonische Bereinigung.*
* [x] **"V2"-Bereinigung:** Vollständige Eliminierung aller "V2"-Suffixe in Dateinamen und Symbolen (z.B. `TurnierWizardV2`, `VeranstalterAuswahlV2`). ✓ (20. April 2026)
* [x] **Plug-and-Play (Turnier):** Umstellung des `turnier-feature` auf ADR-0024. Entfernung von Reflection-Zugriffen auf die Shell und Einführung von ViewModel-Hoisting. ✓ (20. April 2026)
* [x] **Plug-and-Play (Veranstalter):** Umstellung des `veranstalter-feature` auf ADR-0024. Einführung des `VeranstalterDetailViewModel` und Konsolidierung der Screens in der Desktop-Shell. ✓ (20. April 2026)
* [x] **Device-Setup ("Lock-and-Edit"):** Einführung eines Review-Modus mit Konfigurations-Sperre, Drucker-Integration und Maskierung des SharedKeys. ✓ (20. April 2026)
* [x] **Veranstaltungs-Wizard:** Implementierung eines 6-stufigen Profi-Workflows mit Sticky Preview-Card (WYSIWYG), ZNS-Guard und OEPS-Satznummer-Mapping. ✓ (20. April 2026)
* [x] **Code-Hygiene:** Beseitigung von Code-Smells, redundanten Validierungen und ungenutzten Parametern in den zentralen Frontend-Modulen. ✓ (20. April 2026)
* [x] **Connectivity-Diagnose:** Stabiles Diagnose-Tool für Backend-, DB- und Auth-Verbindung in der Desktop-App. ✓ (18. April 2026)
* [x] **WASM-Transition:** Projektweite Umstellung auf JVM (Desktop) und wasmJs (Web). Eliminierung von `js(IR)`. ✓ (18. April 2026)
* [x] **Geräte-Initialisierung:** Refactoring des Onboarding-Prozesses in das Plug-and-Play Modul `device-initialization`. ✓ (18. April 2026)
* [ ] **XML-Export:** Vollständiger B-Satz Export (inkl. Ergebnisse und Platzierungen).
* [ ] **ZNS-Portal:** Upload-Integration in das OEPS-ZNS.
* [ ] **Archivierung:** Langzeit-Archivierung abgeschlossener Turniere.
---
## 5. Wichtige Architektur-Entscheidungen (ADRs)
| # | Entscheidung | Status | Dokument |
|----|--------------------------------------------------------------|--------|------------------------------|
| 1 | Vision_03 = Design-Baseline | ✅ | Session Log 2026-03-24 |
| 2 | Desktop-First mit KMP/Compose Desktop | ✅ | ADR-0009 |
| 3 | `Veranstaltung``Turnier` (ÖTO § 2 Abs. 1) | ✅ | Ubiquitous Language |
| 4 | 6 Bounded Contexts als SCS-Architektur | ✅ | Session Log 2026-03-24 |
| 5 | `series-context` ist Phase 2+ (Architektur vorbereitet) | ✅ | Session Log 2026-03-24 |
| 6 | Cups/Serien benötigen konfigurierbare Reglements | ✅ | Session Log 2026-03-24 |
| 7 | Warn-Logik statt harter Fehler (Override-Event) | ✅ | Abteilungs-Schwellenwerte.md |
| 8 | 6 Bounded Contexts: Mapping & Aggregate Roots | ✅ | ADR-0014 |
| 9 | Context Map: Integration Patterns & ACL-Strategie | ✅ | ADR-0015 |
| 10 | API-Design & ACL: Ports, DTOs, REST-Endpunkte, Domain Events | ✅ | ADR-0016 |
| 11 | Masterdata: Importer-Einbettung als Worker | ✅ | ADR-0017 |
| 12 | Masterdata: Rule-Versionierung (Regulation-as-Data) | ✅ | ADR-0018 |
| 13 | Masterdata: API-Schichten (REST vs. Ingestion) | ✅ | ADR-0019 |
| 14 | Lokale Netzwerk-Kommunikation und Daten-Isolierung | ✅ | ADR-0020 |
| 15 | Masterdata: Observability & Operations | ✅ | masterdata-ops.md, CHANGELOG |
| 16 | Tenant-Resolution: Schema-per-Tenant | ✅ | ADR-0021 |
| 17 | LAN-Sync-Protokoll (Lamport-Uhren, Event-Sourcing Light) | ✅ | ADR-0022 |
| 18 | Domain-Naming: Kein `Dom`-Präfix für Entitäten | ✅ | ADR-0023 |
| 19 | Plug-and-Play Architektur für UI-Komponenten | ✅ | ADR-0024 |
---
## 5. Wichtige Referenzen
| Dokument | Pfad |
|---------------------------|----------------------------------------------------------------------------------------------|
| Ubiquitous Language | `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` |
| Abteilungs-Schwellenwerte | `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
| Warn-Logik-Spezifikation | `docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` |
| Session Log (DDD) | `docs/99_Journal/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
| Infrastruktur | `docs/07_Infrastructure/Zora_System_Architektur.md` |
| Deployment Guide | `docs/07_Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
| Backup Guide | `docs/07_Infrastructure/Guides/Setup_Backup_Zora.md` |
| CI/CD | `.gitea/workflows/docker-publish.yaml` |
| Agent Playbooks | `docs/04_Agents/Playbooks/` |
| ADR-Verzeichnis | `docs/01_Architecture/adr/` |
| ZNS-Importer Roadmap | `docs/01_Architecture/Roadmap_ZNS_Importer.md` |
| Masterdata Roadmap | `backend/services/masterdata/docs/ROADMAP.md` |
| Masterdata Changelog | `backend/services/masterdata/docs/CHANGELOG.md` |
| Masterdata Operations | `backend/services/masterdata/docs/runbooks/masterdata-ops.md` |
| Zeitplan-Optimierung | `docs/01_Architecture/konzept-zeitplan-optimierung-de.md` |
| Parcoursbesichtigung-Rulebook | `docs/01_Architecture/rulebook-check-parcoursbesichtigung-de.md` |
| Status-Automat-Nennungen | `docs/01_Architecture/status-automat-nennungen-de.md` |
---
## 3. Zukünftige Phase (April 2026)
### PHASE 5: Web-App & Neumarkt-Vorbereitung 🔵 IN ARBEIT (Start 13. April 2026)
*Ziel: Fertigstellung der Web-App für Online-Nennungen und Vorbereitung des Neumarkt-Turniers (24. April).*
#### 🎨 Agent: Frontend Expert
* [x] **Web-App Shell:** Modul `frontend:shells:meldestelle-web` (Compose WasmJS) initialisiert.
* [x] **UI-Komponenten:** `VeranstaltungsCard` und `TurnierCard` für Web implementiert (mit PDF- & Nenn-Button).
* [x] **Workflow:** `NennungWebFormular` Prototyp erstellt (mit simuliertem Mail-Versand).
#### 👷 Agent: Backend Developer
* [x] **Daten-Seeding:** Desktop-Stores mit echten Daten für Neumarkt (April 2026) vorbefüllt.
* [ ] **Mail-Service:** Integration eines E-Mail-Dienstes für eingehende Nennungen.
#### 🧐 Agent: QA Specialist
* [x] **Verifikation:** Desktop-Screens (Veranstalter, Turnier, Bewerbe) mit echten Daten geprüft.
* [ ] **End-to-End Test:** Online-Nennung (Web) -> E-Mail -> Desktop-Verarbeitung.
---
### PHASE 5: Desktop-Zentrale & Synchronisation 🔵 IN ARBEIT
*Ziel: Ein einsatzbereiter Desktop-Client für das Neumarkt-Turnier.*
#### 🎨 Agent: Frontend Expert
* [x] **Onboarding UI:** Implementierung des Onboarding-Screens (Name, Key, Backup, Rolle, Sync, Drucker) mit
validierten Eingaben.
* [x] **Navigation:** Navigations-Rail mit Hover-Tooltips und dedizierten Icons für "Setup" und "Sync".
* [x] **Settings:** Persistente Speicherung der Onboarding-Daten in `settings.json`.
#### 👷 Agent: Backend Developer
* [x] **Device Management:** Domain-Modell (`Device`), Tabelle (`identity_devices`) und Repository zur
Geräteverwaltung implementiert.
* [x] **Security Key Auth:** Implementierung des `DeviceSecurityFilter` zur Authentifizierung via `X-Security-Key`
Header.
* [x] **Onboarding API:** REST-Endpunkte zur Registrierung und Abfrage von Desktop-Instanzen erstellt.
#### 🧹 Agent: Curator
* [x] **Dokumentation:** Erstellung der Architektur-Doku für das Onboarding-Backend.
| Dokument | Pfad |
|-------------------------------|----------------------------------------------------------------------------------------------|
| Ubiquitous Language | `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` |
| Abteilungs-Schwellenwerte | `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
| Warn-Logik-Spezifikation | `docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` |
| Session Log (DDD) | `docs/99_Journal/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
| Infrastruktur | `docs/07_Infrastructure/Zora_System_Architektur.md` |
| Deployment Guide | `docs/07_Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
| Backup Guide | `docs/07_Infrastructure/Guides/Setup_Backup_Zora.md` |
| CI/CD | `.gitea/workflows/docker-publish.yaml` |
| Agent Playbooks | `docs/04_Agents/Playbooks/` |
| ADR-Verzeichnis | `docs/01_Architecture/adr/` |
| ADR-0025: Plan-USB | `docs/01_Architecture/adr/0025-plan-usb-offline-integritaet.md` |
| ADR-0026: Lizenzierung | `docs/01_Architecture/adr/0026-offline-lizenzierung-pay-per-event.md` |
| ADR-0027: Discovery | `docs/01_Architecture/adr/0027-netzwerk-discovery-interface-binding.md` |
| Docker-Fix: dc-gui.yaml | `dc-gui.yaml` |
| ZNS-Importer Roadmap | `docs/01_Architecture/Roadmaps/Roadmap_ZNS_Importer.md` |
| Masterdata Roadmap | `backend/services/masterdata/docs/ROADMAP.md` |
| Masterdata Changelog | `backend/services/masterdata/docs/CHANGELOG.md` |
| Masterdata Operations | `backend/services/masterdata/docs/runbooks/masterdata-ops.md` |
| Zeitplan-Optimierung | `docs/01_Architecture/Concepts/konzept-zeitplan-optimierung-de.md` |
| Parcoursbesichtigung-Rulebook | `docs/01_Architecture/Concepts/rulebook-check-parcoursbesichtigung-de.md` |
| Status-Automat-Nennungen | `docs/01_Architecture/Concepts/status-automat-nennungen-de.md` |
@@ -1,358 +0,0 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
---
# Meldestelle — Tech-Stack Zusammenfassung
> **Zweck:** Vollständige Referenz des eingesetzten Tech-Stacks im Projekt "Meldestelle".
> Dient als Basis für Recherchen zu Self-Hosted AI (Codegenerierung, RAG, Agenten).
> **Stand:** 07. März 2026
---
## 1. Überblick
Das Projekt "Meldestelle" ist eine **Kotlin-first, Cloud-native Microservices-Plattform** für die Verwaltung von Reitsport-Meldungen (FEI / ÖTO). Es kombiniert ein **Kotlin Multiplatform (KMP) Frontend** mit einem **Spring Boot Microservices Backend** auf einer vollständig self-hosted Infrastruktur.
```
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (KMP) │ Backend (Spring Boot / Kotlin JVM) │
│ Kotlin 2.3 / Compose │ Java 25 / Spring Boot 3.5.9 │
│ JS + WASM (geplant) │ Microservices + API-Gateway │
├─────────────────────────────────────────────────────────────────┤
│ Infrastruktur (Self-Hosted auf Zora / Proxmox) │
│ Keycloak · Consul · Valkey · PostgreSQL · Zipkin │
│ Prometheus · Grafana · Caddy · Pangolin-Tunnel │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. Sprachen & Laufzeiten
| Komponente | Sprache / Runtime | Version |
|:------------------|:-------------------------|:------------|
| Backend | Kotlin (JVM) | 2.3.0 |
| Frontend | Kotlin (KMP / JS) | 2.3.0 |
| JVM | Java (Eclipse Temurin) | 25 (EA) |
| Build | Gradle (Kotlin DSL) | 9.3.1 |
| Plattform | ARM64 (AArch64) | Linux |
---
## 3. Frontend — Kotlin Multiplatform (KMP)
### 3.1 Core-Framework
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Kotlin Multiplatform | 2.3.0 | Cross-Platform-Basis (JS + WASM) |
| Compose Multiplatform | 1.10.0 | UI-Framework (Deklarativ) |
| Compose Hot Reload | 1.0.0 | Live-Reload im Dev-Modus |
| Koin (DI) | 4.1.1 | Dependency Injection |
| Koin Compose | 4.1.1 | DI-Integration für Compose |
| Ktor Client | 3.4.0 | HTTP-Client (Multiplatform) |
| Kotlin Serialization | 2.3.0 | JSON-Serialisierung |
### 3.2 Persistenz (Offline-First)
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| SQLDelight | 2.2.1 | Cross-Platform SQL-Datenbank |
| SQLite (WASM) | 3.51.1 | SQLite für Browser/WASM |
| SQLite (Native) | 2.6.2 | SQLite für JVM/Desktop |
### 3.3 Build-Targets
| Target | Status | Anmerkung |
|:--------------|:------------|:-----------------------------------|
| KotlinJS | ✅ Aktiv | Primäres Build-Target |
| WASM | ⏳ Geplant | Warten auf Alpha-Version |
| Desktop (JVM) | ⚙️ Möglich | uiDesktop 1.7.0 vorhanden |
### 3.4 Modul-Struktur
```
frontend/
├── core/
│ ├── core-network/ # Ktor HTTP-Client, Auth-Interceptor
│ ├── core-ui/ # Design-System, Tokens, Komponenten
│ ├── core-domain/ # Shared Domain-Models
│ └── core-data/ # Repository-Interfaces
├── features/
│ ├── ping-feature/ # ✅ Blueprint: MVVM + Repository + DI + Tests
│ └── members-feature/ # ⏳ Auskommentiert (nächste Phase)
└── shells/
└── meldestelle-portal/ # Web-App Shell (Caddy-served)
```
---
## 4. Backend — Spring Boot Microservices
### 4.1 Core-Framework
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Spring Boot | 3.5.9 | Microservices-Framework |
| Spring Cloud | 2025.0.1 | Service Discovery, Config |
| Spring Security (OAuth2) | (Boot) | JWT-Validierung, Resource Server |
| Spring Data JPA | (Boot) | ORM-Layer |
| Spring Data Valkey | 0.2.0 | Cache-Integration (Valkey/Redis) |
| Spring WebFlux | (Boot) | Reaktive API (Gateway) |
| Kotlin Coroutines | 2.3.0 | Async/Non-blocking |
### 4.2 Persistenz
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| PostgreSQL Driver | 42.7.8 | JDBC-Treiber |
| Exposed (JetBrains) | 1.0.0 | Kotlin-native SQL DSL |
| Flyway | 11.19.1 | Datenbank-Migrationen |
| HikariCP | 7.0.2 | Connection Pool |
> **Strategie (ADR-001):** Hybrid — JPA für einfache CRUD-Entities, Exposed für komplexe Queries und Domain-Logik.
### 4.3 Caching & Messaging
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Lettuce | 6.6.0 | Valkey/Redis-Client (reaktiv) |
| Redisson | 4.0.0 | Distributed Locks, Pub/Sub |
| Caffeine | 3.2.3 | In-Memory Cache (L1) |
| Reactor Kafka | 1.3.23 | Kafka-Client (Phase 3 / Outbox) |
### 4.4 Observability & Tracing
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Micrometer | 1.16.1 | Metriken (Prometheus-Export) |
| Micrometer Tracing | 1.6.1 | Distributed Tracing |
| Zipkin Reporter | 3.5.1 | Trace-Export zu Zipkin |
| Logback | 1.5.25 | Logging |
### 4.5 Security
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Keycloak Admin Client | 26.0.7 | Keycloak-API-Integration |
| Spring Security OAuth2 | (Boot) | JWT Resource Server |
| Jackson (Kotlin) | 3.0.3 | JSON-Serialisierung |
### 4.6 API & Dokumentation
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| Springdoc OpenAPI | 3.0.0 | Swagger / OpenAPI 3.1 |
| Jakarta Annotation | 3.0.0 | Jakarta EE Annotations |
### 4.7 Modul-Struktur
```
backend/
├── infrastructure/
│ ├── gateway/ # ✅ API-Gateway (Spring Cloud Gateway)
│ ├── security/ # ✅ Zentrales OAuth2/JWT-Modul (DRY)
│ ├── cache/
│ │ ├── cache-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── event-store/
│ │ ├── event-store-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── persistence/ # Hybrid JPA + Exposed
│ └── messaging/ # Kafka (Phase 3 / Outbox-Pattern)
└── services/
├── ping/ # ✅ Deployed — Test/Blueprint-Service
├── entries/ # ⚙️ Registriert, noch nicht deployed
├── events/ # 👻 Ghost Service (nicht registriert)
├── horses/ # 👻 Ghost Service (nicht registriert)
├── masterdata/ # 👻 Ghost Service (nicht registriert)
├── registry/ # 👻 Ghost Service (nicht registriert)
├── results/ # 👻 Ghost Service (nicht registriert)
└── scheduling/ # 👻 Ghost Service (nicht registriert)
```
---
## 5. Infrastruktur-Services (Docker)
### 5.1 Laufende Services
| Service | Image / Version | Port(s) | Zweck |
|:---------------|:--------------------------|:--------------|:-----------------------------|
| PostgreSQL | postgres:16-alpine | 5432 | Primäre Datenbank |
| Keycloak | keycloak:26.4 (custom) | 8180, 9000 | IAM / OAuth2 / OIDC |
| Valkey | valkey:8-alpine | 6379 | Cache + Event-Store |
| Consul | consul:1.21 | 8500, 8600 | Service Discovery + Config |
| Zipkin | openzipkin/zipkin:3.5 | 9411 | Distributed Tracing |
| Prometheus | prom/prometheus:v3.4 | 9090 | Metriken-Sammlung |
| Grafana | grafana/grafana:11.6 | 3000 | Dashboards / Visualisierung |
| Caddy | caddy:2.10-alpine | 4000 | Web-App Serving (Frontend) |
| API-Gateway | (custom Spring Boot) | 8081 | Zentraler Eintrittspunkt |
| Ping-Service | (custom Spring Boot) | 8082 | Test/Blueprint-Service |
### 5.2 CI/CD & DevOps
| Tool | Version / Details | Zweck |
|:----------------|:--------------------------|:-----------------------------|
| Gitea | Self-Hosted (CT 101) | Git-Repository + Registry |
| Gitea Actions | (Runner VM 102) | CI/CD-Pipeline |
| Docker Buildx | ARM64 (linux/arm64) | Multi-Arch Image Build |
| Pangolin | Self-Hosted Tunnel | Reverse Proxy / Extern-Zugang|
### 5.3 Netzwerk & Routing
| Subdomain | Intern (Zora) | Zweck |
|:-----------------------|:--------------------|:-------------------------|
| `git.mo-code.at` | `10.0.0.22:3000` | Gitea |
| `api.mo-code.at` | `10.0.0.50:8081` | API-Gateway |
| `auth.mo-code.at` | `10.0.0.50:8180` | Keycloak |
| `app.mo-code.at` | `10.0.0.50:4000` | Web-App |
| `photos.mo-code.at` | `10.0.0.24:2283` | Immich (Fotos) |
---
## 6. Code-Qualität & Build-Tools
| Tool | Version | Zweck |
|:------------------|:----------|:-----------------------------------|
| Detekt | 1.23.6 | Kotlin Static Analysis |
| ktlint | 12.1.1 | Kotlin Code Formatter |
| ArchUnit | 1.4.1 | Architektur-Tests (Layer-Regeln) |
| Dokka | 2.1.0 | API-Dokumentation (KDoc) |
| Ben-Manes Versions| 0.51.0 | Dependency-Update-Check |
| KSP | 2.3.4 | Kotlin Symbol Processing |
### Build-Konfiguration
```properties
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.workers.max=8
org.gradle.configuration-cache=false # wegen JS-Test Serialisierungsproblem
org.gradle.dependency.verification=strict
```
---
## 7. Test-Stack
| Bibliothek | Version | Zweck |
|:------------------------------|:----------|:-----------------------------------|
| JUnit Jupiter | 5.11.3 | Unit-Tests |
| JUnit Platform | 1.11.3 | Test-Runner |
| MockK | 1.14.7 | Kotlin Mocking |
| AssertJ | 3.27.7 | Fluent Assertions |
| Testcontainers | 2.0.3 | Integration-Tests (Docker) |
| Testcontainers Keycloak | 4.0.1 | Keycloak-Integration-Tests |
| Testcontainers PostgreSQL | 1.21.4 | DB-Integration-Tests |
| Testcontainers Kafka | 1.21.4 | Kafka-Integration-Tests |
| ArchUnit | 1.4.1 | Architektur-Compliance-Tests |
---
## 8. Architektur-Prinzipien (ADRs)
| ADR | Entscheidung | Status |
|:------|:--------------------------------------------------|:---------|
| 0001 | Modulare Architektur (DDD, Clean Architecture) | ✅ Aktiv |
| 0003 | Microservices-Architektur | ✅ Aktiv |
| 0004 | Event-Driven Communication (Kafka Phase 3) | ✅ Aktiv |
| 001 | Backend-Infrastruktur: Hybrid JPA+Exposed, Valkey | ✅ Aktiv |
| 0013 | Tech-Stack-Stabilisierung 2026 (Versionen) | ✅ Aktiv |
**Kern-Prinzipien:**
- **Offline-First:** SQLDelight als Cross-Platform-DB, Sync-Mechanismus
- **Docs-as-Code:** `/docs` als Single Source of Truth
- **DRY-Infrastruktur:** Shared Security/Cache/EventStore-Module
- **ARM64-Native:** Alle Images für `linux/arm64` gebaut
---
## 9. Relevanz für Self-Hosted AI
### 9.1 Welche AI-Aufgaben entstehen im Projekt?
| Aufgabe | Häufigkeit | Komplexität |
|:---------------------------------|:-----------|:------------|
| Kotlin/Spring Boot Code-Completion| Täglich | Mittel |
| Compose Multiplatform UI-Code | Täglich | Mittel |
| SQL / Exposed DSL Queries | Häufig | Mittel |
| Gradle Kotlin DSL Build-Skripte | Gelegentlich| Niedrig |
| Docker / YAML Konfigurationen | Gelegentlich| Niedrig |
| Architektur-Entscheidungen (ADR) | Selten | Hoch |
| Fachlogik FEI/ÖTO Regelwerk | Selten | Sehr hoch |
### 9.2 Anforderungen an das AI-Modell
```
MUSS:
✅ Kotlin (JVM + Multiplatform) — sehr gute Unterstützung
✅ Spring Boot / Spring Cloud — sehr gute Unterstützung
✅ Compose Multiplatform — gute Unterstützung (neuere Modelle)
✅ SQL / PostgreSQL — sehr gute Unterstützung
✅ Docker / YAML — sehr gute Unterstützung
✅ Deutsch (Fachsprache Reitsport) — für RAG-Dokumente
NICE-TO-HAVE:
⭐ Gradle Kotlin DSL
⭐ Keycloak / OAuth2 / OIDC
⭐ Microservices-Architektur-Patterns
```
### 9.3 Empfohlene Modelle für diesen Stack
| Modell | Größe | Stärke | RAM-Bedarf |
|:------------------------|:-------|:------------------------------------|:-----------|
| `qwen2.5-coder:14b` | 14B | Code (Kotlin, Java, SQL) — Top | ~10 GB |
| `deepseek-coder-v2:16b` | 16B | Code-Completion, Refactoring | ~12 GB |
| `llama3.1:8b` | 8B | Allgemein + Deutsch, schnell | ~6 GB |
| `qwen2.5:32b` | 32B | Architektur, Planung, Fachlogik | ~22 GB |
| `codellama:13b` | 13B | Code-Completion (IntelliJ-Plugin) | ~9 GB |
> **Empfehlung für Zora (64 GB RAM):**
> - **Primär:** `qwen2.5-coder:14b` — bester Kotlin/Spring-Support
> - **Sekundär:** `qwen2.5:32b` — für Architektur und Fachlogik
> - **IntelliJ-Integration:** `codellama:13b` oder `qwen2.5-coder:14b`
### 9.4 RAG-Dokumente (Priorität)
Folgende Projekt-Dokumente sind besonders wertvoll als RAG-Kontext:
```
Hohe Priorität:
├── docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md
├── docs/01_Architecture/adr/ (alle ADRs)
├── docs/04_Agents/Playbooks/ (Agenten-Rollen)
├── gradle/libs.versions.toml (Versions-SSoT)
└── docs/07_Infrastructure/ (Infrastruktur-Referenz)
Mittlere Priorität:
├── docs/05_Backend/ (Backend-Guides)
├── docs/06_Frontend/ (Frontend-Guides)
└── docs/03_Domain/ (Fachlogik-Konzepte)
```
---
## 10. Zusammenfassung
```
TECH-STACK KOMPLEXITÄT
──────────────────────────────────────────────────────
Sprachen: Kotlin (JVM + KMP/JS)
Build: Gradle 9.3.1 + Kotlin DSL + libs.versions.toml
Frontend: Compose Multiplatform 1.10 + SQLDelight 2.2 + Koin 4.1
Backend: Spring Boot 3.5.9 + Spring Cloud 2025.0.1
Persistenz: PostgreSQL 16 + Exposed 1.0 + Flyway 11 + HikariCP 7
Cache: Valkey 8 + Lettuce 6.6 + Caffeine 3.2
Security: Keycloak 26.4 + Spring Security OAuth2 + JWT
Observability: Micrometer 1.16 + Zipkin 3.5 + Prometheus + Grafana 11.6
Service Mesh: Consul 1.21 + Spring Cloud Gateway
Messaging: Kafka (Phase 3) + Reactor Kafka 1.3
CI/CD: Gitea Actions + Docker Buildx (ARM64)
Hosting: Proxmox VE 8.4 + Docker Compose + Pangolin-Tunnel
```
@@ -5,23 +5,23 @@ owner: Lead Architect
date: 2026-02-02
---
# Engineering Moderner Frontend-Architekturen: Kotlin 2.3.0, Compose Multiplatform 1.10.0 und Gradle 9.0 für Modulare Monolithen
# Engineering Moderner Frontend-Architekturen: Kotlin 2.3.21, Compose Multiplatform 1.10.0 und Gradle 9.5.0 für Modulare Monolithen
Der architektonische Übergang zu modularen Monolithen bietet Unternehmen die Möglichkeit, die Komplexität von
Microservices zu reduzieren und gleichzeitig eine klare Trennung der Domänenlogik beizubehalten. In Kombination mit
Kotlin Multiplatform (KMP) für Single Page Applications (SPAs) lässt sich Geschäftslogik effizient über den gesamten
Stack teilen. Die Einführung von Kotlin 2.3.0, Compose Multiplatform 1.10.0 und Gradle 9.0 stellt dabei neue Best
Stack teilen. Die Einführung von Kotlin 2.3.21, Compose Multiplatform 1.10.0 und Gradle 9.5.0 stellt dabei neue Best
Practices für Build-Performance und Deployment auf.
## 1. Gradle 9.x Optimierung in der CI/CD
Gradle 9.0 führt signifikante Änderungen ein, die speziell für große Multi-Modul-Projekte wie modulare Monolithen
Gradle 9.5.0 führt signifikante Änderungen ein, die speziell für große Multi-Modul-Projekte wie modulare Monolithen
optimiert sind.
- **Configuration Cache als Standard:** In Gradle 9.0 ist der Configuration Cache der bevorzugte Ausführungsmodus. Durch
- **Configuration Cache als Standard:** In Gradle 9.5.0 ist der Configuration Cache der bevorzugte Ausführungsmodus. Durch
das Caching des Task-Graphen werden nachfolgende Builds erheblich beschleunigt, da die Konfigurationsphase
übersprungen wird.
- **Kotlin DSL Script Compilation Avoidance:** Durch den Einsatz von ABI-Fingerprinting erkennt Gradle 9.0, ob
- **Kotlin DSL Script Compilation Avoidance:** Durch den Einsatz von ABI-Fingerprinting erkennt Gradle 9.5.0, ob
Änderungen an `.kts`-Dateien die Build-Logik tatsächlich beeinflussen. Nicht-relevante Änderungen (wie Kommentare)
führen nicht mehr zur Neukompilierung, was die Konfigurationszeit um bis zu 60 % reduzieren kann.
- **Parallel Configuration Store and Load:** Gradle 8.11 und 9.0 unterstützen das parallele Laden und Speichern von
@@ -74,14 +74,14 @@ Die Wahl des Webservers beeinflusst das Routing und die Performance der Compose
| Komponente | Empfehlung | Vorteil |
|---------------|-------------------------------------|--------------------------------------------------------|
| Build-Tool | Gradle 9.0 mit Configuration Cache | Extreme Verkürzung der Konfigurationsphase |
| Build-Tool | Gradle 9.5.0 mit Configuration Cache | Extreme Verkürzung der Konfigurationsphase |
| CI Caching | Remote Cache Action (Proxy) | Wiederverwendung von Task-Outputs auf frischen Runnern |
| Konfiguration | Runtime config.json Fetch | Ein Docker-Image für alle Umgebungen (Dev/Prod) |
| Webserver | Caddy oder Nginx | Optimiertes SPA-Routing und Web Cache Support |
## Fazit
Die Kombination aus Gradle 9.0 und Kotlin 2.3.0 ermöglicht hocheffiziente Build-Pipelines für modulare Monolithen. Durch
Die Kombination aus Gradle 9.5.0 und Kotlin 2.3.21 ermöglicht hocheffiziente Build-Pipelines für modulare Monolithen. Durch
den Einsatz von Multi-Stage Docker-Builds und dem `config.json`-Fetch-Muster wird eine moderne, skalierbare
Deployment-Strategie umgesetzt, die die neuen Performance-Features von Compose Multiplatform 1.10.0 optimal nutzt.
@@ -9,7 +9,7 @@ Hier ist der Quellcode des Berichts im Markdown-Format:
## Zusammenfassung
Die Softwareentwicklungslandschaft des Jahres 2026, geprägt durch die Veröffentlichung von Kotlin 2.3.0 und Gradle 9.1.0, bietet Entwicklern beispiellose Möglichkeiten zur Vereinheitlichung komplexer Geschäftslogik über Plattformgrenzen hinweg. Dieser Forschungsbericht analysiert detailliert die architektonischen Muster, Implementierungsstrategien und zugrundeliegenden Mechanismen, die für den Aufbau einer robusten, asynchronen Offline-First-Anwendung erforderlich sind. Der Fokus liegt hierbei auf der Integration von SQLDelight in einer Kotlin Multiplatform (KMP) Umgebung, die sowohl Desktop (JVM) als auch Web (Kotlin/JS) Ziele bedient, eingebettet in eine Mikro-Frontend-Architektur.
Die Softwareentwicklungslandschaft des Jahres 2026, geprägt durch die Veröffentlichung von Kotlin 2.3.21 und Gradle 9.5.0, bietet Entwicklern beispiellose Möglichkeiten zur Vereinheitlichung komplexer Geschäftslogik über Plattformgrenzen hinweg. Dieser Forschungsbericht analysiert detailliert die architektonischen Muster, Implementierungsstrategien und zugrundeliegenden Mechanismen, die für den Aufbau einer robusten, asynchronen Offline-First-Anwendung erforderlich sind. Der Fokus liegt hierbei auf der Integration von SQLDelight in einer Kotlin Multiplatform (KMP) Umgebung, die sowohl Desktop (JVM) als auch Web (Kotlin/JS) Ziele bedient, eingebettet in eine Mikro-Frontend-Architektur.
Ein zentraler Schwerpunkt dieser Arbeit ist die Überbrückung der Dichotomie zwischen der synchronen Natur klassischer JVM-Datenbanktreiber und der inhärent asynchronen, Event-Loop-basierten Umgebung des modernen Web (insbesondere unter Nutzung von Web Workern und OPFS). Darüber hinaus wird die fortgeschrittene Integration von Persistenzschichten in einem Mikro-Frontend-Ökosystem untersucht, um sicherzustellen, dass eine einzige Quelle der Wahrheit („Single Source of Truth“) über unabhängig bereitgestellte Frontend-Einheiten hinweg konsistent bleibt.
@@ -17,11 +17,11 @@ Ein zentraler Schwerpunkt dieser Arbeit ist die Überbrückung der Dichotomie zw
### 1.1 Die Evolution von Kotlin Multiplatform
Mit der Veröffentlichung von Kotlin 2.3.0 im Dezember 2025 hat sich das Ökosystem von einer experimentellen Technologie zu einem stabilen Standard für Enterprise-Architekturen entwickelt. Während frühere Versionen oft mit Inkonsistenzen zwischen den Compilern (JVM vs. JS/Native) zu kämpfen hatten, bietet der K2-Compiler in Version 2.3.0 eine vereinheitlichte Frontend-IR (Intermediate Representation), die eine robustere statische Analyse und performantere Kompilierung ermöglicht. Dies ist entscheidend für komplexe Multi-Modul-Projekte, wie sie in Mikro-Frontend-Architekturen üblich sind.
Mit der Veröffentlichung von Kotlin 2.3.21 im Dezember 2025 hat sich das Ökosystem von einer experimentellen Technologie zu einem stabilen Standard für Enterprise-Architekturen entwickelt. Während frühere Versionen oft mit Inkonsistenzen zwischen den Compilern (JVM vs. JS/Native) zu kämpfen hatten, bietet der K2-Compiler in Version 2.3.21 eine vereinheitlichte Frontend-IR (Intermediate Representation), die eine robustere statische Analyse und performantere Kompilierung ermöglicht. Dies ist entscheidend für komplexe Multi-Modul-Projekte, wie sie in Mikro-Frontend-Architekturen üblich sind.
### 1.2 Gradle 9.1.0: Die Build-Infrastruktur
### 1.2 Gradle 9.5.0: Die Build-Infrastruktur
Gradle 9.1.0, veröffentlicht im September 2025, hat die Art und Weise, wie KMP-Projekte konfiguriert werden, grundlegend verändert. Mit der vollständigen Unterstützung des „Configuration Cache“ und der strikten „Project Isolation“ zwingt es Entwickler zu sauberen Modulgrenzen. Für unser Szenario bedeutet dies, dass die Abhängigkeiten zwischen dem `shared`-Modul (Datenbank) und den konsumierenden Mikro-Frontends explizit und ohne Seiteneffekte definiert werden müssen, um die parallele Ausführung und inkrementelle Kompilierung nicht zu gefährden.
Gradle 9.5.0, veröffentlicht im September 2025, hat die Art und Weise, wie KMP-Projekte konfiguriert werden, grundlegend verändert. Mit der vollständigen Unterstützung des „Configuration Cache“ und der strikten „Project Isolation“ zwingt es Entwickler zu sauberen Modulgrenzen. Für unser Szenario bedeutet dies, dass die Abhängigkeiten zwischen dem `shared`-Modul (Datenbank) und den konsumierenden Mikro-Frontends explizit und ohne Seiteneffekte definiert werden müssen, um die parallele Ausführung und inkrementelle Kompilierung nicht zu gefährden.
### 1.3 Die Problemstellung: Synchron vs. Asynchron
@@ -38,12 +38,12 @@ SQLDelight 2.0+ adressiert dieses Problem mit der Konfiguration `generateAsync =
In einer Offline-First-Architektur fungiert die lokale Datenbank nicht als bloßer Cache, sondern als primäre Quelle der Wahrheit. Die Benutzeroberfläche (UI) kommuniziert niemals direkt mit dem Netzwerk.
| Konzept | Traditionelle Architektur | Offline-First Architektur |
| --- | --- | --- |
| **Datenquelle** | Remote API (REST/GraphQL) | Lokale Datenbank (SQLite) |
| **Lesepfad** | UI ruft Netzwerk auf -> Wartet -> Zeigt an | UI beobachtet Datenbank (Flow) -> Zeigt an |
| **Schreibpfad** | UI sendet an API -> Wartet auf OK -> Aktualisiert UI | UI schreibt in DB -> DB emittiert neue Daten -> Sync im Hintergrund |
| **Netzwerkstatus** | Voraussetzung für Funktionalität | Optional; beeinflusst nur Synchronisation |
| Konzept | Traditionelle Architektur | Offline-First Architektur |
|--------------------|------------------------------------------------------|---------------------------------------------------------------------|
| **Datenquelle** | Remote API (REST/GraphQL) | Lokale Datenbank (SQLite) |
| **Lesepfad** | UI ruft Netzwerk auf -> Wartet -> Zeigt an | UI beobachtet Datenbank (Flow) -> Zeigt an |
| **Schreibpfad** | UI sendet an API -> Wartet auf OK -> Aktualisiert UI | UI schreibt in DB -> DB emittiert neue Daten -> Sync im Hintergrund |
| **Netzwerkstatus** | Voraussetzung für Funktionalität | Optional; beeinflusst nur Synchronisation |
Dieses Prinzip der „Inversion of Control“ entkoppelt die User Experience von Netzwerklatenz und -verfügbarkeit. In SQLDelight wird dies durch Reactive Extensions realisiert, die SQL-Abfragen als `Flow<T>` exponieren, die sich bei Datenänderungen automatisch aktualisieren.
@@ -60,8 +60,8 @@ Das Fundament eines stabilen KMP-Projekts ist eine präzise Gradle-Konfiguration
### 3.1 Version Catalog (`gradle/libs.versions.toml`)toml
[versions]
kotlin = "2.3.0"
gradle = "9.1.0"
kotlin = "2.3.21"
gradle = "9.5.0"
sqldelight = "2.1.0"
coroutines = "1.10.1" # Hypothetische Version passend zu Kotlin 2.3
ktor = "3.1.0"
@@ -5,20 +5,20 @@ owner: Lead Architect
tags: [kotlin, java, configuration, setup]
---
# Tech-Stack Referenz: Kotlin 2.3.0 & Java 25 (KMP)
# Tech-Stack Referenz: Kotlin 2.3.21 & Java 25 (KMP)
**Kontext:** Dieses Dokument beschreibt die notwendigen Konfigurationen, um Kotlin 2.3.0 mit Java 25 in einem Kotlin Multiplatform (KMP) Projekt mit Gradle 9.x zu verwenden.
**Kontext:** Dieses Dokument beschreibt die notwendigen Konfigurationen, um Kotlin 2.3.21 mit Java 25 in einem Kotlin Multiplatform (KMP) Projekt mit Gradle 9.x zu verwenden.
---
### 1. Kern-Spezifikationen
| Komponente | Version | Status |
| --- |----------| --- |
| **Kotlin** | `2.3.0` | Stabil (K2 Compiler standardmäßig aktiv) |
| **Java (JDK)** | `25` | LTS (Long-Term Support) |
| **Gradle** | `9.2.1` | Erforderlich für JDK 25 Support |
| **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität |
| Komponente | Version | Status |
|--------------------------|----------|------------------------------------------|
| **Kotlin** | `2.3.21` | Stabil (K2 Compiler standardmäßig aktiv) |
| **Java (JDK)** | `25` | LTS (Long-Term Support) |
| **Gradle** | `9.5.0` | Erforderlich für JDK 25 Support |
| **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität |
---
@@ -28,7 +28,7 @@ Für ein **Kotlin Multiplatform (KMP)** Projekt ist die Java Toolchain-Konfigura
```kotlin
plugins {
kotlin("multiplatform") version "2.3.0"
kotlin("multiplatform") version "2.3.21"
id("com.android.library") version "8.8.0" // Falls Android Target genutzt wird
}
@@ -60,15 +60,15 @@ Damit das Projekt Java 25 erkennt, muss der Wrapper auf dem neuesten Stand sein:
**Terminal-Befehl:**
```bash
./gradlew wrapper --gradle-version 9.2.1 --distribution-type all
./gradlew wrapper --gradle-version 9.5.0 --distribution-type all
```
---
### 4. Wichtige Kompatibilitätshinweise
* **IDE-Version:** IntelliJ IDEA 2025.3 (oder neuer) wird für die volle Unterstützung von JDK 25 und dem Kotlin 2.3.0 Plugin empfohlen.
* **K2 Compiler:** Kotlin 2.3.0 nutzt den K2-Compiler.
* **IDE-Version:** IntelliJ IDEA 2025.3 (oder neuer) wird für die volle Unterstützung von JDK 25 und dem Kotlin 2.3.21 Plugin empfohlen.
* **K2 Compiler:** Kotlin 2.3.21 nutzt den K2-Compiler.
* **Bytecode:** Java 25 Bytecode wird nur generiert, wenn das `jvmTarget` explizit auf `25` gesetzt ist.
---
@@ -76,4 +76,4 @@ Damit das Projekt Java 25 erkennt, muss der Wrapper auf dem neuesten Stand sein:
### 5. Bekannte Features in diesem Setup
* **Java 25 Features:** Unterstützung für die finalen Versionen von *Scoped Values* und *Structured Concurrency*.
* **Kotlin 2.3.0 Features:** Nutzung von `explicit backing fields` und dem verbesserten `unused return value` Checker.
* **Kotlin 2.3.21 Features:** Nutzung von `explicit backing fields` und dem verbesserten `unused return value` Checker.
@@ -5,7 +5,7 @@ owner: Lead Architect
tags: [kotlin, release-notes, tech-stack]
---
# Was ist neu in Kotlin 2.3.0
# Was ist neu in Kotlin 2.3.21
**Quelle:** [Offizielle Kotlin-Dokumentation](https://kotlinlang.org/docs/whatsnew23.html)
**Datum des Dokuments:** 16. Dezember 2025
@@ -13,7 +13,7 @@ tags: [kotlin, release-notes, tech-stack]
---
Kotlin 2.3.0 ist erschienen! Hier sind die wichtigsten Highlights:
Kotlin 2.3.21 ist erschienen! Hier sind die wichtigsten Highlights:
* **Sprache:** Mehr stabile und standardmäßig aktivierte Features, Checker für ungenutzte Rückgabewerte, explizite Backing Fields und Änderungen bei der kontextsensitiven Auflösung.
* **Kotlin/JVM:** Unterstützung für Java 25.
@@ -26,7 +26,7 @@ Kotlin 2.3.0 ist erschienen! Hier sind die wichtigsten Highlights:
## Sprache
Kotlin 2.3.0 konzentriert sich auf die Stabilisierung von Features, führt einen neuen Mechanismus zur Erkennung ungenutzter Rückgabewerte ein und verbessert die kontextsensitive Auflösung.
Kotlin 2.3.21 konzentriert sich auf die Stabilisierung von Features, führt einen neuen Mechanismus zur Erkennung ungenutzter Rückgabewerte ein und verbessert die kontextsensitive Auflösung.
### Stabile Features
@@ -38,13 +38,13 @@ Folgende Features sind nun stabil:
* Unterstützung für `return`-Anweisungen in Ausdrucks-Bodies mit explizitem Rückgabetyp ist nun standardmäßig aktiviert.
### Experimentell: Checker für ungenutzte Rückgabewerte
Kotlin 2.3.0 führt den Checker für ungenutzte Rückgabewerte ein, um das versehentliche Ignorieren von Ergebnissen zu verhindern.
Kotlin 2.3.21 führt den Checker für ungenutzte Rückgabewerte ein, um das versehentliche Ignorieren von Ergebnissen zu verhindern.
### Experimentell: Explizite Backing Fields
Eine neue Syntax zur expliziten Deklaration des zugrundeliegenden Felds, das den Wert einer Property hält vereinfacht das verbreitete Backing-Properties-Muster.
## Kotlin/JVM: Unterstützung für Java 25
Ab Kotlin 2.3.0 kann der Compiler Klassen mit Java-25-Bytecode generieren.
Ab Kotlin 2.3.21 kann der Compiler Klassen mit Java-25-Bytecode generieren.
## Kotlin/Native
* **Verbesserter Swift-Export:** Direkte Zuordnung für native Enum-Klassen und variadische Funktionsparameter.
@@ -3,22 +3,26 @@
## 🏗️ [Lead Architect] | 14. April 2026
Dieses Dokument beschreibt die Umsetzung der Online-Nennung für das Turnier in Neumarkt (24. April 2026).
Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Service` sendet, welcher diese verarbeitet und in der Desktop-Zentrale zur manuellen Übernahme bereitstellt.
Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Service` sendet, welcher diese verarbeitet
und in der Desktop-Zentrale zur manuellen Übernahme bereitstellt.
---
### Phase 1: E-Mail-Infrastruktur (Vorbereitung) ✅
* [x] Definition des Adress-Schemas: `meldestelle-[Turnier-Nr]@mo-code.at`.
* [x] Konfiguration der World4You SMTP/IMAP Zugangsdaten.
* [x] Mailpit Integration für lokale Tests (bereits in `dc-ops.yaml`).
### Phase 2: Das Web-Formular (WasmJS Frontend) ✅
* [x] **Basis-UI:** Erstellung des Formulars gemäß Spezifikation (Reiter, Pferd, Lizenz, Bewerbe).
* [x] **Validierung:** Implementierung der Pflichtfeld-Prüfung (Buttonsperre bis alles ok).
* [x] **Mail-Versand:** Integration des API-Calls an das Backend (`mail-service`), um die Nennung zu speichern.
* [x] **DSGVO:** Checkbox und Hinweistext eingebaut.
### Phase 3: Mail-Service (Backend-Verarbeitung) 🏗️
* [x] **Endpoint:** POST-Endpunkt für direkte Nennungen aus dem Web-Formular implementiert.
* [ ] **Polling:** Implementierung des IMAP-Pollers (imap.world4you.com).
* [ ] **Parsing:** Extraktion der Turnier-Nummer aus dem `To`-Header und Mapping auf das Datenbank-Schema (Tenant).
@@ -26,12 +30,14 @@ Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Serv
* [x] **Persistence:** Speichern der eingegangenen "Nennungs-Mails" in einer temporären Tabelle.
### Phase 4: Desktop-Zentrale Integration ✅
* [x] **UI-Tab:** Neuer Reiter "Online-Eingang" in der Turnierverwaltung (`TurnierDetailScreen`).
* [x] **Vorschau:** Anzeige der eingegangenen Nennungen mit Details (`OnlineNennungEingangTabContent`).
* [x] **Übernahme:** "Übernehmen"-Button, der Reiter/Pferd in die Nennung vorausfüllt (`NennungViewModel`).
* [ ] **Abschluss:** Manueller "Bestätigen"-Button zum Versenden der finalen Bestätigungsmail.
### Phase 5: End-to-End Test & Deployment 🚀 (Deadline: 21.04.2026)
* [ ] Test-Nennung über Web-Formular (Mailpit).
* [ ] Verifikation der Schema-Zuordnung im Backend.
* [ ] Live-Test mit `online-nennen@mo-code.at`.
@@ -40,6 +46,7 @@ Ziel ist ein schlankes Web-Formular, das strukturierte E-Mails an den `Mail-Serv
---
### Meilensteine
1. **16.04.:** Web-Formular ist funktionsfähig (Senden möglich).
2. **18.04.:** Mail-Service verarbeitet Mails und sendet Auto-Antworten.
3. **20.04.:** Desktop-UI zur Übernahme ist fertig.
@@ -10,7 +10,9 @@ last_update: 2026-03-25
10. **🏗️ [Lead Architect]** | 5. April 2026
**Kontext:**
Der ZNS-Importer wurde für die Verarbeitung der Datei `RICHT01.dat` optimiert. Es wurde klargestellt, dass Richter (SatzID 'X') und Parcoursbauer (SatzID 'Y') gemeinsam in dieser Datei geliefert werden. Eine separate `PARCO01.dat` existiert nicht.
Der ZNS-Importer wurde für die Verarbeitung der Datei `RICHT01.dat` optimiert. Es wurde klargestellt, dass Richter (
SatzID 'X') und Parcoursbauer (SatzID 'Y') gemeinsam in dieser Datei geliefert werden. Eine separate `PARCO01.dat`
existiert nicht.
Um den `registration-context` und `actor-context` unter realistischen Bedingungen testen zu können, benötigen wir echte
Stammdaten (Reiter, Pferde, Vereine, Funktionäre). Diese Daten werden vom ÖPS (Österreichischer Pferdesportverband) in
Form einer `ZNS.zip` bereitgestellt.
@@ -51,7 +53,8 @@ gesteuert wird und die Daten persistent im Backend (`actor-context`) ablegt.
* ZIP-Entpackung in-memory implementiert (`ZnsImportService`).
* [x] **Legacy-Parser (CP850 Fixed-Width):**
* `ZnsLegacyParsers` in `core:zns-parser` (KMP-Modul) implementiert.
* Alle 4 Dateitypen (VEREIN01, LIZENZ01, PFERDE01, RICHT01) bytegenau gemappt. RICHT01 verarbeitet Richter ('X') und Parcoursbauer ('Y'). ✅
* Alle 4 Dateitypen (VEREIN01, LIZENZ01, PFERDE01, RICHT01) bytegenau gemappt. RICHT01 verarbeitet Richter ('X') und
Parcoursbauer ('Y'). ✅
### Phase 2: Domain-Mapping & Persistenz (👷 Backend Developer)
@@ -0,0 +1,89 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-15
---
# Frontend-Architektur & Modularisierungsstrategie
**Status:** ENTWURF
**Zuletzt aktualisiert:** 2026-01-19
**Kontext:** Migration zu Clean Architecture & Feature-Modulen
---
## 1. Übersicht
Die Frontend-Architektur von **Meldestelle** basiert auf **Kotlin Multiplatform (KMP)** mit **Compose Multiplatform**
für die Benutzeroberfläche. Wir folgen einem strikten **Clean Architecture**-Ansatz, um Testbarkeit, Skalierbarkeit und
Trennung der Zuständigkeiten sicherzustellen.
## 2. Modulstruktur
Das Projekt ist in folgende Schichten unterteilt:
### 2.1 Core-Module (`frontend/core`)
Wiederverwendbare Komponenten, die unabhängig von spezifischen Geschäftsfunktionen sind.
* `core-network`: Zentrale HTTP-Client-Konfiguration (Auth, Logging, ContentNegotiation).
* `core-sync`: Generische Synchronisierungslogik (`SyncManager`, `SyncableRepository`).
* `core-ui`: Gemeinsame UI-Komponenten und Design-System.
### 2.2 Feature-Module (`frontend/features`)
Jede Geschäftsdomäne (z.B. `ping`, `auth`, `events`) liegt in ihrem eigenen Modul.
Ein Feature-Modul MUSS die **Clean Architecture** Paketstruktur einhalten:
* `at.mocode.{feature}.feature.domain`
* **Entitäten:** Reine Datenklassen.
* **Interfaces:** Repository-Interfaces, Service-Interfaces.
* **Use Cases:** Geschäftslogik (optional, für komplexe Logik).
* `at.mocode.{feature}.feature.data`
* **Implementierungen:** Repository-Implementierungen, API-Clients.
* **DTOs:** Data Transfer Objects (wenn von Domain-Entitäten abweichend).
* `at.mocode.{feature}.feature.presentation`
* **ViewModels:** Zustandsverwaltung.
* **Screens:** Composable-Funktionen.
* `at.mocode.{feature}.feature.di`
* **Koin-Modul:** Konfiguration der Dependency Injection.
### 2.3 Shells (`frontend/shells`)
Anwendungs-Einstiegspunkte, die alles zusammenführen.
* `meldestelle-portal`: Die Haupt-Web-/Desktop-Anwendung.
## 3. Migrationsstrategie (Übergangsphase)
Wir migrieren aktuell von einer monolithischen `clients`-Paketstruktur zu modularen Feature-Modulen.
**Regeln für die Migration:**
1. **Neue Features:** Müssen direkt in `frontend/features/{name}` unter Verwendung der Clean Architecture-Struktur
implementiert werden.
2. **Bestehende Features:** Werden schrittweise migriert.
3. **Koexistenz:** Während des Übergangs ist Legacy-Code in `clients/` erlaubt, aber als veraltet markiert.
4. **Dependency Injection:** Legacy-Code muss die neuen Koin-Module verwenden, sofern verfügbar.
5. **Keine Ghost-Klassen:** Klassen nicht duplizieren. Wenn eine Klasse in ein Feature-Modul verschoben wird, muss die
alte in `clients/` gelöscht werden.
## 4. Wichtige Entscheidungen (ADRs)
### ADR-001: Entkopplung der Sync-Logik
* **Entscheidung:** ViewModels dürfen nicht direkt vom `SyncManager` abhängen.
* **Begründung:** Um einfacheres Testen zu ermöglichen und die Komplexität des generischen Sync-Mechanismus zu
verbergen.
* **Umsetzung:** Ein Domain-Service-Interface (z.B. `PingSyncService`) einführen, das den `SyncManager`-Aufruf kapselt.
### ADR-002: Feature-Modul-Isolation
* **Entscheidung:** Feature-Module sollten nach Möglichkeit nicht direkt voneinander abhängen.
* **Kommunikation:** Gemeinsame Core-Module oder lose Kopplung über Interfaces/Events verwenden, wenn modulübergreifende
Kommunikation nötig ist.
---
**Freigegeben von:** Lead Architect
@@ -3,11 +3,15 @@ type: Reference
status: ACTIVE
owner: Lead Architect
---
# Architektur: Das Platform-Modul
## Überblick
Das **Platform-Modul** ist das Rückgrat der Build-Infrastruktur des Meldestelle-Projekts. Seine alleinige Aufgabe ist die zentrale Verwaltung und Bereitstellung von Abhängigkeiten und deren Versionen. Dies stellt sicher, dass alle Module im gesamten Projekt dieselben Bibliotheksversionen verwenden, was Inkonsistenzen ("JAR Hell") verhindert und die Wartbarkeit drastisch verbessert.
Das **Platform-Modul** ist das Rückgrat der Build-Infrastruktur des Meldestelle-Projekts. Seine alleinige Aufgabe ist
die zentrale Verwaltung und Bereitstellung von Abhängigkeiten und deren Versionen. Dies stellt sicher, dass alle Module
im gesamten Projekt dieselben Bibliotheksversionen verwenden, was Inkonsistenzen ("JAR Hell") verhindert und die
Wartbarkeit drastisch verbessert.
Das Modul agiert als eine interne "Single Source of Truth" für alle externen Bibliotheken.
@@ -24,17 +28,21 @@ platform/
### `platform-bom`
Dies ist das wichtigste Modul der Plattform. Es ist als "Bill of Materials" (BOM) konfiguriert und nutzt das `java-platform`-Plugin von Gradle.
Dies ist das wichtigste Modul der Plattform. Es ist als "Bill of Materials" (BOM) konfiguriert und nutzt das
`java-platform`-Plugin von Gradle.
* **Zweck:** Definiert eine umfassende Liste von Abhängigkeiten und deren exakten, geprüften Versionen. Es importiert auch andere wichtige BOMs (z.B. von Spring Boot und Kotlin).
* **Funktionsweise:** Andere Module importieren diese BOM mit `platform(projects.platform.platformBom)`. Gradle sorgt dann dafür, dass alle transitiven und deklarierten Abhängigkeiten den in der BOM festgelegten Versionen entsprechen.
* **Zweck:** Definiert eine umfassende Liste von Abhängigkeiten und deren exakten, geprüften Versionen. Es importiert
auch andere wichtige BOMs (z.B. von Spring Boot und Kotlin).
* **Funktionsweise:** Andere Module importieren diese BOM mit `platform(projects.platform.platformBom)`. Gradle sorgt
dann dafür, dass alle transitiven und deklarierten Abhängigkeiten den in der BOM festgelegten Versionen entsprechen.
* **Vorteil:** Absolute Versionskontrolle über das gesamte Projekt.
### `platform-dependencies`
Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhängigkeiten bündelt.
* **Zweck:** Vereinfacht die `build.gradle.kts`-Dateien der Service-Module. Anstatt 5-6 einzelne `kotlinx`- und Logging-Bibliotheken hinzuzufügen, genügt eine einzige Abhängigkeit zu diesem Modul.
* **Zweck:** Vereinfacht die `build.gradle.kts`-Dateien der Service-Module. Anstatt 5-6 einzelne `kotlinx`- und
Logging-Bibliotheken hinzuzufügen, genügt eine einzige Abhängigkeit zu diesem Modul.
* **Verwendung:**
```kotlin
@@ -48,7 +56,8 @@ Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhäng
Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken.
* **Zweck:** Stellt ein konsistentes Set an Test-Frameworks (JUnit 5, MockK, AssertJ) und Werkzeugen (Testcontainers) für alle Module bereit.
* **Zweck:** Stellt ein konsistentes Set an Test-Frameworks (JUnit 5, MockK, AssertJ) und Werkzeugen (Testcontainers)
für alle Module bereit.
* **Verwendung:**
```kotlin
@@ -58,4 +67,5 @@ Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken.
}
```
* **Optimierung:** Dieses Modul nutzt die in `libs.versions.toml` definierten `[bundles]`, um die Build-Datei extrem kurz und lesbar zu halten.
* **Optimierung:** Dieses Modul nutzt die in `libs.versions.toml` definierten `[bundles]`, um die Build-Datei extrem
kurz und lesbar zu halten.
@@ -0,0 +1,362 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
date: 2026-03-07
---
# Meldestelle — Tech-Stack Zusammenfassung
> **Zweck:** Vollständige Referenz des eingesetzten Tech-Stacks im Projekt "Meldestelle".
> Dient als Basis für Recherchen zu Self-Hosted AI (Codegenerierung, RAG, Agenten).
> **Stand:** 07. März 2026
---
## 1. Überblick
Das Projekt "Meldestelle" ist eine **Kotlin-first, Cloud-native Microservices-Plattform** für die Verwaltung von
Reitsport-Meldungen (FEI / ÖTO). Es kombiniert ein **Kotlin Multiplatform (KMP) Frontend** mit einem **Spring Boot
Microservices Backend** auf einer vollständig self-hosted Infrastruktur.
```
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (KMP) │ Backend (Spring Boot / Kotlin JVM) │
│ Kotlin 2.3.21 / Compose │ Java 25 / Spring Boot 3.5.9 │
│ JS + WASM (geplant) │ Microservices + API-Gateway │
├─────────────────────────────────────────────────────────────────┤
│ Infrastruktur (Self-Hosted auf Zora / Proxmox) │
│ Keycloak · Consul · Valkey · PostgreSQL · Zipkin │
│ Prometheus · Grafana · Caddy · Pangolin-Tunnel │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. Sprachen & Laufzeiten
| Komponente | Sprache / Runtime | Version |
|:-----------|:-----------------------|:--------|
| Backend | Kotlin (JVM) | 2.3.21 |
| Frontend | Kotlin (KMP / JS) | 2.3.21 |
| JVM | Java (Eclipse Temurin) | 25 (EA) |
| Build | Gradle (Kotlin DSL) | 9.5.0 |
| Plattform | ARM64 (AArch64) | Linux |
---
## 3. Frontend — Kotlin Multiplatform (KMP)
### 3.1 Core-Framework
| Bibliothek | Version | Zweck |
|:----------------------|:--------|:---------------------------------|
| Kotlin Multiplatform | 2.3.21 | Cross-Platform-Basis (JS + WASM) |
| Compose Multiplatform | 1.10.0 | UI-Framework (Deklarativ) |
| Compose Hot Reload | 1.0.0 | Live-Reload im Dev-Modus |
| Koin (DI) | 4.1.1 | Dependency Injection |
| Koin Compose | 4.1.1 | DI-Integration für Compose |
| Ktor Client | 3.4.0 | HTTP-Client (Multiplatform) |
| Kotlin Serialization | 2.3.21 | JSON-Serialisierung |
### 3.2 Persistenz (Offline-First)
| Bibliothek | Version | Zweck |
|:----------------|:--------|:-----------------------------|
| SQLDelight | 2.2.1 | Cross-Platform SQL-Datenbank |
| SQLite (WASM) | 3.51.1 | SQLite für Browser/WASM |
| SQLite (Native) | 2.6.2 | SQLite für JVM/Desktop |
### 3.3 Build-Targets
| Target | Status | Anmerkung |
|:--------------|:-----------|:--------------------------|
| KotlinJS | ✅ Aktiv | Primäres Build-Target |
| WASM | ⏳ Geplant | Warten auf Alpha-Version |
| Desktop (JVM) | ⚙️ Möglich | uiDesktop 1.7.0 vorhanden |
### 3.4 Modul-Struktur
```
frontend/
├── core/
│ ├── core-network/ # Ktor HTTP-Client, Auth-Interceptor
│ ├── core-ui/ # Design-System, Tokens, Komponenten
│ ├── core-domain/ # Shared Domain-Models
│ └── core-data/ # Repository-Interfaces
├── features/
│ ├── ping-feature/ # ✅ Blueprint: MVVM + Repository + DI + Tests
│ └── members-feature/ # ⏳ Auskommentiert (nächste Phase)
└── shells/
└── meldestelle-portal/ # Web-App Shell (Caddy-served)
```
---
## 4. Backend — Spring Boot Microservices
### 4.1 Core-Framework
| Bibliothek | Version | Zweck |
|:-------------------------|:---------|:---------------------------------|
| Spring Boot | 3.5.9 | Microservices-Framework |
| Spring Cloud | 2025.0.1 | Service Discovery, Config |
| Spring Security (OAuth2) | (Boot) | JWT-Validierung, Resource Server |
| Spring Data JPA | (Boot) | ORM-Layer |
| Spring Data Valkey | 0.2.0 | Cache-Integration (Valkey/Redis) |
| Spring WebFlux | (Boot) | Reaktive API (Gateway) |
| Kotlin Coroutines | 2.3.21 | Async/Non-blocking |
### 4.2 Persistenz
| Bibliothek | Version | Zweck |
|:--------------------|:--------|:----------------------|
| PostgreSQL Driver | 42.7.8 | JDBC-Treiber |
| Exposed (JetBrains) | 1.0.0 | Kotlin-native SQL DSL |
| Flyway | 11.19.1 | Datenbank-Migrationen |
| HikariCP | 7.0.2 | Connection Pool |
> **Strategie (ADR-001):** Hybrid — JPA für einfache CRUD-Entities, Exposed für komplexe Queries und Domain-Logik.
### 4.3 Caching & Messaging
| Bibliothek | Version | Zweck |
|:--------------|:--------|:--------------------------------|
| Lettuce | 6.6.0 | Valkey/Redis-Client (reaktiv) |
| Redisson | 4.0.0 | Distributed Locks, Pub/Sub |
| Caffeine | 3.2.3 | In-Memory Cache (L1) |
| Reactor Kafka | 1.3.23 | Kafka-Client (Phase 3 / Outbox) |
### 4.4 Observability & Tracing
| Bibliothek | Version | Zweck |
|:-------------------|:--------|:-----------------------------|
| Micrometer | 1.16.1 | Metriken (Prometheus-Export) |
| Micrometer Tracing | 1.6.1 | Distributed Tracing |
| Zipkin Reporter | 3.5.1 | Trace-Export zu Zipkin |
| Logback | 1.5.25 | Logging |
### 4.5 Security
| Bibliothek | Version | Zweck |
|:-----------------------|:--------|:-------------------------|
| Keycloak Admin Client | 26.0.7 | Keycloak-API-Integration |
| Spring Security OAuth2 | (Boot) | JWT Resource Server |
| Jackson (Kotlin) | 3.0.3 | JSON-Serialisierung |
### 4.6 API & Dokumentation
| Bibliothek | Version | Zweck |
|:-------------------|:--------|:-----------------------|
| Springdoc OpenAPI | 3.0.0 | Swagger / OpenAPI 3.1 |
| Jakarta Annotation | 3.0.0 | Jakarta EE Annotations |
### 4.7 Modul-Struktur
```
backend/
├── infrastructure/
│ ├── gateway/ # ✅ API-Gateway (Spring Cloud Gateway)
│ ├── security/ # ✅ Zentrales OAuth2/JWT-Modul (DRY)
│ ├── cache/
│ │ ├── cache-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── event-store/
│ │ ├── event-store-api/ # Interface-Abstraktion
│ │ └── valkey-impl/ # Valkey-Implementierung
│ ├── persistence/ # Hybrid JPA + Exposed
│ └── messaging/ # Kafka (Phase 3 / Outbox-Pattern)
└── services/
├── ping/ # ✅ Deployed — Test/Blueprint-Service
├── entries/ # ⚙️ Registriert, noch nicht deployed
├── events/ # 👻 Ghost Service (nicht registriert)
├── horses/ # 👻 Ghost Service (nicht registriert)
├── masterdata/ # 👻 Ghost Service (nicht registriert)
├── registry/ # 👻 Ghost Service (nicht registriert)
├── results/ # 👻 Ghost Service (nicht registriert)
└── scheduling/ # 👻 Ghost Service (nicht registriert)
```
---
## 5. Infrastruktur-Services (Docker)
### 5.1 Laufende Services
| Service | Image / Version | Port(s) | Zweck |
|:-------------|:-----------------------|:-----------|:----------------------------|
| PostgreSQL | postgres:16-alpine | 5432 | Primäre Datenbank |
| Keycloak | keycloak:26.4 (custom) | 8180, 9000 | IAM / OAuth2 / OIDC |
| Valkey | valkey:8-alpine | 6379 | Cache + Event-Store |
| Consul | consul:1.21 | 8500, 8600 | Service Discovery + Config |
| Zipkin | openzipkin/zipkin:3.5 | 9411 | Distributed Tracing |
| Prometheus | prom/prometheus:v3.4 | 9090 | Metriken-Sammlung |
| Grafana | grafana/grafana:11.6 | 3000 | Dashboards / Visualisierung |
| Caddy | caddy:2.10-alpine | 4000 | Web-App Serving (Frontend) |
| API-Gateway | (custom Spring Boot) | 8081 | Zentraler Eintrittspunkt |
| Ping-Service | (custom Spring Boot) | 8082 | Test/Blueprint-Service |
### 5.2 CI/CD & DevOps
| Tool | Version / Details | Zweck |
|:--------------|:---------------------|:------------------------------|
| Gitea | Self-Hosted (CT 101) | Git-Repository + Registry |
| Gitea Actions | (Runner VM 102) | CI/CD-Pipeline |
| Docker Buildx | ARM64 (linux/arm64) | Multi-Arch Image Build |
| Pangolin | Self-Hosted Tunnel | Reverse Proxy / Extern-Zugang |
### 5.3 Netzwerk & Routing
| Subdomain | Intern (Zora) | Zweck |
|:--------------------|:-----------------|:---------------|
| `git.mo-code.at` | `10.0.0.22:3000` | Gitea |
| `api.mo-code.at` | `10.0.0.50:8081` | API-Gateway |
| `auth.mo-code.at` | `10.0.0.50:8180` | Keycloak |
| `app.mo-code.at` | `10.0.0.50:4000` | Web-App |
| `photos.mo-code.at` | `10.0.0.24:2283` | Immich (Fotos) |
---
## 6. Code-Qualität & Build-Tools
| Tool | Version | Zweck |
|:-------------------|:--------|:---------------------------------|
| Detekt | 1.23.6 | Kotlin Static Analysis |
| ktlint | 12.1.1 | Kotlin Code Formatter |
| ArchUnit | 1.4.1 | Architektur-Tests (Layer-Regeln) |
| Dokka | 2.1.0 | API-Dokumentation (KDoc) |
| Ben-Manes Versions | 0.51.0 | Dependency-Update-Check |
| KSP | 2.3.4 | Kotlin Symbol Processing |
### Build-Konfiguration
```properties
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.workers.max=8
org.gradle.configuration-cache=false # wegen JS-Test Serialisierungsproblem
org.gradle.dependency.verification=strict
```
---
## 7. Test-Stack
| Bibliothek | Version | Zweck |
|:--------------------------|:--------|:-----------------------------|
| JUnit Jupiter | 5.11.3 | Unit-Tests |
| JUnit Platform | 1.11.3 | Test-Runner |
| MockK | 1.14.7 | Kotlin Mocking |
| AssertJ | 3.27.7 | Fluent Assertions |
| Testcontainers | 2.0.3 | Integration-Tests (Docker) |
| Testcontainers Keycloak | 4.0.1 | Keycloak-Integration-Tests |
| Testcontainers PostgreSQL | 1.21.4 | DB-Integration-Tests |
| Testcontainers Kafka | 1.21.4 | Kafka-Integration-Tests |
| ArchUnit | 1.4.1 | Architektur-Compliance-Tests |
---
## 8. Architektur-Prinzipien (ADRs)
| ADR | Entscheidung | Status |
|:-----|:--------------------------------------------------|:--------|
| 0001 | Modulare Architektur (DDD, Clean Architecture) | ✅ Aktiv |
| 0003 | Microservices-Architektur | ✅ Aktiv |
| 0004 | Event-Driven Communication (Kafka Phase 3) | ✅ Aktiv |
| 001 | Backend-Infrastruktur: Hybrid JPA+Exposed, Valkey | ✅ Aktiv |
| 0013 | Tech-Stack-Stabilisierung 2026 (Versionen) | ✅ Aktiv |
**Kern-Prinzipien:**
- **Offline-First:** SQLDelight als Cross-Platform-DB, Sync-Mechanismus
- **Docs-as-Code:** `/docs` als Single Source of Truth
- **DRY-Infrastruktur:** Shared Security/Cache/EventStore-Module
- **ARM64-Native:** Alle Images für `linux/arm64` gebaut
---
## 9. Relevanz für Self-Hosted AI
### 9.1 Welche AI-Aufgaben entstehen im Projekt?
| Aufgabe | Häufigkeit | Komplexität |
|:-----------------------------------|:-------------|:------------|
| Kotlin/Spring Boot Code-Completion | Täglich | Mittel |
| Compose Multiplatform UI-Code | Täglich | Mittel |
| SQL / Exposed DSL Queries | Häufig | Mittel |
| Gradle Kotlin DSL Build-Skripte | Gelegentlich | Niedrig |
| Docker / YAML Konfigurationen | Gelegentlich | Niedrig |
| Architektur-Entscheidungen (ADR) | Selten | Hoch |
| Fachlogik FEI/ÖTO Regelwerk | Selten | Sehr hoch |
### 9.2 Anforderungen an das AI-Modell
```
MUSS:
✅ Kotlin (JVM + Multiplatform) — sehr gute Unterstützung
✅ Spring Boot / Spring Cloud — sehr gute Unterstützung
✅ Compose Multiplatform — gute Unterstützung (neuere Modelle)
✅ SQL / PostgreSQL — sehr gute Unterstützung
✅ Docker / YAML — sehr gute Unterstützung
✅ Deutsch (Fachsprache Reitsport) — für RAG-Dokumente
NICE-TO-HAVE:
⭐ Gradle Kotlin DSL
⭐ Keycloak / OAuth2 / OIDC
⭐ Microservices-Architektur-Patterns
```
### 9.3 Empfohlene Modelle für diesen Stack
| Modell | Größe | Stärke | RAM-Bedarf |
|:------------------------|:------|:----------------------------------|:-----------|
| `qwen2.5-coder:14b` | 14B | Code (Kotlin, Java, SQL) — Top | ~10 GB |
| `deepseek-coder-v2:16b` | 16B | Code-Completion, Refactoring | ~12 GB |
| `llama3.1:8b` | 8B | Allgemein + Deutsch, schnell | ~6 GB |
| `qwen2.5:32b` | 32B | Architektur, Planung, Fachlogik | ~22 GB |
| `codellama:13b` | 13B | Code-Completion (IntelliJ-Plugin) | ~9 GB |
> **Empfehlung für Zora (64 GB RAM):**
> - **Primär:** `qwen2.5-coder:14b` — bester Kotlin/Spring-Support
> - **Sekundär:** `qwen2.5:32b` — für Architektur und Fachlogik
> - **IntelliJ-Integration:** `codellama:13b` oder `qwen2.5-coder:14b`
### 9.4 RAG-Dokumente (Priorität)
Folgende Projekt-Dokumente sind besonders wertvoll als RAG-Kontext:
```
Hohe Priorität:
├── docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md
├── docs/01_Architecture/adr/ (alle ADRs)
├── docs/04_Agents/Playbooks/ (Agenten-Rollen)
├── gradle/libs.versions.toml (Versions-SSoT)
└── docs/07_Infrastructure/ (Infrastruktur-Referenz)
Mittlere Priorität:
├── docs/05_Backend/ (Backend-Guides)
├── docs/06_Frontend/ (Frontend-Guides)
└── docs/03_Domain/ (Fachlogik-Konzepte)
```
---
## 10. Zusammenfassung
```
TECH-STACK KOMPLEXITÄT
──────────────────────────────────────────────────────
Sprachen: Kotlin (JVM + KMP/JS)
Build: Gradle 9.5.0 + Kotlin DSL + libs.versions.toml
Frontend: Compose Multiplatform 1.10 + SQLDelight 2.2 + Koin 4.1
Backend: Spring Boot 3.5.9 + Spring Cloud 2025.0.1
Persistenz: PostgreSQL 16 + Exposed 1.0 + Flyway 11 + HikariCP 7
Cache: Valkey 8 + Lettuce 6.6 + Caffeine 3.2
Security: Keycloak 26.4 + Spring Security OAuth2 + JWT
Observability: Micrometer 1.16 + Zipkin 3.5 + Prometheus + Grafana 11.6
Service Mesh: Consul 1.21 + Spring Cloud Gateway
Messaging: Kafka (Phase 3) + Reactor Kafka 1.3
CI/CD: Gitea Actions + Docker Buildx (ARM64)
Hosting: Proxmox VE 8.4 + Docker Compose + Pangolin-Tunnel
```
@@ -13,7 +13,7 @@ Feature-Implementierung an der verfeinerten DDD-Struktur (ADR-0014) sowie der De
### 🟢 Technische Stabilisierung
* **Kotlin 2.3.20:** Alle Module wurden auf Kotlin 2.3.20 migriert. Deprecation-Warnungen für `Clock` und `Instant`
* **Kotlin 2.3.21:** Alle Module wurden auf Kotlin 2.3.21 migriert. Deprecation-Warnungen für `Clock` und `Instant`
wurden durch Standardisierung auf `kotlin.time.*` behoben.
* **Zentralisierte Serialisierung:** Erstellung der `Serializers.kt` im `core-domain` Modul für `Uuid`, `Instant`,
`LocalDate`, `LocalDateTime` und `LocalTime`.
@@ -10,23 +10,27 @@ Cups/Serien.
## 1) Fokus-Themen und Deliverables (heute Nacht)
1. Reporting & Output (Vorbereitung)
- [Owner] Vorlagen sammeln/übermitteln: Startlisten, Ergebnislisten (PDF/Scan/Excel)
- [Owner] Spring-Protokolle: Inhalte/Felder definieren (Fehler, Zeit, Stechen)
- [Owner] Dressur-Protokolle: Vorlage für personalisierten Ausdruck (Kopfzeile Reiter/Pferd)
- [Arch/BE] Technik-Entscheidung PDF: KMP-Library vs. Server-Side Rendering (ADR-Entwurf)
- [FE] UI-Draft „Druckvorschau“ in V2-Screens: Platzhalter mit Beispiel-Daten
- [Owner] Vorlagen sammeln/übermitteln: Startlisten, Ergebnislisten (PDF/Scan/Excel)
- [Owner] Spring-Protokolle: Inhalte/Felder definieren (Fehler, Zeit, Stechen)
- [Owner] Dressur-Protokolle: Vorlage für personalisierten Ausdruck (Kopfzeile Reiter/Pferd)
- [Arch/BE] Technik-Entscheidung PDF: KMP-Library vs. Server-Side Rendering (ADR-Entwurf)
- [FE] UI-Draft „Druckvorschau“ in V2-Screens: Platzhalter mit Beispiel-Daten
2. Events/Turniere (Backend-Readiness für Neumarkt)
- [BE] DB-Migrationen finalisieren: `turniere`, `ausschreibungen` (Flyway)
- [BE] Seed-Datensatz „Veranstaltung Neumarkt 2026“ (+ 12 Turniere)
- [BE] Repositories prüfen und Test-Cases anlegen (Roundtrip CRUD)
- [BE] DB-Migrationen finalisieren: `turniere`, `ausschreibungen` (Flyway)
- [BE] Seed-Datensatz „Veranstaltung Neumarkt 2026“ (+ 12 Turniere)
- [BE] Repositories prüfen und Test-Cases anlegen (Roundtrip CRUD)
3. Identity & Profil (Verifikation)
- [QA] E2E-Check „ZNS-Link“: Login → Profile → Satznummer verknüpfen → Refresh
- [FE] Validation/UX-Polish im `profile-feature`
- [QA] E2E-Check „ZNS-Link“: Login → Profile → Satznummer verknüpfen → Refresh
- [FE] Validation/UX-Polish im `profile-feature`
4. Live-Ergebnisse Vision (Input sammeln)
- [Owner] Skizze/Mock für mobile Web-Ansicht (Zuschauer): Bewerb → Abteilungen → Live-Board
- [Owner] Skizze/Mock für mobile Web-Ansicht (Zuschauer): Bewerb → Abteilungen → Live-Board
---
@@ -11,17 +11,17 @@ last_update: 2026-01-20
Angenommen
## Kontext
Das Projekt "Meldestelle" setzt auf einen sehr modernen Technologie-Stack (Java 25, Kotlin 2.3.0, Spring Boot 3.5.9). Eine Analyse im Januar 2026 hat jedoch kritische Versionskonflikte aufgedeckt, die die Stabilität des Builds und der Laufzeitumgebung gefährden.
Das Projekt "Meldestelle" setzt auf einen sehr modernen Technologie-Stack (Java 25, Kotlin 2.3.21, Spring Boot 3.5.9). Eine Analyse im Januar 2026 hat jedoch kritische Versionskonflikte aufgedeckt, die die Stabilität des Builds und der Laufzeitumgebung gefährden.
1. **Spring Cloud Konflikt:** Der Release Train `2025.1.0` (Oakwood) ist für Spring Boot 4.0 konzipiert und inkompatibel mit Spring Boot 3.5.9 (führt zu `NoSuchMethodError`).
2. **Compose Multiplatform:** Version `1.9.3` führt zu Compiler-Crashes in Verbindung mit Kotlin 2.3.0.
3. **Exposed:** Version `0.61.0` ist veraltet und inkompatibel mit Kotlin 2.3.0.
2. **Compose Multiplatform:** Version `1.9.3` führt zu Compiler-Crashes in Verbindung mit Kotlin 2.3.21.
3. **Exposed:** Version `0.61.0` ist veraltet und inkompatibel mit Kotlin 2.3.21.
## Entscheidung
Wir führen folgende Korrekturen am Tech-Stack durch, um eine stabile "Best Compatibility List" zu etablieren:
1. **Spring Cloud Downgrade:** Wechsel auf Release Train `2025.0.1` (Northfields), der offiziell für Spring Boot 3.5.x freigegeben ist.
2. **Compose Multiplatform Upgrade:** Wechsel auf `1.10.0-rc02` (oder stable), um volle Kotlin 2.3.0 Kompatibilität zu gewährleisten.
2. **Compose Multiplatform Upgrade:** Wechsel auf `1.10.0-rc02` (oder stable), um volle Kotlin 2.3.21 Kompatibilität zu gewährleisten.
3. **Exposed Upgrade:** Wechsel auf `1.0.0-rc-4` (oder neuer), um Bytecode-Inkompatibilitäten zu beheben.
4. **Micrometer Upgrade:** Explizites Setzen von Version `1.16.1` für verbesserten Java 25 (Virtual Threads) Support.
@@ -29,7 +29,7 @@ Wir führen folgende Korrekturen am Tech-Stack durch, um eine stabile "Best Comp
### Positiv
* **Stabilität:** Der Build und die Application Context Initialisierung sind wieder stabil.
* **Zukunftssicherheit:** Wir nutzen weiterhin die neuesten Features von Java 25 und Kotlin 2.3.0, aber in einer validierten Kombination.
* **Zukunftssicherheit:** Wir nutzen weiterhin die neuesten Features von Java 25 und Kotlin 2.3.21, aber in einer validierten Kombination.
* **Wartbarkeit:** Die `libs.versions.toml` spiegelt nun eine getestete Konfiguration wider.
### Negativ
@@ -0,0 +1,22 @@
# ADR-0025: "Plan-USB" & Offline-Datenintegrität
## Status
In Prüfung (Wartet auf PoC)
## Kontext
Im professionellen Turniersport ist eine stabile Netzwerkverbindung (LAN/WLAN) nicht immer garantiert. Ein Ausfall des Netzwerks darf den laufenden Betrieb (Ergebniserfassung, Meldestelle) nicht blockieren. Zudem müssen sensible Reiter- und Pferdedaten (DSGVO) auch auf physischen Datenträgern geschützt sein.
## Entscheidung
Wir führen die "Plan-USB" Strategie als primären Fallback und parallelen Sicherungsmechanismus ein.
1. **Permanenter Delta-Export:** Der Master-PC schreibt kontinuierlich verschlüsselte Delta-Pakete (JSON-basiert) in ein definiertes Backup-Verzeichnis. Dies ist bereits in der UI als Pfad-Option vorbereitet.
2. **Verschlüsselung:** Alle Daten auf dem USB-Stick werden mit dem `Shared Key` (AES-256) verschlüsselt. Der Benutzer legt diesen Schlüssel einmalig während der Initialisierung fest.
3. **Datenintegrität:** Pakete werden signiert, um Manipulationen durch Texteditoren zu verhindern.
4. **Sync-Vorschau:** Die UI bietet eine visuelle Bestätigung ("Sync-Dashboard"), welche Daten zuletzt erfolgreich auf den Stick geschrieben wurden. (Umgesetzt im UI-Design der Initialisierung).
5. **Manueller Not-Import:** Clients erhalten eine Funktion, um Delta-Pakete manuell von einem Stick einzulesen und eigene Ergebnisse dorthin zurückzuschreiben.
## Konsequenzen
- Erhöhte Komplexität in der Sync-Logik (Hybrid-Modus: Netzwerk + Datei).
- Benutzer muss initial einen `Shared Key` festlegen.
- Rechtliche Absicherung bei Verlust von Hardware durch Verschlüsselung.
- Maximale Ausfallsicherheit: Das Turnier kann rein via USB-Stick ("Turnschuh-Netzwerk") zu Ende geführt werden.
@@ -0,0 +1,23 @@
# ADR-0026: Offline-Lizenzierung ("Pay-per-Event")
## Status
Vorgeschlagen
## Kontext
Die Software wird als Service pro Veranstaltung lizenziert. Da die App primär offline betrieben wird (Meldestelle am Turnierplatz), kann keine permanente Online-Verbindung zur Lizenzprüfung vorausgesetzt werden.
## Entscheidung
Wir implementieren ein ticketbasiertes Offline-Lizenzmodell.
1. **Online-Erwerb:** Der Veranstalter kauft ein "Event-Ticket" über das zentrale Web-Backend.
2. **Lizenz-Datei:** Das Backend generiert eine digital signierte Lizenz-Datei (`.mlic`). Diese enthält:
- Veranstalter-Identität (OEPS-Nummer).
- Gültigkeitszeitraum (Von-Bis).
- Event-Typ (z.B. CSN-B*).
3. **Offline-Aktivierung:** Im `EventWizard` der Desktop-App wird die Lizenz-Datei hochgeladen. Die App validiert die Signatur gegen unseren Public-Key (völlig offline).
4. **Hardware-Fingerprint:** Die Lizenz wird beim ersten Import an die Hardware-ID des Master-PCs gebunden, um unkontrollierte Vervielfältigung zu verhindern.
## Konsequenzen
- Benutzer muss einmalig (vor dem Turnier) Internetzugang haben, um die Lizenzdatei herunterzuladen.
- Keine Abhängigkeit von Server-Verfügbarkeit während des Turniers.
- Sicherer Schutz unseres Geschäftsmodells ohne Gängelung des ehrlichen Nutzers.
@@ -0,0 +1,33 @@
# ADR-0027: Netzwerk-Discovery & Interface-Binding
## Status
Akzeptiert & Implementiert (05.05.2026)
## Kontext
Desktop-Rechner auf Turnieren sind oft mit mehreren Netzwerken gleichzeitig verbunden (z.B. LAN für das
Turnier-Netzwerk, WLAN für Internet-Hotspot). Automatische Discovery-Dienste (mDNS) wählen ohne explizite Konfiguration
oft ein Interface, das für die anderen Teilnehmer nicht erreichbar ist (Bridging-Probleme zwischen LAN und WLAN). Zudem
blockieren einige Router Multicast-Pakete zwischen WLAN und LAN-Segmenten.
## Entscheidung
Wir führen ein robustes, mehrstufiges Netzwerk-Management für die Initialisierung ein:
1. **Multi-Interface Broadcast:** Der Master registriert seinen Dienst proaktiv auf **allen** verfügbaren
Netzwerk-Interfaces (IPv4). Dies erhöht die Chance massiv, dass Clients in verschiedenen Segmenten (WLAN/LAN) den
Master finden.
2. **Interface-Selektion:** Der Benutzer kann weiterhin ein bevorzugtes Interface wählen. Die Master-Info-Card zeigt die
Erreichbarkeit transparent an.
3. **Manueller IP-Fallback:** Wenn mDNS fehlschlägt, kann die IP des Masters manuell eingegeben werden. Dies ist der "
Ultima-Ratio"-Weg für restriktive Netzwerke.
4. **Konnektivitäts-Check (Chat & Self-Test):** Nach dem Handshake wird ein Modal geöffnet, das einen automatischen
Ping-Pong Test durchführt und einen Test-Chat bietet. Dies verifiziert die reale Datenübertragung (Serialisierung,
WebSockets) noch vor Abschluss des Setups.
## Konsequenzen
- Deutlich höhere Stabilität in heterogenen Netzwerkumgebungen.
- Transparenteres Feedback für den Anwender bei Verbindungsproblemen.
- Der Chat dient als "Connectivity-Proof" für das Support-Personal vor Ort.
@@ -1,51 +0,0 @@
# 🤖 Konzept: Status-Automat für Nennungen & Zeitplan-Synchronisation
Dieses Dokument spezifiziert die Logik des Status-Automaten für Nennungen (Sprint C-1) und dessen Auswirkungen auf den dynamischen Zeitplan.
## 1. Status-Definitionen (NennStatusE)
Basierend auf `core-domain/Enums.kt`:
| Status | Bedeutung | Auswirkung auf Zeitplan |
| :--- | :--- | :--- |
| `EINGEGANGEN` | Nennung wurde erstellt (Initialzustand) | Belegt Zeitslot (basierend auf `reitdauerMinuten`) |
| `BESTAETIGT` | Meldestelle hat Nennung geprüft | Belegt Zeitslot |
| `NACHNENNUNG` | Nennung nach Nennschluss | Belegt Zeitslot (ggf. am Ende der Liste) |
| `TRANSFERIERT` | Nennung wurde auf anderes Paar übertragen | **Inaktiv** (Original-Eintrag wird durch neuen ersetzt) |
| `ZURUECKGEZOGEN`| Reiter hat abgemeldet (vor Startlistenerstellung) | **Inaktiv** (Slot wird frei) |
| `GESTARTET` | Paar ist in die Prüfung eingeritten | Startzeitpunkt fixiert, Folgestarts ggf. anpassen |
| `NICHT_ANGETRETEN`| Paar ist zum Startzeitpunkt nicht erschienen | **Zeitslot verfällt** oder Folgestarts rücken nach |
## 2. Status-Übergänge & Validierung
### 2.1 Gültige Übergänge (Beispiele)
- `EINGEGANGEN` -> `BESTAETIGT` (Normalfall)
- `EINGEGANGEN` -> `ZURUECKGEZOGEN` (Abmeldung)
- `BESTAETIGT` -> `TRANSFERIERT` (Reitertausch)
- `BESTAETIGT` -> `GESTARTET` (Während des Turniers)
### 2.2 Side-Effects (Side-Effect-Engine)
Wenn sich der Status einer Nennung ändert, müssen folgende Systeme informiert werden:
1. **Billing-Service:** Bei `ZURUECKGEZOGEN` ggf. Stornogebühren prüfen. Bei `TRANSFERIERT` Guthaben übertragen.
2. **Startlisten-Service:** Bei `ZURUECKGEZOGEN` nach Veröffentlichung der Startliste -> Eintrag als `istGestrichen = true` markieren.
3. **Zeitplan-Optimierung:** Bei `NICHT_ANGETRETEN` -> Alle folgenden Startzeiten rücken um `reitdauerMinuten` nach vorne (sofern im Kalender-Modus "Dynamisch" aktiv ist).
## 3. Dynamische Zeitplan-Anpassung (C-1 Extension)
Der `StartlistenService` muss eine Methode `aktualisiereZeitplanNachStatusAenderung` erhalten:
- **Szenario A (Nicht angetreten):** Wenn Nennung X `NICHT_ANGETRETEN` wird, rücken alle folgenden Nennungen in der Abteilung nach vorne.
- **Szenario B (Verspätung):** Wenn Nennung X `GESTARTET` wird, aber 2 Minuten später als geplant, verschieben sich alle Folgetermine um +2 Minuten (Kettenreaktion).
### Puffer-Regel (ÖTO-Konformität)
- Eine dynamische Verschiebung nach *vorne* darf nie dazu führen, dass ein Reiter vor seiner ursprünglich kommunizierten Startzeit (oder einem definierten Puffer-Zeitraum von z.B. 15 Minuten) starten muss, ohne dass dies explizit bestätigt wurde.
## 4. Implementierungs-Leitfaden für Backend (C-1)
1. Erweiterung von `NennungUseCases.statusAendern` um Aufrufe der Side-Effect-Handler.
2. Implementierung des `NennungStatusListener` in `entries-service`.
3. Anbindung an den `StartlistenService` zur Zeitre-Kalkulation.
---
**Status:** Entwurf (Lead Architect)
**Datum:** 11. April 2026
@@ -0,0 +1,92 @@
# 🛠️ Guide: Conveyor Installation
Dieses Dokument beschreibt die Installation von **Hydraulic Conveyor** auf verschiedenen Linux-Distributionen (Ubuntu
26.04 und Fedora 44).
---
## 1. Ubuntu 26.04 (Debian-basiert)
Der am einfachsten Weg für Ubuntu ist der direkte Download des `.deb`-Pakets. Dieses konfiguriert bei der Installation
automatisch das APT-Repository für zukünftige Updates.
### Installation via .deb (Empfohlen)
```bash
# Aktuelles Paket herunterladen (Beispiel v12.0 - bitte Version ggf. anpassen)
VERSION="12.0"
curl -L https://downloads.hydraulic.dev/conveyor/conveyor_${VERSION}_amd64.deb -o conveyor.deb
# Installieren (konfiguriert auch das Repo automatisch)
sudo apt update
sudo apt install ./conveyor.deb
```
---
## 2. Fedora 44 (RPM-basiert)
Für Fedora wird die Installation via Tarball empfohlen, da Conveyor als autarkes Binary geliefert wird.
### Installation via Tarball (Systemweit)
Dies ist der zuverlässigste Weg für Fedora:
```bash
# Version definieren (Beispiel v12.0, bitte aktuelle Version prüfen)
VERSION="12.0"
curl -L https://downloads.hydraulic.dev/conveyor/conveyor-${VERSION}-linux-amd64.tar.gz -o conveyor.tar.gz
# Entpacken nach /opt
sudo tar -xzf conveyor.tar.gz -C /opt/
sudo ln -s /opt/conveyor-${VERSION}/bin/conveyor /usr/local/bin/conveyor
# Test
conveyor --version
```
### Installation via RPM (Falls verfügbar)
Prüfen Sie auf der Hydraulic Website, ob mittlerweile ein natives RPM-Repository existiert. Falls ja:
```bash
sudo dnf config-manager --add-repo https://conveyor.hydraulic.dev/rpm/conveyor.repo
sudo dnf install conveyor
```
---
## 3. Post-Installation & Verifikation
Nach der Installation sollten Sie den Pfad und die Version prüfen:
```bash
conveyor --version
```
### Root-Key Initialisierung
Beim ersten Ausführen von `conveyor` wird ein Root-Key generiert. **Sichern Sie diesen unbedingt!**
```bash
conveyor make site
```
*Folgen Sie den Anweisungen im Terminal zur Sicherung des Root-Keys.*
---
## 4. Troubleshooting
### Fehlende Bibliotheken (Fedora)
Falls Conveyor native Hilfe benötigt (z.B. für Icons oder Kompression):
```bash
sudo dnf install libX11 libXext libXrender
```
### Berechtigungen
Stellen Sie sicher, dass Ihr Benutzer in der Gruppe `docker` ist, falls Sie Conveyor innerhalb von Containern nutzen
oder Docker-basierte Inputs verwenden (für dieses Projekt primär lokal relevant).
+112
View File
@@ -0,0 +1,112 @@
# 📦 Guide: Desktop App Packaging (Conveyor & Gradle)
Dieses Dokument beschreibt den professionellen Packaging-Prozess für die Meldestelle Desktop App. Wir nutzen **Conveyor** als primäres Werkzeug für das Cross-Platform Packaging (Windows, Linux, macOS), da es stabile Installer inklusive signierter Updates und gebündelter JREs erzeugt.
---
## 1. Strategie: Conveyor vs. Gradle
| Feature | Conveyor (Empfohlen) | Gradle (Compose Plugin) |
| :--- | :--- | :--- |
| **Zielgruppe** | Endanwender (Produktion) | Entwickler (Lokaler Test) |
| **Plattformen** | Windows (.msix), Linux (.deb), macOS | Nur Host-OS (Linux auf Linux) |
| **Updates** | Automatisch integriert | Manuell |
| **JRE** | Amazon Corretto (isoliert) | System JRE oder Toolchain |
---
## 2. Cross-Packaging mit Conveyor
Conveyor ist so konfiguriert, dass es von Linux aus Pakete für alle Zielsysteme schnüren kann.
### Voraussetzungen
1. **JAR-Dateien:** Die App muss kompiliert sein:
```bash
./gradlew :frontend:shells:meldestelle-desktop:jvmJar
```
2. **Icons:** Das System sucht nach `icon.png` in `frontend/shells/meldestelle-desktop/src/jvmMain/resources/`.
### Pakete bauen
Führen Sie Conveyor im Projekt-Root aus:
```bash
# Komplette Release-Site (Windows & Linux)
conveyor make site
# Nur ein spezifisches Paket (schneller für Tests)
conveyor make debian-package # Linux .deb
conveyor make windows-msix # Windows .msix
```
Die Ergebnisse liegen im Ordner `output/`.
---
## 3. Konfiguration (`conveyor.conf`)
Wichtige Parameter der aktuellen Konfiguration (v1.0.1):
* **JDK:** Nutzt `Amazon Corretto 21` für maximale Cross-Platform Stabilität.
* **Heap-Size:** Erhöht auf `-Xmx1024m`, um auch große Stammdaten-Importe zu bewältigen.
* **Linux-Deps:** Automatische Installation von `libasound2`, `libgl1-mesa-glx` und `libx11-6`.
* **Native Access:** `--enable-native-access=ALL-UNNAMED` ist für Netty/SQLite aktiviert.
---
## 4. Netzwerk & Sicherheit (WICHTIG)
Damit die P2P-Funktionen (Chat, Discovery, Sync) nach der Installation funktionieren, müssen folgende Ports auf dem Host-System offen sein:
| Port | Protokoll | Funktion |
| :--- | :--- | :--- |
| **8080** | TCP | P2P Sync & Datenabgleich |
| **8090** | TCP | Veranstaltungs-Chat (WebSocket) |
| **5353** | UDP | mDNS Discovery (Geräte finden) |
### Firewall-Einrichtung (Linux)
Nutzen Sie das optimierte Setup-Script:
```bash
sudo ./setup-firewall-linux.sh
```
### Windows-Besonderheit
Beim ersten Start der `.msix` App wird Windows fragen, ob der Netzwerkzugriff erlaubt werden soll. **Wichtig:** Sowohl "Private" als auch "Öffentliche" Netzwerke anhaken, falls auf Turnieren oft Gast-WLANs oder Hotspots genutzt werden.
---
## 5. Troubleshooting
### Problem: "No main class specified"
**Lösung:** Stellen Sie sicher, dass in der `Main.kt` eine saubere Top-Level `fun main()` existiert und in der `conveyor.conf` auf `at.mocode.frontend.shell.desktop.MainKt` verwiesen wird.
### Problem: SQLite / Native Libs laden nicht
**Lösung:** Prüfen Sie, ob `extract-native-libraries.conf` in der `conveyor.conf` inkludiert ist.
### Problem: JmDNS findet keine Teilnehmer
**Lösung:** Prüfen Sie die Ports via `ss -tulpn`. Auf Linux blockieren oft Docker-Interfaces (`br-*`) den Broadcast. Die App filtert diese nun automatisch, aber ein aktives `setup-firewall-linux.sh` ist zwingend erforderlich.
## 6. Performance-Optimierung (Gradle)
Der Build-Prozess kann bei aktivierter Web-Kompilierung (WASM/JS) sehr lange dauern. Für die reine Desktop-Entwicklung
wurde WASM standardmäßig deaktiviert.
* **WASM aktivieren (z.B. für CI/Portal):** `./gradlew -PenableWasm=true ...`
* **WASM deaktivieren (Default):** `./gradlew ...` (Spart bis zu 70% Build-Zeit).
## 7. Gradle Deep-Optimierung
Neben dem Deaktivieren von WASM wurden folgende systemweite Optimierungen in der `gradle.properties` vorgenommen:
* **Configuration Cache:** Aktiviert. Gradle merkt sich die Projektstruktur, was den Start jedes Befehls um Sekunden bis
Minuten verkürzt.
* **JVM G1GC & 12GB Heap:** Optimiert für große Multi-Modul-Projekte auf Systemen mit viel RAM (ab 16GB).
* **Parallel Workers:** Erhöht auf 12, um die 16 logischen Kerne Ihres Rechners besser auszulasten.
### Optionale Analysen
Statische Analysen sind nun standardmäßig **deaktiviert**, um den täglichen Workflow nicht zu bremsen.
* **Analyse laufen lassen:** `./gradlew staticAnalysis -PrunStaticAnalysis=true`
* **Dokka Dokumentation bauen:** `./gradlew dokkaAll -PrunDokka=true`
Stellen Sie in der `gradle.properties` sicher, dass `enableWasm=false` gesetzt ist, wenn Sie primär an der Desktop-App
arbeiten.
+58
View File
@@ -0,0 +1,58 @@
---
type: Guide
status: ACTIVE
owner: Lead Architect
last_update: 2026-04-28
---
# Git Branching & Deployment Strategy (Meldestelle)
Um parallele Weiterentwicklung und stabile Feld-Tests zu ermöglichen, nutzen wir einen vereinfachten **GitHub Flow** mit Release-Tags. Da wir ein kleines Team (bzw. Solo-Entwickler mit KI-Agents) sind, verzichten wir auf übermäßig komplexe Git-Flow-Modelle (wie `develop`, `release/*`, `hotfix/*`), stellen aber Stabilität für Deployments sicher.
## 1. Branching-Struktur
### `main` (Source of Truth / Production)
* **Zweck:** Enthält *immer* den aktuellen, stabilen und im Feld getesteten/auslieferbaren Code.
* **Regel:** Direkte Commits auf `main` sind tabu (außer Notfall-Hotfixes).
* **Deployment:** Ein Push/Merge auf `main` bedeutet **nicht** zwingend ein sofortiges Deployment auf Zora, aber der Code ist *bereit* dafür.
### Feature Branches (`feature/*` oder `fix/*`)
* **Zweck:** Hier findet die eigentliche Entwicklung statt (z.B. neue Bounded Contexts, Wizards).
* **Namenskonvention:** `feature/event-wizard-neu`, `fix/zns-import-bug`
* **Lebensdauer:** So kurz wie möglich. Sobald ein Feature/Fix *in sich geschlossen* und lokal getestet ist, wird ein Pull Request (PR) auf `main` erstellt.
### Release Tags (`v1.x.x`)
* **Zweck:** Markiert einen spezifischen, stabilen Punkt auf dem `main`-Branch, der tatsächlich für ein Turnier (Feld-Test) deployed wurde.
* **Szenario:** Du hast Version `v1.2.0` (Plan-B) für ein Turnier deployed. Du entwickelst weiter auf `feature/*` und mergest in `main`. Das nächste Turnier bekommt dann Tag `v1.3.0`.
## 2. Der Workflow im Alltag
1. **Start:** `git checkout main` -> `git pull` -> `git checkout -b feature/mein-neues-feature`
2. **Entwicklung:** Arbeiten, KI-Agents nutzen, Commits machen.
3. **Abschluss:** Feature ist fertig.
4. **Merge:** Pull Request in Gitea erstellen (oder lokal: `git checkout main`, `git merge feature/mein-neues-feature`, `git push`).
5. **Aufräumen:** `git branch -d feature/mein-neues-feature`
## 3. Strategie für Feld-Tests (Turnier-Einsatz)
Wenn ein Turnier ansteht und ein stabiler Stand eingefroren werden muss:
1. Stelle sicher, dass `main` den gewünschten Zustand hat.
2. Setze einen Tag in Git: `git tag -a v1.2.0 -m "Release für Turnier in Neumarkt"`
3. Pushe den Tag: `git push origin v1.2.0`
4. **Deployment:** Das Deployment-Skript zieht sich *diesen* Tag auf Zora (oder baut den Docker-Container aus diesem Tag).
### Was passiert, wenn während des Turniers ein Bug auftritt (Hotfix)?
*Szenario: Das Turnier läuft auf `v1.2.0`. Auf `main` gibt es schon neuere Features (unfertig).*
1. Checkout des stabilen Tags: `git checkout -b hotfix/turnier-fix v1.2.0`
2. Bug fixen, committen.
3. Neuen Tag für das Deployment setzen: `git tag -a v1.2.1 -m "Hotfix ZNS Import"`
4. `git push origin v1.2.1` -> Fix wird auf Zora deployed.
5. **WICHTIG (Backport):** Damit der Fix nicht verloren geht, den Hotfix-Branch danach in `main` mergen: `git checkout main`, `git merge hotfix/turnier-fix`.
## 4. Gitea Actions (CI/CD)
* **Pushes auf `feature/*`:** Führen Code-Checks/Tests aus.
* **Pushes auf `main`:** Führen erweiterte Tests aus und bauen Docker-Images mit dem Tag `latest` sowie dem Git-SHA in die interne Registry (`10.0.0.22:3000`).
* **Erstellung eines Tags (`v*`):** Triggert automatisch den Build und Push von Docker-Images in die interne Registry. Das Image erhält den Namen des Tags (z.B. `:v1.2.0`). Dies ist die Basis für stabile Deployments auf Zora.
@@ -0,0 +1,123 @@
A26128CSN-C-NEU CSNP-C-NEU NEUM2026042520260425CSN-C-Neu CSNP-C_Neu 2.2PSO v1.07
B010Stilspringprüfung - CSNP-C_N006000000001
C010001307002129000000000000000000000000000000000000021771000000
D001PG47Paddy's Nikita 170107Remplbauer Selina 00080000000 000000AUT*
D002PK06H-S Button 196040Gillinger Marlene 00067000000 000000AUT*
D003P824Pit 3 184759Krenn Eva 00055000000 000000AUT*
D004P814Balu 6 193244Remplbauer Sophia 00000000000 000000AUT
D004P901Daneder's Blitz 195501Weidinger Janina 00000000000 000000AUT
D004PB70Daneder's Caramello 163545Montgomery Helena 00000000000 000000AUT
B021Einlaufspringprüfung - CSN-C-Ne008000000002
C021001307002129000000000000000000000000000000000000021771000000
D0001781Ritual Do Vizo 126532Layr Bianca 00000000000 000000AUT*
D000P816Aldensfarm Breaking Dawn 159405Starzengruber Marie-Theres 00000000000 000000AUT*
D000P901Daneder's Blitz 195501Weidinger Janina 00000000000 000000AUT*
D000PB70Daneder's Caramello 163545Montgomery Helena 00000000000 000000AUT*
D000PE14SD Antonette 929451Mayrhofer Simon 00000000000 000000AUT*
D000PG47Paddy's Nikita 170107Remplbauer Selina 00000000000 000000AUT*
D000P824Pit 3 184759Krenn Eva 00003000000 000000AUT
D000P814Balu 6 193244Remplbauer Sophia 00000000000 000000AUT
B022Einlaufspringprüfung - CSN-C-Ne003000000002
C022001307002129000000000000000000000000000000000000021771000000
D000AR70Chocolate Kiss 2 147265Vanova Nina 00000000000 000000AUT*10258795
D000P561Ginger Bread Girl 153601Winter Maja Sophie 00000000000 000000AUT*
D997Z001Wildberry Gold RPZ 168660Zechmeister-Paster Diana A00000000000 000000AUT
B030Stilspringprüfung - CSNP-C_N006000000003
C030001307002129000000000000000000000000000000000000021771000000
D001PA53Rathcline Star 178474Schmidmayr Nena Sophie 00072000000 000000AUT*
D002P152Verena 3 170454Krenn Miriam 00070000000 000000AUT*
D003P816Aldensfarm Breaking Dawn 159405Starzengruber Marie-Theres 00068000000 000000AUT*
D004P561Ginger Bread Girl 153601Winter Maja Sophie 00067000000 000000AUT*
D997PE14SD Antonette 929451Mayrhofer Simon A00000000000 000000AUT
D997PK06H-S Button 196040Gillinger Marlene A00000000000 000000AUT
B041Einlaufspringprüfung - CSNP-C_N006000000004
C041001307002129000000000000000000000000000000000000021771000000
D0002M80Handsome 186927Lengauer Jelena 00000000000 000000AUT* 106KB09
D000AN19Exklusiv EM 187665Mück Hannah 00000000000 000000AUT*
D0001781Ritual Do Vizo 126532Layr Bianca 00040000000 000000AUT
D0004Y59Legolas 196 925183Schreiber Tamina 00047000000 000000GER
D000AB83HB Vijola 920327Reisinger Marlene 00056000000 000000AUT
D0003E99Quinet 906586Kapeller Emilia 00000000000 000000AUT
B042Einlaufspringprüfung - CSNP-C_N007000000004
C042001307002129000000000000000000000000000000000000021771000000
D0003K69Lillet 18 150620Reitetschläger Lena 00000000000 000000AUT*
D0005789Furiosa de la Bryere CE 140156Ehrentraut Carina 00000000000 000000AUT*
D000A099Quintessa 2 609548Aichinger Bianca 00000000000 000000AUT*
D0003M58Samantha 25 609771Karl Reinhard 00040000000 000000AUT
D000H606Moondancer 070156Alberer Manuela 00040000000 000000AUT
D000Z001Wildberry Gold RPZ 168660Zechmeister-Paster Diana 00092500000 000000AUT
D000AR70Chocolate Kiss 2 147265Vanova Nina 00129000000 000000AUT 10258795
B050Stilspringprüfung - CSNP-C_N003000000005
C050001307002129000000000000000000000000000000000000021771000000
D001P152Verena 3 170454Krenn Miriam 00074000000 000000AUT*
D002P985Taffy 2 193430Schartmüller Sarah 00072000000 000000AUT*
D003PA53Rathcline Star 906580Egger Julia 00065000000 000000AUT*
B061Stilspringprüfung - CSNP-C_N009000000006
C061001307002129000000000000000000000000000000000000021771000000
D0012B41Guccini 922710Simlinger Marlies 00075000000 000000AUT*
D002AN19Exklusiv EM 187665Mück Hannah 00072000000 000000AUT*
D0033E99Quinet 906586Kapeller Emilia 00071000000 000000AUT*
D0042M80Handsome 186927Lengauer Jelena 00070000000 000000AUT* 106KB09
D004AF41Cäsar 55 916541Dugandzic Sarah 00070000000 000000AUT*
D006PA53Rathcline Star 906580Egger Julia 00068000000 000000AUT
D0074Y59Legolas 196 925183Schreiber Tamina 00062000000 000000GER
D0083785Coeur 17 145963Obermüller Hannah 00061000000 000000AUT
D009AB83HB Vijola 920327Reisinger Marlene 00057000000 000000AUT
B062Stilspringprüfung - CSNP-C_N007000000006
C062001307002129000000000000000000000000000000000000021771000000
D001A099Quintessa 2 609548Aichinger Bianca 00082000000 000000AUT*
D0025789Furiosa de la Bryere CE 140156Ehrentraut Carina 00072000000 000000AUT*
D0033K69Lillet 18 150620Reitetschläger Lena 00067000000 000000AUT*
D004KSS1Charity Coke 053749Eichler Eva 00065000000 000000AUT*
D0053M58Samantha 25 609771Karl Reinhard 00060000000 000000AUT
D005H606Moondancer 070156Alberer Manuela 00060000000 000000AUT
D9971A11Gradan 102783Steyrer Anna A00000000000 000000AUT
B070Stilspringprüfung - CSNP-C_N002000000007
C070001307002129000000000000000000000000000000000000021771000000
D001Y001Bella Graziella 144315Gaugl Laura 00075000000 000000AUT*
D002P985Taffy 2 193430Schartmüller Sarah 00000000000 000000AUT
B080Springreiterbewerb - CSNP-C_N003000000008
C080001307002129000000000000000000000000000000000000021771000000
D0013785Coeur 17 145963Obermüller Hannah 00080000000 000000AUT*
D0022M80Handsome 186927Lengauer Jelena 00072000000 000000AUT* 106KB09
D9973E99Quinet 178474Schmidmayr Nena Sophie A00000000000 000000AUT
B091Standardspringprüfung - CSNP-C_N005000000009
C091001307002129000000000000000000000000000000000000021771000000
D0012062Grover 157407Pröll Leonie 00000005416 000000AUT*
D0022B41Guccini 160813Grubmüller Lea 00000005463 000000AUT*
D0031317Quality's Finest 612295Stroblmair Victoria 00000005492 000000AUT*
D0041A11Gradan 102783Steyrer Anna 00000005858 000000AUT*
D005KSS1Charity Coke 053749Eichler Eva 00040006428 000000AUT
B092Standardspringprüfung - CSNP-C_N007000000009
C092001307002129000000000000000000000000000000000000021771000000
D001A024D Day 075374Ambros Susanne 00000005940 000000AUT*10071068 108EH50
D0021G88Hamira 3 074007Beißmann Andreas 00000005991 000000AUT*
D0032G77S Mirrallas 605835Ellmer Kassandra 00000006298 000000AUT*
D0043966Capitaine 601366Madlmayr Carina 00040005862 000000AUT
D0051942Obora's Agnetha 601300Hofer Michaela 00040005966 000000AUT
D006Y001Bella Graziella 144315Gaugl Laura 00080005012 000000AUT
D9972785Herr Frodo 144315Gaugl Laura A00000000000 000000AUT
B100Springpferdeprüfung - CSN-C-Ne000000000010
C100001307002129000000000000000000000000000000000000021771000000
B110Stilspringprüfung - CSN-C-Ne002000000011
C110001307002129000000000000000000000000000000000000021771000000
D0012062Grover 157407Pröll Leonie 00085000000 000000AUT*
D0021317Quality's Finest 612295Stroblmair Victoria 00080000000 000000AUT*
B121Standardspringprüfung - CSN-C-Ne002000000012
C121001307002129000000000000000000000000000000000000021771000000
D0012062Grover 157407Pröll Leonie 00040005651 000000AUT*
D0022B41Guccini 160813Grubmüller Lea 00080005774 000000AUT
B122Standardspringprüfung - CSN-C-Ne004000000012
C122001307002129000000000000000000000000000000000000021771000000
D001AS94Landliebe 3 162776Höllmüller Anna 00000005557 000000AUT*10294537
D0022G77S Mirrallas 605835Ellmer Kassandra 00000006212 000000AUT*
D0031942Obora's Agnetha 601300Hofer Michaela 00000006723 000000AUT*
D004A024D Day 075374Ambros Susanne 00040005943 000000AUT 10071068 108EH50
B130Stilspringprüfung - CSN-C-Ne001000000013
C130001307002129000000000000000000000000000000000000021771000000
D0014258Casino East 601300Hofer Michaela 00075000000 000000AUT*
B140Standardspringprüfung - CSN-C-Ne003000000014
C140001307002129000000000000000000000000000000000000021771000000
D0012010Leonidas van de Zuuthoeve Z 145960Fischerlehner Leonie 00000005368 000000AUT*
D002AS94Landliebe 3 162776Höllmüller Anna 00000005745 000000AUT*10294537
D0034258Casino East 601300Hofer Michaela 00000006261 000000AUT*
Binary file not shown.
@@ -0,0 +1,96 @@
A26129CDN-C-NEU CDNP-C_NEU NEUM2026042620260426 2.2PSO v1.07
B010Dressurprüfung lzf CDN-C_Ne002000000001
C010000000038705000000000000000000000000000000000000000000000000
D001PB70Daneder's Caramello 163545Montgomery Helena 00062000000 000000AUT*
D0022892Amore 5 AUT Stadler Caroline 00060000000 000000AUT*
B020Dressurprüfung lzf CDN-C_Ne003000000002
C020000000038705000000000000000000000000000000000000000000000000
D0014208Sahib Silver G 195331Neuhauser Lara 00075000000 000000AUT*
D0022892Amore 5 AUT Stadler Caroline 00068000000 000000AUT*
D003PB70Daneder's Caramello 163545Montgomery Helena 00060000000 000000AUT*
B030Dressurreiterprüfung lzf CDN-C_Ne005000000003
C030035110000000000000000000000000000000000000000000000000000000
D001PC62Flora HP 917397Altendorfer Pia 00080000000 000000AUT*
D002Z002Abrakadabra S 107926Fürbäck Melanie 00077000000 000000AUT*
D0034Y59Legolas 196 184074Stöbich Enya 00068000000 000000AUT*
D004HKTBAcceptius FA 196261Salzinger Luisa Marie 00064000000 000000AUT
D005PA53Rathcline Star 922380Kropfreiter Ines 00062000000 000000AUT
B040Dressurreiterprüfung lzf CDN-C_Ne006000000004
C040000000038705000000000000000000000000000000000000000000000000
D001PC62Flora HP 917397Altendorfer Pia 00078000000 000000AUT*
D0024208Sahib Silver G 195331Neuhauser Lara 00076000000 000000AUT*
D003Z002Abrakadabra S 107926Fürbäck Melanie 00068000000 000000AUT*
D004HKTBAcceptius FA 196261Salzinger Luisa Marie 00064000000 000000AUT
D0054Y59Legolas 196 184074Stöbich Enya 00062000000 000000AUT
D006PA53Rathcline Star 922380Kropfreiter Ines 00060000000 000000AUT
B050Dressurreiterprüfung lzf CDN-C_Ne001000000005
C050035110000000000000000000000000000000000000000000000000000000
D001PF06Domino N AUT Stelzl Helena 00080000000 000000AUT*
B060Dressurreiterprüfung lzf CDN-C_Ne000000000006
C060035110000000000000000000000000000000000000000000000000000000
B070Pony Dressurprüfung A CSNP-C_N003000000007
C070000000038705000000000000000000000000000000000000000000000000
D001PT24Daneder's Captain 146663Steinmetz Sinah-Marie 00065000000 000000AUT*
D002P561Ginger Bread Girl 153601Winter Maja Sophie 00060000000 000000AUT*
D003PA53Rathcline Star 906592Emsenhuber Tanja 00058000000 000000AUT
B081Dressurreiterprüfung A CDN-C_Ne006000000008
C081035110038705000000000000000000000000000000000000000000000000
D0013888Ravasz 123156Scheiblechner Sonja 00072000000 000000AUT*
D0024307Makker 146066Gstöttenbauer Olivia 00064000000 000000AUT*
D003P561Ginger Bread Girl 153601Winter Maja Sophie 00062000000 000000AUT*
D0042083Light Blue 194297Hazoth Anna-Maria 00060000000 000000AUT*
D0053M58Samantha 25 609771Karl Reinhard 00058000000 000000AUT
D005KSS1Charity Coke 053749Eichler Eva 00058000000 000000AUT
B082Dressurreiterprüfung A CDN-C_Ne002000000008
C082035110038705000000000000000000000000000000000000000000000000
D001GIGIGigi D'Agostidinina 076742Klein Elisabeth 00068000000 000000AUT*10144403
D002A590Queeny 8 612592Panzirsch Anna 00064000000 000000AUT*
B091Dressurprüfung A CDN-C_Ne007000000009
C091035110038705000000000000000000000000000000000000000000000000
D0013888Ravasz 123156Scheiblechner Sonja 00070000000 000000AUT*
D002AN19Exklusiv EM 187665Mück Hannah 00064000000 000000AUT*
D0032083Light Blue 194297Hazoth Anna-Maria 00062000000 000000AUT*
D0044B66Vingino's Victory 616957Kiesenhofer Sarah 00058000000 000000AUT
D0053M58Samantha 25 609771Karl Reinhard 00055000000 000000AUT
D005KSS1Charity Coke 053749Eichler Eva 00055000000 000000AUT
D0074307Makker 146066Gstöttenbauer Olivia 00053000000 000000AUT
B092Dressurprüfung A CDN-C_Ne004000000009
C092035110038705000000000000000000000000000000000000000000000000
D001GIGIGigi D'Agostidinina 076742Klein Elisabeth 00068000000 000000AUT*10144403
D002AL46Superbunt 616836Lengauer Julia 00065000000 000000AUT*
D0032010Leonidas van de Zuuthoeve Z 145960Fischerlehner Leonie 00064000000 000000AUT*
D004A590Queeny 8 612592Panzirsch Anna 00058000000 000000AUT
B100Pony Dressurprüfung L CSNP-C_N001000000010
C100035110038705000000000000000000000000000000000000000000000000
D001P540Pieter V 153601Winter Maja Sophie 00056000000 000000AUT*
B110Dressurreiterprüfung L CDN-C_Ne003000000011
C110035110038705000000000000000000000000000000000000000000000000
D0011317Quality's Finest 612295Stroblmair Victoria 00074000000 000000AUT*
D0021F34Ferro Felicis 146066Gstöttenbauer Olivia 00064000000 000000AUT*
D003P540Pieter V 153601Winter Maja Sophie 00062000000 000000AUT*
B121Dressurprüfung L CDN-C_Ne003000000012
C121035110038705000000000000000000000000000000000000000000000000
D001AN19Exklusiv EM 187665Mück Hannah 00068000000 000000AUT*
D0021F34Ferro Felicis 146066Gstöttenbauer Olivia 00062000000 000000AUT*
D003AE11Merlin SH 061601Povacz Gisela 00060000000 000000AUT*
B122Dressurprüfung L CDN-C_Ne002000000012
C122035110038705000000000000000000000000000000000000000000000000
D001A024D Day 075374Ambros Susanne 00066000000 000000AUT*10071068 108EH50
D0023966Capitaine 601366Madlmayr Carina 00060000000 000000AUT*
B131Dressurpferdeprüfung A CDN-C_Ne003000000013
C131035110038705000000000000000000000000000000000000000000000000
D001AX99Bon Sai 102783Steyrer Anna 00073400000 000000AUT*
D0020214SHS Donna Verdi 169981Süss Sarah 00066000000 000000AUT*
D003PT24Daneder's Captain 146663Steinmetz Sinah-Marie 00061200000 000000AUT*
B132Dressurpferdeprüfung A CDN-C_Ne005000000013
C132035110038705000000000000000000000000000000000000000000000000
D001MAXIVerstappen 2 075374Ambros Susanne 00074600000 000000AUT*10071068
D0022H08SHS Weltmädel 169981Süss Sarah 00074200000 000000AUT*
D003P983Daneders Tornado 153601Winter Maja Sophie 00064800000 000000AUT*
D0044B03SHS Roubinjo 169981Süss Sarah 00064200000 000000AUT*
D0054B66Vingino's Victory 616957Kiesenhofer Sarah 00063000000 000000AUT*
B140Dressurpferdeprüfung L CDN-C_Ne003000000014
C140035110038705000000000000000000000000000000000000000000000000
D0012H08SHS Weltmädel 169981Süss Sarah 00067800000 000000AUT*
D002P983Daneders Tornado 153601Winter Maja Sophie 00064800000 000000AUT*
D0034B03SHS Roubinjo 169981Süss Sarah 00063000000 000000AUT*
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

@@ -8,7 +8,7 @@
#### 1. Standardized Dockerfile Template (v2.5.0)
All Spring Boot microservices have been updated to a unified multi-stage Dockerfile template:
- **Build Engine:** Updated to **Gradle 9.4.1** and **JDK 25** (eclipse-temurin).
- **Build Engine:** Updated to **Gradle 9.5.0** and **JDK 25** (eclipse-temurin).
- **Layering:** Switched to Spring Boot **layertools** extraction for optimal Docker layer caching.
- **Security:**
- Integrated **tini** as init process to handle signals correctly.
@@ -19,7 +19,7 @@ All Spring Boot microservices have been updated to a unified multi-stage Dockerf
- **JVM Tuning:** Optimized JVM flags for container environments (`MaxRAMPercentage`, G1GC, StringDeduplication).
#### 2. Docker Compose Synchronization (`dc-backend.yaml`)
- **Global Args:** Synchronized `GRADLE_VERSION` (9.4.1) and `JAVA_VERSION` (25) across all service build definitions.
- **Global Args:** Synchronized `GRADLE_VERSION` (9.5.0) and `JAVA_VERSION` (25) across all service build definitions.
- **Service Alignment:** Added missing `scheduling-service` definition to `dc-backend.yaml`.
- **Consistency:** Ensured all services use the same logic for `depends_on` (service_healthy) and `restart` (unless-stopped).
+2
View File
@@ -32,6 +32,8 @@ Deine Aufgaben:
6. **Handover:** Stelle Architekturentscheidungen nicht nur als Text, sondern auch als Diagramm (Mermaid/PlantUML) bereit.
7. Erstelle und pflege die MASTER ROADMAP. Du bist der "Hüter des Plans". Du delegierst Aufgaben an die spezialisierten Agenten (Backend, Frontend, DevOps, QA), führst sie aber nicht selbst aus, es sei denn, es betrifft direkt die Architektur oder das Build-System.
8. **Bounded Context Awareness:** Stelle sicher, dass Änderungen immer einem der 6 SCS (Self-Contained Systems) zugeordnet sind und die Grenzen gewahrt bleiben.
9. **Active Task Manifest:** Nutze die Datei `docs/ACTIVE_TASK.md`, um den aktuellen Arbeitsstand zu dokumentieren und für die nächste Session/KI bereitzustellen.
10. **Scout-Prinzip:** Wenn eine Aufgabe unklar ist, delegiere zuerst an Junie als "Scout", um Code-Snippets in `docs/04_Agents/Research_Snippet.md` zu sammeln, bevor architektonische Entscheidungen getroffen werden.
Don't:
- Implementiere keine Business-Logik in Backend-Services (→ Backend Developer).
+14 -2
View File
@@ -23,6 +23,7 @@ Ziel:
- Jede Session endet mit genau einem Artefakt in `docs/`.
- Veraltetes Wissen wird sauber archiviert.
- Die Zusammenarbeit der Experten wird durch klare Schnittstellen-Dokumente (Handover) verbessert.
- **Context-Handover:** Am Ende jeder Session wird ein standardisierter `🔄 NEXT SESSION CONTEXT` Block ausgegeben und die Datei `docs/ACTIVE_TASK.md` aktualisiert.
Regeln:
1. Single Source of Truth ist `docs/`.
@@ -31,11 +32,22 @@ Regeln:
- Reference / technische Wahrheit pro System (z.B. `docs/05_Backend/Services/<service>.md`)
- How-to / Runbook (passender Bereich)
- Journal Entry (`docs/99_Journal/`)
3. **Quality Gate:** Prüfe, ob die Artefakte den Standards entsprechen:
3. **Session-Abschluss Checkliste:**
- [ ] Wurden alle geänderten/neuen Dateien im Journal/Artefakt mit absolutem Pfad erwähnt?
- [ ] Wurde ein "Warum" dokumentiert (nicht nur das "Was")?
- [ ] Wurde die Datei `docs/ACTIVE_TASK.md` auf den neuesten Stand gebracht?
- [ ] Enthält die finale Antwort den `🔄 NEXT SESSION CONTEXT` Block?
4. **🔄 NEXT SESSION CONTEXT Struktur:**
- **Focus:** [SCS / Feature-Name]
- **Last State:** [Kurz-Zusammenfassung des aktuellen Stands]
- **Critical Files:** [Liste der wichtigsten Dateien für die nächste Session]
- **Open Threads:** [Offene Fragen oder nächste konkrete Schritte]
- **Agent-Handover:** [Spezifische Anweisungen für die nächste KI-Rolle]
5. **Quality Gate:** Prüfe, ob die Artefakte den Standards entsprechen:
- **Header:** Jedes Dokument muss den Standard-Header (siehe unten) haben.
- **Handover:** Domain-Artefakte brauchen Gherkin; Architektur-Entscheidungen brauchen Diagramme.
- **ADR-Pflicht:** Bei größeren Entscheidungen (z.B. Tech-Stack-Änderungen) muss ein ADR eingefordert werden.
4. **Lifecycle & Archivierung:**
6. **Lifecycle & Archivierung:**
- Veraltete Dokumente (z.B. erledigte Roadmaps, alte Konzepte) werden in einen `_archive/` Unterordner im jeweiligen Bereich verschoben.
- Dateiname bei Archivierung: `YYYY-MM-DD_OriginalName.md`.
- Status im Header auf `ARCHIVED` setzen.
+2
View File
@@ -17,6 +17,8 @@ Gemini wird genutzt für **Konzeptarbeit**: Varianten vergleichen, Argumente/Tra
* Immer 24 Optionen mit Vor-/Nachteilen liefern.
* Offene Fragen explizit als Liste zurückgeben.
* Formuliere Outputs so, dass sie **direkt** in ein `docs/*` Artefakt übernommen werden können.
* **Richter-Prinzip:** Nutze von Junie bereitgestellte Code-Snippets in `docs/04_Agents/Research_Snippet.md`, um fundierte Entscheidungen zu treffen, ohne den Code selbst im Detail lesen zu müssen.
* **Manifest-Pflicht:** Nutze die `docs/ACTIVE_TASK.md`, um den Kontext-Handover zwischen Sessions zu gewährleisten.
## Dont
* Keine Annahmen als Fakten verkaufen.
+2
View File
@@ -21,6 +21,8 @@ Junie wird genutzt für **Repo-nahe Arbeit**: Code lesen, reale Pfade/Module fin
## Dont
* Keine „zweite Wahrheit“ in `.junie/*` etablieren (Tooling bleibt Tooling).
* Keine Entscheidungen „im Chat verlieren“ am Ende muss ein Artefakt in `docs/` stehen.
* **Scout-Prinzip:** Agiere bei Bedarf als technischer Scout für Gemini. Sammele Code-Beweise und Snippets in `docs/04_Agents/Research_Snippet.md`, um architektonische Entscheidungen vorzubereiten.
* **Manifest-Pflicht:** Lies bei Session-Start immer zuerst die `MASTER_ROADMAP` und dann die `docs/ACTIVE_TASK.md`.
## Abschluss (Pflicht)
Am Ende der Session genau **ein** Artefakt gemäß `docs/03_Agents/README.md` erzeugen (oder aktualisieren).
@@ -0,0 +1,37 @@
🏗️ **[Lead Architect]**
Datum: 30. April 2026
# 🧪 POC-Anleitung: Zero-Config Initialisierung
Dieses Dokument beschreibt die Schritte für den technischen Hardware-POC der "Meldestelle" Desktop-App.
## 1. Bauen der App
Führen Sie auf Ihrem Entwicklungsrechner aus:
```bash
./gradlew :frontend:shells:meldestelle-desktop:createDistributable
```
Kopieren Sie den Ordner `frontend/shells/meldestelle-desktop/build/compose/binaries/main/app` auf einen USB-Stick.
## 2. Test am Master-PC (PC-1)
1. Starten Sie die App vom Stick.
2. Wählen Sie die Rolle **Master (Host)**.
3. Vergeben Sie einen Namen (z.B. "Meldestelle-Zentrale").
4. Geben Sie den **Sicherheitsschlüssel** (Demo: `1234`) ein.
5. Wählen Sie den USB-Pfad für **Plan-USB** aus (Native FileDialog öffnet sich).
6. Klicken Sie auf "Initialisierung abschließen".
## 3. Test am Client-PC (PC-2)
1. Starten Sie die App auf dem zweiten PC im selben LAN.
2. Wählen Sie die Rolle **Client**.
3. **Wait-State:** Sie sollten nun die Meldung "Suche nach der Meldestelle..." sehen.
4. Sobald der Master aktiv ist, erscheint er in der Liste.
5. Klicken Sie auf den Master-Eintrag.
6. Geben Sie denselben Sicherheitsschlüssel (`1234`) ein.
7. Klicken Sie auf **"Jetzt verbinden"**.
8. **Verifikation:** Bei Erfolg erscheint ein grüner Haken und die Meldung "Verbunden mit Meldestelle-Zentrale".
## 4. Erfolgskriterien
- [ ] Master wird vom Client automatisch gefunden (mDNS).
- [ ] Client kann sich per Klick verbinden.
- [ ] Native Dateidialoge sind lesbar und stabil.
- [ ] Handshake-Feedback (Grün/Rot) funktioniert.
@@ -0,0 +1,94 @@
---
type: How-to
status: ACTIVE
owner: DevOps Engineer
---
# Runbook: Caddy & Pangolin Deployment (Plan-B Setup)
Dieses Dokument sichert das Wissen über die Konfiguration von Caddy als Webserver/Reverse-Proxy in Kombination mit Pangolin-Tunneln, welches während der "Plan-B" Online-Nennung erarbeitet wurde.
## 1. Architektur-Übersicht
* **Pangolin:** Stellt den sicheren Tunnel vom lokalen Netzwerk (Zora) ins Internet her (ersetzt Cloudflare). Leitet Traffic auf spezifische lokale Ports weiter.
* **Caddy:** Agiert als Reverse-Proxy und TLS-Terminierungspunkt. Nimmt Traffic von Pangolin (und lokalem Netz) an und routet ihn zu den internen Docker-Services (z.B. Frontend-Web, API-Gateway).
## 2. Caddy Konfiguration (`Caddyfile`)
Die Konfiguration befindet sich in `config/docker/caddy/web-app/Caddyfile`.
### Wichtige Erkenntnisse / Fallstricke:
* **TLS/SSL:** Caddy wurde mit `auto_https off` konfiguriert, da die SSL-Terminierung extern (Pangolin/Edge) erfolgt. Caddy läuft intern auf Port 80.
* **Same-Origin Strategy:** Um CORS-Probleme im Browser zu vermeiden, werden alle API-Anfragen (`/api/*`) über Caddy an den `mail-service:8085` geproxt. Dies macht die App robuster gegen Browser-Security-Policies.
* **MIME-Types:** Explizite Setzung von `application/wasm` für `.wasm` Dateien ist für KMP-Web-Apps kritisch (siehe Snippet).
* **COOP/COEP Header:** Für WASM/KMP-Web-Apps sind `Cross-Origin-Embedder-Policy "require-corp"` und `Cross-Origin-Opener-Policy "same-origin"` essentiell, damit SharedArrayBuffer etc. funktionieren.
* **Caching:**
* Assets mit Hashes im Namen sind `immutable` (max-age 1 Jahr).
* `.wasm` und `.js` Dateien wurden während Plan-B auf `no-store, no-cache, must-revalidate` gesetzt, um sicherzustellen, dass Teilnehmer immer die aktuellste Logik erhalten.
* **Header-Weiterleitung:** Wichtige Header für das Backend: `X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto`.
### Aktuelles Plan-B Snippet:
```caddyfile
{
auto_https off
}
:80 {
root * /usr/share/caddy
header {
Cross-Origin-Embedder-Policy "require-corp"
Cross-Origin-Opener-Policy "same-origin"
}
# API Proxy (Same-Origin Strategy)
handle /api/* {
reverse_proxy mail-service:8085 {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
# Wasm MIME & Caching
@wasm path *.wasm
header @wasm Content-Type "application/wasm"
@wasm_js path *.wasm *.js
header @wasm_js Cache-Control "no-store, no-cache, must-revalidate"
# SPA Fallback
handle {
try_files {path} /index.html
file_server
}
}
```
## 3. Pangolin Konfiguration
### Erkenntnisse aus Plan-B:
* **Tunnel-Endpunkt:** Pangolin leitet den Traffic von der öffentlichen Domain (z.B. `meldestelle.mo-code.at`) auf den lokalen Port der Zora-Instanz weiter (standardmäßig Port 80, gemappt auf Host-Port via Docker).
* **Stabilität:** Der Pangolin-Client läuft als persistenter Dienst auf der Zora-Node. Er ist extrem stabil gegenüber IP-Wechseln des ISP (DSL-Reconnect).
* **Konfiguration:** Erfolgt primär über das Pangolin-Dashboard (Web-UI). Wichtig ist das Mapping der Resource auf die interne IP von Zora.
## 4. Deployment-Workflow (Erkenntnisse)
### SMTP-Härtung (Plan-B Mail-Service)
In `dc-planb.yaml` wurden folgende Einstellungen für World4You (SMTP) als stabil verifiziert:
```yaml
SPRING_MAIL_HOST: "smtp.world4you.com"
SPRING_MAIL_PORT: "587"
SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE: "true"
SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_REQUIRED: "true"
```
Wichtig: `STARTTLS_REQUIRED` verhindert den Versand, falls keine verschlüsselte Verbindung aufgebaut werden kann.
### Infrastruktur-Optimierung
* **Zero-Downtime:** `docker compose exec web-app caddy reload --config /etc/caddy/Caddyfile` ermöglicht Konfigurationsänderungen ohne Container-Neustart.
* **Health-Check:** Der `/health` Endpunkt in Caddy wurde genutzt, um die Erreichbarkeit des Containers zu prüfen.
* **In-Memory DB:** Für Plan-B wurde die H2-Datenbank (In-Memory) genutzt, da keine Persistenz über den Turnier-Zeitraum hinaus (außer E-Mail-Kopien) nötig war. Dies vereinfachte das Deployment massiv.
---
*Hinweis: Dieses Dokument basiert auf den erfolgreichen Feld-Tests vom April 2026.*
@@ -26,7 +26,7 @@ Der Runner ist das "Arbeitstier" des Systems.
* **Software:** `act_runner` (v0.2.11).
* **Ressourcen:** 16 GiB RAM (optimiert für schwere Kotlin/JS-Builds).
* **Build-Stack:** Java 25 (Temurin), Gradle 9.3.1.
* **Build-Stack:** Java 25 (Temurin), Gradle 9.5.0.
* **Besonderheiten:**
* **Sequenzieller Build:** Um GitHub Rate-Limits und RAM-Spitzen zu vermeiden, arbeitet der Runner die Matrix-Jobs kontrolliert ab.
* **Docker Buildx:** Native ARM64-Builds mit Optimierungs-Flags (`-XX:+UseTransparentHugePages`, `-XX:+UseSVE=1`).
@@ -42,13 +42,13 @@ Die Zielumgebung für das Deployment.
* **Verzeichnis:** `~/meldestelle/`
* **Service-Übersicht:**
| Dienst | Externer Port | Interner Port | Image-Name (Registry) |
| --- | --- | --- | --- |
| **Web-App** | 4000 | 4000 (Caddy) | `web-app` |
| **API-Gateway** | 8081 | 8081 | `api-gateway` |
| **Keycloak** | 8180 (Admin) | 8080 | `keycloak` |
| **Ping-Service** | 8082 | 8082 | `ping-service` |
| **Consul** | 8500 | 8500 | `hashicorp/consul` |
| Dienst | Externer Port | Interner Port | Image-Name (Registry) |
|------------------|---------------|---------------|-----------------------|
| **Web-App** | 4000 | 4000 (Caddy) | `web-app` |
| **API-Gateway** | 8081 | 8081 | `api-gateway` |
| **Keycloak** | 8180 (Admin) | 8080 | `keycloak` |
| **Ping-Service** | 8082 | 8082 | `ping-service` |
| **Consul** | 8500 | 8500 | `hashicorp/consul` |
---

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

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