Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1690da3fab | |||
| cb6e0103e7 | |||
| 98d0bf0c7b | |||
| 0a90b57c2a | |||
| 0ab62a2752 | |||
| 6070709bf2 | |||
| 763c2a9157 | |||
| 4f715d10bb | |||
| 0b830eb675 | |||
| 4c37ecb952 | |||
| c25ef17a4a | |||
| e5e3b4cfec | |||
| 7d064853e5 | |||
| 387180c12c | |||
| 49393d3eac | |||
| e389fe9bce | |||
| 1a4753cd73 | |||
| ece3f8bf78 | |||
| 8d176ce955 | |||
| 280db663c7 | |||
| 74ef6424b7 | |||
| 3959168695 | |||
| 04a435df1d | |||
| 3aaf5cc59c | |||
| a2d94bbc7e | |||
| 95a130c72e | |||
| 223bf77776 | |||
| 99cbfeef11 | |||
| ed1cb507cf | |||
| f4fab93a6c | |||
| 9b9f60a071 | |||
| d219176609 | |||
| 7411038b3b | |||
| 77ee608094 | |||
| 9bee2f233e | |||
| c317147ca4 | |||
| 15222b5453 | |||
| 6f15ada447 |
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -193,7 +193,7 @@ secrets/
|
||||
# ===================================================================
|
||||
TODO*.md
|
||||
NOTES*.md
|
||||
**/.junie/
|
||||
.junie/
|
||||
|
||||
# ===================================================================
|
||||
# Keep essential files (override exclusions)
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
desktop-tests:
|
||||
# Komplett deaktivierbar über Repo-Variable: Settings → Variables → DESKTOP_CI_ENABLED=true
|
||||
# Zusätzlich: Für Plan‑B‑Builds ü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
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Build and Publish Docker Images
|
||||
run-name: Build & Publish by @${{ github.actor }}
|
||||
run-name: Build & Publish by @${{ gitea.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -117,8 +117,8 @@ jobs:
|
||||
images: ${{ env.REGISTRY_INTERNAL }}/${{ env.IMAGE_PREFIX }}/${{ matrix.image }}
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=sha,format=long,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
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
|
||||
@@ -132,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 }}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 Plan‑B 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 Plan‑B 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
|
||||
|
||||
@@ -56,3 +56,7 @@ desktop.ini
|
||||
docs/temp/
|
||||
docs/Bin/
|
||||
docs/_archive/
|
||||
|
||||
# Conveyor
|
||||
conveyor.rootkey
|
||||
output/
|
||||
|
||||
@@ -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" "$@"
|
||||
|
||||
@@ -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" "$@"
|
||||
|
||||
@@ -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" "$@"
|
||||
|
||||
@@ -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
|
||||
@@ -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" "$@"
|
||||
@@ -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" "$@"
|
||||
@@ -20,7 +20,7 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
|
||||
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
|
||||
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
|
||||
|
||||
Wesentliche Architektur-Referenz: [Offline‑First Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md)
|
||||
Wesentliche Architektur-Referenz: [Offline‑First Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/Concepts/konzept-offline-first-desktop-backend-de.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -114,4 +114,8 @@ Beiträge sind willkommen. Bitte lies zunächst die Entwickler-Guides unter [`do
|
||||
|
||||
Dieses Projekt steht unter der [MIT License](LICENSE).
|
||||
|
||||
## Gitea - Test
|
||||
---
|
||||
|
||||
## Test
|
||||
|
||||
Das ist der 2. Versuch über Remote zu Committen
|
||||
|
||||
@@ -8,7 +8,7 @@ import io.valkey.springframework.data.valkey.core.ValkeyTemplate
|
||||
import io.valkey.springframework.data.valkey.serializer.StringValkeySerializer
|
||||
import 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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).
|
||||
- **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).
|
||||
|
||||
### 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).
|
||||
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).
|
||||
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).
|
||||
|
||||
- **Frontend (Compose Desktop):**
|
||||
- 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).
|
||||
- **Warnungen:**
|
||||
- Ü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.
|
||||
|
||||
Ä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.
|
||||
|
||||
## 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
|
||||
@@ -2,7 +2,7 @@
|
||||
type: Roadmap
|
||||
status: ACTIVE
|
||||
owner: Lead Architect
|
||||
last_update: 2026-04-30
|
||||
last_update: 2026-05-06
|
||||
---
|
||||
|
||||
# MASTER ROADMAP: Meldestelle
|
||||
@@ -87,7 +87,10 @@ Fokus: Physische Implementierung der Turnier-Hierarchie und technisches Onboardi
|
||||
* [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.
|
||||
* [ ] **PoC Verifikation:** 🔴 **FEHLGESCHLAGEN** (Hardware-Test durch User nicht erfolgreich - Analyse für Abend-Session erforderlich).
|
||||
* [x] **Cross-Packaging (Conveyor):** Windows-Build auf Linux-CI ermöglicht (x64-Abhängigkeit identifiziert).
|
||||
* [x] **Build-Performance:** WASM standardmäßig deaktiviert, um Desktop-Build-Zeiten zu reduzieren (11.05.2026).
|
||||
* [ ] **PoC Verifikation:** 🔴 **BLOCKIERT** (Log 483: ARM64-Runner inkompatibel mit Conveyor-Binary; Workflow auf
|
||||
manuell gesetzt).
|
||||
|
||||
### MEILENSTEIN 1: Die Basis-Hierarchie (Prio 1) ⚪ GEPLANT
|
||||
|
||||
@@ -150,26 +153,26 @@ Code-Stand.*
|
||||
|
||||
## 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/` |
|
||||
| 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/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` |
|
||||
| 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,19 +28,23 @@ 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
|
||||
// In einem Service-Modul
|
||||
dependencies {
|
||||
@@ -48,9 +56,10 @@ 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
|
||||
// In einem Service-Modul
|
||||
dependencies {
|
||||
@@ -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“ (+ 1–2 Turniere)
|
||||
- [BE] Repositories prüfen und Test-Cases anlegen (Roundtrip CRUD)
|
||||
|
||||
- [BE] DB-Migrationen finalisieren: `turniere`, `ausschreibungen` (Flyway)
|
||||
- [BE] Seed-Datensatz „Veranstaltung Neumarkt 2026“ (+ 1–2 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
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
# ADR-0027: Netzwerk-Discovery & Interface-Binding
|
||||
|
||||
## Status
|
||||
In Prüfung (Wartet auf PoC)
|
||||
|
||||
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 (JmDNS) wählen ohne explizite Konfiguration oft das falsche Interface, wodurch sich Clients und Master nicht finden.
|
||||
|
||||
Desktop-Rechner auf Turnieren sind oft mit mehreren Netzwerken gleichzeitig verbunden (z.B. LAN für das
|
||||
Turnier-Netzwerk, WLAN für Internet-Hotspot). Automatische Discovery-Dienste (mDNS) wählen ohne explizite Konfiguration
|
||||
oft ein Interface, das für die anderen Teilnehmer nicht erreichbar ist (Bridging-Probleme zwischen LAN und WLAN). Zudem
|
||||
blockieren einige Router Multicast-Pakete zwischen WLAN und LAN-Segmenten.
|
||||
|
||||
## Entscheidung
|
||||
Wir führen ein explizites Netzwerk-Management für die Initialisierung ein.
|
||||
|
||||
1. **Interface-Selektion:** Der Benutzer muss bei der technischen Initialisierung explizit wählen, über welches Netzwerk-Interface (IP-Adresse/Adapter) die App kommunizieren soll. Die UI zeigt hierfür benutzerfreundliche Namen (WLAN, Ethernet) an.
|
||||
2. **Geführte Discovery:** Sobald ein Interface gewählt ist, startet ein "Radar-Modus". Dieser scannt aktiv via JmDNS nach vorhandenen Master-Geräten.
|
||||
3. **Adaptive Rolle:** Findet die Discovery einen Master, wird dem Benutzer die Rolle "Client" vorgeschlagen. Die UI bleibt jedoch flexibel für manuelle Rollenwechsel.
|
||||
4. **Fokus-Management:** Nach Auswahl der Rolle wird der Fokus automatisch in das erste relevante Eingabefeld (Gerätename) gesetzt, um einen reibungslosen Workflow zu ermöglichen.
|
||||
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
|
||||
- Verhindert "Geistersuchen" im falschen Netzwerk.
|
||||
- Erhöht die Benutzerfreundlichkeit durch automatische Vorschläge.
|
||||
- Erfordert Zugriff auf System-Netzwerk-APIs in der Desktop-Shell.
|
||||
|
||||
- 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).
|
||||
@@ -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.
|
||||
@@ -1,14 +1,14 @@
|
||||
# CSN-C NEU / CSNP-C NEU NEUMARKT/M.
|
||||
|
||||
**Turnier-Nr.: 26128** | **Datum: 25. April 2026**
|
||||
**Turnier-Nr.: 26128** | **Datum: 25. April 2026**
|
||||
|
||||
## Allgemeine Informationen
|
||||
|
||||
* **Veranstalter:** Union Reit- u. Fahrverein Neumarkt/M. (6-009)
|
||||
* **Ort:** Reitanlage Stroblmair, 4212 Neumarkt
|
||||
* **Kontakt:** Ursula Stroblmair, Brandstetterweg 2, 4212 Neumarkt
|
||||
* **Veranstalter:** Union Reit- u. Fahrverein Neumarkt/M. (6-009)
|
||||
* **Ort:** Reitanlage Stroblmair, 4212 Neumarkt
|
||||
* **Kontakt:** Ursula Stroblmair, Brandstetterweg 2, 4212 Neumarkt
|
||||
* **Tel.:** 0664 1832381
|
||||
* **E-Mail:** reit-stall@gmx.at
|
||||
* **E-Mail:** reit-stall@gmx.at
|
||||
* **Nennungsschluss:** 24.04.2026, 19:00 Uhr
|
||||
* **Online-Nennung:** Ab Mittwoch, 22.04.
|
||||
auf [www.ihremeldestelle.at](http://www.ihremeldestelle.at)
|
||||
@@ -17,17 +17,17 @@
|
||||
## Technische Details
|
||||
|
||||
* **Austragungsplatz:** 45 x 65 m (Sand/Vlies)
|
||||
* **Vorbereitungsplatz:** 20 x 40 m Halle (Sand/Vlies)
|
||||
* **Warmreiten:** Draußen (20 x 60 m Sand/Vlies) möglich
|
||||
* **Boxen:** Keine Einstallung möglich
|
||||
* **Vorbereitungsplatz:** 20 x 40 m Halle (Sand/Vlies)
|
||||
* **Warmreiten:** Draußen (20 x 60 m Sand/Vlies) möglich
|
||||
* **Boxen:** Keine Einstallung möglich
|
||||
|
||||
## Funktionäre
|
||||
|
||||
* **Turnierleiter:** Ursula Stroblmair
|
||||
* **Turnierbeauftragter:** Rudi Kreupl
|
||||
* **Richter:** Rudi Kreupl, Helmut Riedler
|
||||
* **Parcoursbauchef:** Kurt Reitetschlägerr
|
||||
* **Tierarzt:** Dr. Sabine Ötschmaier
|
||||
* **Richter:** Rudi Kreupl, Helmut Riedler
|
||||
* **Parcoursbauchef:** Kurt Reitetschlägerr
|
||||
* **Tierarzt:** Dr. Sabine Ötschmaier
|
||||
|
||||
---
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
* **Kosten:** Startgeld € 15,- pro Bewerb. Kein Nenngeld, kein Sporteuro.
|
||||
* **Teilnahmebedingungen:**
|
||||
* Für Springprüfungen bis 95 cm: Mitgliedschaft OEPS-Verein und Reiterpass erforderlich.
|
||||
* Pferde bis 90 cm müssen **nicht** beim OEPS registriert sein.
|
||||
* Pferdepass mit gültigem Impfschutz (§ 11 OTO) ist vorzulegen.
|
||||
* Pferde bis 90 cm müssen **nicht** beim OEPS registriert sein.
|
||||
* Pferdepass mit gültigem Impfschutz (§ 11 OTO) ist vorzulegen.
|
||||
* Haftpflichtversicherung für jedes Pferd ist Pflicht.
|
||||
* **Startregelung:**
|
||||
* Ein Pferd darf maximal 3x pro Tag starten.
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 325 KiB After Width: | Height: | Size: 325 KiB |
@@ -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).
|
||||
|
||||
|
||||
@@ -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 |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
@@ -11,6 +11,7 @@ Dieser Ordner ist archiviert. Historische Betriebs-/Infra-Screenshots wurden nac
|
||||
`docs/80_Assets/exports/ops/archive/` verschoben.
|
||||
|
||||
Neue Screens bitte gemäß Docs-as-Code in folgenden Bereichen ablegen:
|
||||
|
||||
- UI-/Produkt-Screens: `docs/80_Assets/frontend/screens/<Modul>/...`
|
||||
- Figma-Exports: `docs/80_Assets/frontend/figma/<vision>/<bereich>/...`
|
||||
- Ops-/Infra-Exports: `docs/80_Assets/exports/ops/<topic>/...`
|
||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |