Compare commits

...

5 Commits

Author SHA1 Message Date
ef234747bc Create C-3 proposal for reorganizing docs/ folder structure: document hotspots, define target hierarchy, and outline migration plan. Update README.md and Curator roadmap with proposal details.
Some checks failed
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Has been cancelled
2026-04-03 23:19:28 +02:00
7150622e1d Update setup guide and README to emphasize desktop-first development. Add detailed instructions for local setup, including prerequisites (JDK 25, Gradle 9.4.0, Docker), and clarify Docker backend stack as optional. Mark Sprint C tasks C-1 and C-2 as complete. 2026-04-03 23:11:20 +02:00
c6f28462eb Update MVVM + UDF documentation: add metadata, extend examples, and consolidate references. Mark Curator roadmap tasks as complete. 2026-04-03 23:05:17 +02:00
dbe7c74a9c Document tenant-aware database schema, multi-tenant strategy, and API references:
- Add database schema documentation: `Database_Schema_V1-V009.md` for tenant-isolated entities (`veranstaltungen`, `turniere`, `bewerbe`, etc.).
- Draft initial Kassa API reference: `Kassa_API.md` (status: DRAFT).
- Finalize Stammdaten API reference: `API_Uebersicht_Stammdaten.md` (status: ACTIVE).
- Summarize tenant isolation and multi-tenant strategy in `Multi_Tenant_Kurz.md`.
- Update `README.md` with links to new references. Mark B-2 roadmap tasks as partially complete.
2026-04-03 22:59:45 +02:00
6e484ee9a1 Update MASTER_ROADMAP with Offline-First product focus and Phase 8 milestones. Add detailed concept document for Desktop↔Backend synchronization (konzept-offline-first-desktop-backend-de.md). Mark Sprint C tasks C-1 and C-2 as complete and link ADR-0021/0022 dependencies. 2026-04-03 22:52:19 +02:00
15 changed files with 628 additions and 55 deletions

View File

@ -1,6 +1,6 @@
# Meldestelle
> Modulares System für Pferdesportveranstaltungen — gebaut mit Domain-Driven Design, Kotlin Multiplatform und Microservices.
> DesktopFirst Meldestelle: Offlinefähige ComposeDesktopApp mit optionalem BackendStack. Domänengetrieben (DDD), Kotlin Multiplatform.
[![CI/CD Pipeline](https://git.mo-code.at/mocode-software/meldestelle/actions/workflows/docker-publish.yaml/badge.svg)](https://git.mo-code.at/mocode-software/meldestelle/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@ -15,20 +15,28 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
| Bereich | Inhalt |
|-----------------------------------------------|---------------------------------------------|
| [01_Architecture](./docs/01_Architecture) | Master Roadmap, ADRs, C4-Modelle |
| [01_Architecture](./docs/01_Architecture) | Master Roadmap, ADRs, C4Modelle, DesktopKonzept |
| [02_Guides](./docs/02_Guides) | Setup-Anleitungen, Entwickler-Guidelines |
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md)
---
## 🏗️ Tech Stack
## 🖥️ Primärer Fokus: DesktopApp
- Compose Multiplatform (JVM Desktop) als primäre Zielplattform
- OfflineFirst: Lokale SQLDelightDB, Synchronisation optional
- MultiTenantBackend optional für Sync/Verwaltung (SchemaperTenant, vgl. ADR0021)
## 🏗️ Tech Stack (aktueller Stand)
| Schicht | Technologie |
|-----------------------|---------------------------------------------------|
| **Backend** | Kotlin, Spring Boot 3.x, Spring Cloud Gateway |
| **Frontend** | Kotlin Multiplatform (KMP), Compose Multiplatform |
| **Datenbank** | PostgreSQL + Exposed / JPA |
| **Frontend (primär)** | Kotlin Multiplatform (KMP), Compose Multiplatform |
| **Backend** | Kotlin (Ktor/Spring Boot), Spring Cloud Gateway |
| **Datenbank** | SQLDelight (lokal), PostgreSQL (Backend) |
| **Auth** | Keycloak (OAuth2 / OIDC) |
| **Cache** | Valkey |
| **Service Discovery** | Consul |
@ -38,27 +46,51 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
---
## 🚀 Quick Start (Lokal)
## 🚀 Quick Start (lokale Entwicklung)
Empfohlen: Starte die DesktopApp direkt aus dem Repo. Der BackendStack ist optional und wird nur für Sync/Integration benötigt.
### A) DesktopApp starten (ohne Backend)
Voraussetzungen: JDK 21+, aktuelle Gradle Wrapper verwendet.
```bash
# 1. Umgebungsvariablen vorbereiten (nur beim ersten Mal)
cp .env.example .env
# DesktopShell ausführen (Compose Desktop)
./gradlew :frontend:shells:meldestelle-desktop:run
```
# 2. Infrastruktur starten (Postgres, Keycloak, Valkey, Consul, Zipkin)
Hinweise:
- Beim ersten Start wird die lokale Datenbank initialisiert (OfflineFirst).
- Architektur-Referenz: `docs/06_Frontend/MVVM_UDF_Pattern.md` (UDF/MVVM für ViewModels)
### B) Optional: BackendStack per Docker starten
```bash
# 1. Umgebungsvariablen (nur beim ersten Mal)
cp .env.example .env || true
# 2. Infrastruktur (Postgres, Keycloak, Valkey, Consul, Zipkin)
docker compose -f docker-compose.yaml -f dc-infra.yaml up -d
# 3. Backend-Services starten (Gateway, Ping-Service)
# 3. BackendServices (Gateway, Masterdata, Ping, …)
docker compose -f docker-compose.yaml -f dc-backend.yaml up -d
# 4. Ops-Stack starten (Prometheus, Grafana)
# 4. OpsStack (Prometheus, Grafana)
docker compose -f docker-compose.yaml -f dc-ops.yaml up -d
# 5. Optional: Web-App starten
# 5. Optional: WebShell
docker compose -f docker-compose.yaml -f dc-gui.yaml up -d
```
> ⚠️ **Reihenfolge beachten:** Infra muss `healthy` sein, bevor Backend gestartet wird.
> Keycloak benötigt ~6090 Sekunden zum Hochfahren.
> ⚠️ Reihenfolge beachten: Infra muss `healthy` sein, bevor Backend gestartet wird. Keycloak benötigt ~6090 Sekunden.
---
## 🧭 Legacy (V1) Hinweise
- Ältere V1Abschnitte/Anleitungen (WebFirst/MicroservicesOnly) gelten als DEPRECATED.
- Verwende für lokale Entwicklung primär die DesktopApp (siehe Quick Start). DockerStacks sind optional für Integration/Sync.
- In der Doku sind V1Seiten entsprechend markiert oder werden sukzessive bereinigt (siehe Roadmaps Sprint C4).
### Wichtige lokale Ports

View File

@ -2,7 +2,7 @@
type: Roadmap
status: ACTIVE
owner: Lead Architect
last_update: 2026-03-30
last_update: 2026-04-03
---
# MASTER ROADMAP: Meldestelle-Biest
@ -13,6 +13,10 @@ last_update: 2026-03-30
Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP).
Vollständige Self-Hosted Infrastruktur (Gitea, Pangolin, Zora). Datensouveränität, Offline-First, saubere Wissensbasis.
**Produktfokus:**
- Desktop-App ist der primäre Client (Compose Desktop, KMP) — „Desktop-First“ gilt für UX und Architektur.
- Offline-First Betrieb mit lokaler Persistenz und opportunistischer Synchronisation.
**Aktueller technischer Stand (30.03.2026):**
* **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen.
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
@ -204,10 +208,12 @@ und über definierte Schnittstellen kommunizieren.
*Ziel: Fachliche Tiefe in den Turnieren (Import, Generierung, Zeitberechnung).*
* [x] **Konzept/ADR:** LANSync (ADR0022) und OfflineFirst Desktop↔Backend Konzept definiert und verlinkt.
* [ ] **Bewerbe-Import:** Implementierung der Merge-Logik (ZNS-XML -> BewerbUiModel).
* [ ] **Startlisten-Automatisierung:** Generierung und Zeitberechnung (Pausen, Umbauzeiten).
* [ ] **Discovery:** Implementierung des mDNS-Service für die Geräte-Suche (Phase 7 Übertrag).
* [ ] **Transport:** Aufbau der WebSocket-Infrastruktur für P2P-Sync (Phase 7 Übertrag).
* [ ] **Offline-First Desktop↔Backend:** Umsetzung gemäß Konzept „Offline-First Synchronisation (Desktop ↔ Backend)“ → `docs/01_Architecture/konzept-offline-first-desktop-backend-de.md`.
### PHASE 9: Series-Context & Erweiterungen 🔵 PHASE 2+
@ -238,6 +244,8 @@ und über definierte Schnittstellen kommunizieren.
| 13 | Masterdata: API-Schichten (REST vs. Ingestion) | ✅ | ADR-0019 |
| 14 | Lokale Netzwerk-Kommunikation und Daten-Isolierung | ✅ | ADR-0020 |
| 15 | Masterdata: Observability & Operations | ✅ | masterdata-ops.md, CHANGELOG |
| 16 | Tenant-Resolution: Schema-per-Tenant | ✅ | ADR-0021 |
| 17 | LAN-Sync-Protokoll (Lamport-Uhren, Event-Sourcing Light) | ✅ | ADR-0022 |
---

View File

@ -0,0 +1,78 @@
---
type: [Proposal]
status: [DRAFT]
owner: [🏗️ Lead Architect, 🧹 Curator]
created: 2026-04-03
related:
- docs/01_Architecture/MASTER_ROADMAP.md
- docs/04_Agents/Roadmaps/Curator_Roadmap.md
---
# C-3: Vorschlag zur Unterordner-Struktur in `docs/`
## Ziel
Überladene/uneinheitliche Verzeichnisse identifizieren und eine klare, skalierbare Struktur vorschlagen, die zu unseren Prinzipien „DocsasCode“ und „OfflineFirst“ passt. Keine Moves im Rahmen dieses PRs nur Abstimmungsvorlage.
## Leitprinzipien
- One purpose per folder: thematische Trennung (Architektur, Domain, Backend, Frontend, Infrastruktur, Prozesse).
- Assets trennen: Binärdateien/Medien unter `assets/` konsolidieren, fachliche Inhalte bleiben textuell in Bereichsordnern.
- Zeitliche Inhalte standardisieren: Tägliche Notizen → `99_Journal/`, formelle Auswertungen/Status → `90_Reports/`.
- Reversibel: Bestehende Links möglichst stabil halten; bei Moves Redirect-Hinweise (Link-Stub) lassen.
## Hotspots (Ist-Zustand)
- `06_Frontend` (20+ Dateien, 10+ Unterordner): Fach-Docs, Logs, Screenshots und ein ZIP (FIGMA) gemischt.
- `99_Journal`: viele Session-Logs erwartbar groß, aber Index fehlt.
- `90_Reports`: Berichte gemischt ohne Subkategorien.
- Lose Ordner im Doc-Root ohne klare Zuordnung: `BilderSuDo/`, `ScreenShots/`, `temp/`, `OePS/`, `Neumarkt2026/`, `Bin/`.
## Zielstruktur (Top-Level, unverändert wo sinnvoll)
- `01_Architecture/` ADRs, Referenzen, Roadmaps, Proposals (neu: dieser Ordner)
- `02_Guides/` Setup- & HowToGuides
- `03_Domain/` Fachliche Referenzen, Glossar, Regelwerke
- `04_Agents/` Playbooks, Roadmaps, Sitzungsdokus der Agenten
- `05_Backend/` API, DBSchema, ServicesDoku
- `06_Frontend/` Patterns, Navigation, Guidelines (+ interner `README`/Index)
- `07_Infrastructure/` Deployment, Ops, Security
- `80_Assets/` NEU: Zentrale Medien & Binärartefakte
- `80_Assets/screenshots/`
- `80_Assets/figma/`
- `80_Assets/exports/` (z. B. HTMLTemplates, generierte Artefakte)
- `80_Assets/legacy/` (Altbestände wie `BilderSuDo`)
- `90_Reports/` Berichte, gegliedert nach Bereich/Projekt
- `90_Reports/frontend/`
- `90_Reports/backend/`
- `90_Reports/events/` (z. B. `Neumarkt2026/`)
- `99_Journal/` Chronologisches Journal (täglich), mit monatlichen Indexdateien
- `_archive/` Altes/abgelegtes Material (mit READMEs, warum archiviert)
## Migrationsmatrix (Quelle → Ziel)
- `docs/06_Frontend/FIGMA/**/*.zip``docs/80_Assets/figma/`
- `docs/06_Frontend/Screenshots/**/*``docs/80_Assets/screenshots/frontend/`
- `docs/06_Frontend/Logs/**/*``docs/90_Reports/frontend/logs/`
- `docs/06_Frontend/StartErgListen/*.html|*.png``docs/80_Assets/exports/erg-listen/`
- `docs/ScreenShots/**/*``docs/80_Assets/screenshots/`
- `docs/BilderSuDo/**/*``docs/80_Assets/legacy/BilderSuDo/`
- `docs/Neumarkt2026/**/*``docs/90_Reports/events/Neumarkt2026/`
- `docs/OePS/**/*``docs/03_Domain/02_Reference/OEPS/`
- `docs/Bin/**/*``docs/_archive/bin/` (oder `platform/tools/` sofern build-relevant; Klärung nötig)
- `docs/temp/**/*``docs/_archive/_temp/` (oder löschen, falls leer/obsolet)
## Phasenplan
1) Phase 1 (dieses Ticket): Inventur, Vorschlag, Abstimmung. Keine Moves, nur Verlinkungen/Indexe ergänzen.
2) Phase 2 (nach Freigabe): Gezielte Moves inkl. RedirectStubs (kurze MD-Dateien mit Verweis), Link-Update in Kern-Docs.
3) Phase 3 (Cleanup): Veraltete Duplikate entfernen oder als `ARCHIVED` markieren; monatliche Indizes für `99_Journal` einführen.
## Offene Punkte für den Architect
- `Bin/`: Enthält es build-relevante Tools? Falls ja, Verlagerung in `platform/` statt `_archive`.
- `OePS/`: Exakter Zielpfad unter `03_Domain/02_Reference/` Naming „OEPS“ vs. „OePS“ vereinheitlichen.
- HTMLTemplates (`StartErgListen`): Bleiben sie als Referenz im Frontend oder als Export/Asset?
- Fallback für große Binärdateien (>50 MB): Soll ein externes Artefakt-Repo genutzt werden?
## Auswirkungen
- Klare Trennung zwischen TextDoku und Medien → bessere Lesbarkeit, schnellere Diffs.
- Bessere Skalierbarkeit der zeitlichen Inhalte (Reports/Journal) → einfache Auffindbarkeit.
- Geringes Bruchrisiko dank RedirectStubs in Phase 2.
## Nächste Schritte
- Review durch 🏗️ Architect
- Nach Freigabe: Migrations-Tickets je Teilbereich (Frontend, Reports, Assets)

View File

@ -0,0 +1,147 @@
---
type: Concept
status: DRAFT
owner: Lead Architect
last_update: 2026-04-03
---
# Konzept: Offline-First Synchronisation (Desktop ↔ Backend)
## 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.
Nicht-Ziele: Cloud-Realtime für Endnutzer, kollaboratives Editieren außerhalb des Veranstaltungsbetriebs.
## Leitprinzipien
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.
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.
- 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.
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 |
Konflikte über Kategoriegrenzen werden durch Mastership-Regeln verhindert; verbleibende Konflikte werden per Regel-Matrix gelöst.
## Änderungsmodell (Wiederverwendung `SyncEvent`)
Struktur wie in ADR-0022 beschrieben:
```kotlin
data class SyncEvent(
val eventId: String,
val turnierId: String?,
val sequenceNumber: Long, // Lamport
val originNodeId: String, // Desktop-ID oder Backend-Node-ID
val aggregateType: String, // z. B. "Nennung", "Bewertung", "Start"
val aggregateId: String,
val eventType: String,
val payload: ByteArray,
val createdAt: Instant,
val checksum: String,
val schemaVersion: Int,
)
```
- Erweiterung: `schemaVersion` ist Pflichtfeld für WAN-Sync (Schema-Evolution, Rolling Upgrades).
- Persistenz: `sync_events`, `sync_snapshots` lokal (SQLDelight) und im Backend (pro Tenant-Schema) gespiegelt.
## 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.
## 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.
Empfohlene Endpunkte (pro `eventId`):
```
POST /api/sync/{eventId}/hello → { nodeId, lastKnownSeq } → { backendNodeId, currentSeq, minSupportedSchema }
POST /api/sync/{eventId}/pull → { sinceSeq, limit } → [ SyncEvent... ], { nextSeq }
POST /api/sync/{eventId}/push → [ SyncEvent... ] → { ackedMaxSeq, rejected:[ids...] }
POST /api/sync/{eventId}/snapshot/request → { scope } → { snapshotBlob, snapshotSeq }
POST /api/sync/{eventId}/diagnostics → { stats } → { advice }
```
Batching: bis 512 Events oder 1 MiB pro Batch. Serverseitiges Paging über `sinceSeq`/`nextSeq`.
Idempotenz: Jeder `SyncEvent` wird durch `(eventId, originNodeId, sequenceNumber, checksum)` dedupliziert.
## 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).
- 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.
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).
3) Reihenfolge-/Kausalitätskonflikte:
- 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.
## 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.
- 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.
- 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`.
- Logs: pro Event `tenant`, `originNodeId`, `seq`, `aggType`, `eventType`, `result`.
- UI: Status-Anzeige (Verbunden, Getrennt, Ausstehend X), Konflikt-Review-Queue.
## Einführungsplan (Auszug)
1. Core: `SyncEvent` in Shared-KMP-Modul härten (`schemaVersion`), Persistenzschicht Desktop/Backend angleichen.
2. Backend-API: `hello/pull/push/snapshot` Endpunkte implementieren (Spring Boot/Ktor), Mandantentrennung.
3. Desktop-Client: Batch-Sync, Retry, Id-Mapping-Mechanismus.
4. Review-UI: `PENDING_REVIEW`-Queue im Backend (Admin) und Anzeige im Desktop.
5. E2E-Tests: Offline-Phase, Reconnect, Konflikt, Provisionals-Merge, Schema-Rolling-Upgrade.
## Referenzen
- [ADR-0021: Tenant-Resolution-Strategie](adr/0021-tenant-resolution-strategy-de.md)
- [ADR-0022: LAN-Sync-Protokoll (Meldestelle ↔ Richter-Turm)](adr/0022-lan-sync-protocol-de.md)

View File

@ -7,14 +7,19 @@ tags: [setup, local, docker, gradle]
# Start Local (Lokales Setup)
Kurzanleitung, um das Projekt lokal in wenigen Minuten zu starten.
Kurzanleitung, um das Projekt lokal in wenigen Minuten zu starten DesktopFirst mit optionalem DockerBackend.
## Voraussetzungen
- Docker und Docker Compose (v2)
- Java 25 (JDK)
- Git
## Voraussetzungen (exakte Versionen)
- Git ≥ 2.40
- JDK 25 (Temurin/Eclipse Adoptium empfohlen) Projekttoolchain lädt bei Bedarf automatisch
- Gradle Wrapper 9.4.0 (wird über `./gradlew` automatisch verwendet)
- Docker Engine ≥ 24, Docker Compose v2 ≥ 2.24
## Schnellstart
Hinweise:
- Die JavaToolchain wird per Gradle automatisch heruntergeladen (`org.gradle.java.installations.auto-download=true`). Ein lokal installiertes JDK 25 wird dennoch empfohlen für IDERuns.
- Auf AppleSilicon (arm64) sind die DockerImages optimiert; Keycloak nutzt `start --optimized`.
## Schnellstart (nur Backend in Docker)
```bash
# 1) Repository klonen
@ -25,7 +30,7 @@ cd meldestelle
# Kopiere die Vorlage.
cp .env.example .env
# 3) Infrastruktur starten (Postgres, Redis, Keycloak, Monitoring, Gateway)
# 3) Infrastruktur starten (Postgres, Valkey, Keycloak, Tracing, Service Discovery)
docker compose --profile infra up -d
# 4) Backend starten (Gateway + Ping Service)
@ -33,10 +38,25 @@ docker compose --profile backend up -d
```
Sobald die Infrastruktur läuft, erreichst du unter anderem:
- Gateway: http://localhost:8081
- Keycloak: http://localhost:8180
- Grafana: http://localhost:3000
- Prometheus: http://localhost:9090
- Gateway (API): http://localhost:8081
- Keycloak (IAM): http://localhost:8180
- Zipkin (Tracing): http://localhost:9411
- Consul (Service Discovery): http://localhost:8500
- Optional WebApp (falls `--profile gui` gebaut/gestartet): http://localhost:4000
## DesktopApp starten (Compose Desktop)
Die DesktopApp ist der primäre EntwicklungsEntryPoint.
```bash
# 1) Abhängigkeiten bauen (optional; Gradle lädt automatisch beim ersten Run)
./gradlew :frontend:shells:meldestelle-desktop:build
# 2) DesktopApp starten
./gradlew :frontend:shells:meldestelle-desktop:run
```
Voraussetzung: Für Features, die BackendKonnektivität benötigen (z. B. Login, Stammdaten), muss das DockerBackend (infra + backend) laufen. Für rein lokale/offline Flows kann die App auch ohne Docker gestartet werden.
## Tests ausführen
```bash
@ -58,9 +78,12 @@ Sobald die Infrastruktur läuft, erreichst du unter anderem:
docker compose down -v
docker compose --profile infra up -d
```
- Environment-Variablen: werden aus der `.env`-Datei im Root-Verzeichnis geladen.
- EnvironmentVariablen: werden aus der `.env`Datei im RootVerzeichnis geladen.
- Gradle/Java Probleme? Stelle sicher, dass JDK 25 aktiv ist bzw. lasse die GradleToolchain das passende JDK laden.
- ARM64 (Apple Silicon): Falls Images nicht starten, lösche alte Images und starte neu: `docker compose down -v && docker system prune -af && docker compose --profile infra up -d`.
## Weiterführende Hinweise
- Architektur: `docs/01_Architecture/MASTER_ROADMAP_2026_Q1.md`
- README QuickStart (DesktopFirst): `README.md`
- ArchitekturKurzkonzept (OfflineFirst Desktop & Backend): `docs/01_Architecture/konzept-offline-first-desktop-backend-de.md`
- ADRs: `docs/01_Architecture/adr/`
- Aktuelle Reports: `docs/90_Reports/`

View File

@ -39,15 +39,17 @@
## 🟠 Sprint C — Priorität 2 (nächste Woche)
- [ ] **C-1** | Synchronisations-Protokoll-Konzeption
- [ ] Offline-First-Konzept für Desktop ↔ Backend ausarbeiten
- [ ] Conflict-Resolution-Strategie definieren (gleichzeitige Änderungen)
- [ ] Konzept-Dokument in `docs/01_Architecture/` ablegen
- [x] Offline-First-Konzept für Desktop ↔ Backend ausarbeiten
- [x] Conflict-Resolution-Strategie definieren (gleichzeitige Änderungen)
- [x] Konzept-Dokument in `docs/01_Architecture/` ablegen → `docs/01_Architecture/konzept-offline-first-desktop-backend-de.md`
- Verweis/Bezug: Baut auf ADR-0021 (Tenant) und ADR-0022 (LAN-Sync Lamport) auf; einheitliches `SyncEvent`-Modell Desktop↔Backend.
- [ ] **C-2** | MASTER_ROADMAP aktualisieren
- [ ] Desktop-App-Fokus eintragen
- [ ] Tenant-Isolation-Meilensteine (Sprint A Ergebnisse) als erledigt markieren
- [ ] Offline-Sync-Meilensteine eintragen
- [ ] Phase 8 Fortschritt reflektieren
- [x] Desktop-App-Fokus eintragen
- [x] Tenant-Isolation-Meilensteine (Sprint A Ergebnisse) als erledigt markieren
- [x] Offline-Sync-Meilensteine eintragen
- [x] Phase 8 Fortschritt reflektieren
- Update: Siehe `docs/01_Architecture/MASTER_ROADMAP.md` (Stand 2026-04-03) — Produktfokus ergänzt, ADR0021/0022 in ADRTabelle eingetragen, Phase8Status („Konzept/ADR erledigt“) markiert, Todo „OfflineFirst Desktop↔Backend“ verlinkt.
---

View File

@ -42,33 +42,33 @@
- [x] Alle Roadmaps: abgeschlossene Aufgaben korrekt als `[x]` markiert
- [ ] **B-2** | `docs/05_Backend/` aktualisieren
- [ ] Datenbankschema dokumentieren: Tabellen `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`,
`teilnehmer_konten`, `turnier_kassa` (Flyway V1V009)
- [ ] API-Endpunkte-Übersicht erstellen: Reiter, Pferde, Vereine, Funktionäre (Backend B-1 ✅ abgeschlossen)
- [ ] Kassa-Endpunkte ergänzen sobald Backend B-2 abgeschlossen (`/kassa/saldo`, `/zahlvorgaenge`)
- [ ] Tenant-Isolation (ADR-0021) und Multi-Tenant-Architektur kurz beschreiben
- [x] Datenbankschema dokumentieren: Tabellen `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`,
`teilnehmer_konten`, `turnier_kassa` (Flyway V1V009)`docs/05_Backend/Schema/Database_Schema_V1-V009.md` (03.04.2026)
- [x] API-Endpunkte-Übersicht erstellen: Reiter, Pferde, Vereine, Funktionäre (Backend B-1 ✅ abgeschlossen)`docs/05_Backend/API/API_Uebersicht_Stammdaten.md` (03.04.2026)
- [ ] Kassa-Endpunkte ergänzen sobald Backend B-2 abgeschlossen (`/kassa/saldo`, `/zahlvorgaenge`) → Platzhalter: `docs/05_Backend/API/Kassa_API.md` (DRAFT)
- [x] Tenant-Isolation (ADR-0021) und Multi-Tenant-Architektur kurz beschreiben`docs/05_Backend/Multi_Tenant_Kurz.md` (03.04.2026)
- [ ] **B-3** | `docs/06_Frontend/` aktualisieren
- [ ] ViewModel-Architektur-Muster (MVVM/UDF) verlinken
- [ ] Verweis auf `VeranstalterViewModel` als Referenz-Implementierung eintragen
- [x] ViewModel-Architektur-Muster (MVVM/UDF) verlinken`docs/06_Frontend/MVVM_UDF_Pattern.md` (03.04.2026)
- [x] Verweis auf `VeranstalterViewModel` als Referenz-Implementierung eintragen → Code: `frontend/features/veranstalter-feature/src/commonMain/kotlin/at/mocode/veranstalter/feature/presentation/VeranstalterViewModel.kt` (03.04.2026)
---
## 🟠 Sprint C — Priorität 2 (nächste Woche)
- [ ] **C-1** | `README.md` aktualisieren
- [ ] Desktop-App als primären Fokus hervorheben
- [ ] Schnellstart-Anleitung für lokale Entwicklungsumgebung prüfen
- [ ] Veraltete V1-Abschnitte entfernen oder als deprecated markieren
- [x] Desktop-App als primären Fokus hervorheben → `README.md` (03.04.2026)
- [x] Schnellstart-Anleitung für lokale Entwicklungsumgebung prüfen → Desktop-Run (`:frontend:shells:meldestelle-desktop:run`) ergänzt (03.04.2026)
- [x] Veraltete V1-Abschnitte entfernen oder als deprecated markieren → Abschnitt „Legacy (V1) Hinweise“ in `README.md` (03.04.2026)
- [ ] **C-2** | Setup-Guide aktualisieren
- [ ] Schritt-für-Schritt: Projekt klonen → Docker starten → Desktop-App starten
- [ ] Voraussetzungen (JDK, Gradle, Docker) mit exakten Versionen dokumentieren
- [ ] Dokument in `docs/02_Guides/` ablegen
- [x] **C-2** | Setup-Guide aktualisieren ✅ *3. April 2026*
- [x] Schritt-für-Schritt: Projekt klonen → Docker starten → Desktop-App starten`docs/02_Guides/start-local.md`
- [x] Voraussetzungen (JDK, Gradle, Docker) mit exakten Versionen dokumentiert (JDK 25, Gradle 9.4.0, Compose v2)
- [x] Dokument in `docs/02_Guides/` abgelegt/aktualisiert → `docs/02_Guides/start-local.md`
- [ ] **C-3** | Unterordner-Struktur in `docs/` prüfen
- [ ] Überladene Verzeichnisse identifizieren
- [ ] Strukturvorschlag mit Architect abstimmen
- [x] Überladene Verzeichnisse identifizieren → Hotspots dokumentiert (06_Frontend, 99_Journal, 90_Reports, BilderSuDo, ScreenShots, temp, OePS, Neumarkt2026, Bin) (03.04.2026)
- [ ] Strukturvorschlag mit Architect abstimmen → Proposal: `docs/01_Architecture/Proposals/C-3_Docs-Strukturvorschlag.md`
- [ ] **C-4** | V1-Code-Bereinigung koordinieren
- [ ] V1-Dateien und -Module zusammen mit Frontend + Backend identifizieren

View File

@ -0,0 +1,63 @@
---
type: Reference
status: ACTIVE
owner: Backend Developer
last_update: 2026-04-03
---
# API-Übersicht Stammdaten
Abdeckung: Backend Sprint B1 (abgeschlossen). Konsolidierte Endpunkte für Reiter, Pferde, Vereine und Funktionäre. Implementiert mit Ktor; DTOs und Validierung in den jeweiligen Services.
Hinweis Tenant/Headers: Stammdaten sind global bzw. nicht tenantspezifisch. Für domainspezifische Vorgänge (Entries, Kassa) gilt ADR0021/`X-Event-Id`.
## Reiter (`/reiter`)
- GET `/reiter` — Liste (optional Filter: `lizenzKlasse`, `vereinId`; Pagination: `limit`, `offset`)
- GET `/reiter/search?q=...` — Suche nach Name oder Satznummer
- GET `/reiter/{id}` — Einzelabruf
- GET `/reiter/satznummer/{nr}` — Lookup per Satznummer
- POST `/reiter` — Anlegen
- PUT `/reiter/{id}` — Aktualisieren (partiell)
- DELETE `/reiter/{id}` — Löschen
Quelle: `backend/services/masterdata/masterdata-api/.../ReiterController.kt`
## Pferde (`/horse`)
- GET `/horse` — Liste (optional Filter: `jahrgang`, `besitzerId`; Pagination: `limit`, `offset`)
- GET `/horse/search?q=...` — Suche nach Name/Nummern
- GET `/horse/{id}` — Einzelabruf
- POST `/horse` — Anlegen
- PUT `/horse/{id}` — Aktualisieren (partiell)
- DELETE `/horse/{id}` — Löschen
Quelle: `backend/services/masterdata/masterdata-api/.../HorseController.kt`
## Vereine (`/verein`)
- GET `/verein` — Liste (optional Filter: `verband`/Bundesland; Pagination: `limit`, `offset`)
- GET `/verein/search?q=...` — Suche nach Name/Kurzname
- GET `/verein/{id}` — Einzelabruf
- POST `/verein` — Anlegen
- PUT `/verein/{id}` — Aktualisieren (partiell)
- DELETE `/verein/{id}` — Löschen
Quelle: `backend/services/masterdata/masterdata-api/.../VereinController.kt`
## Funktionäre (`/funktionaer`)
- GET `/funktionaer` — Liste (optional Filter: `rolle`; Pagination: `limit`, `offset`)
- GET `/funktionaer/search?q=...` — Suche nach Name
- GET `/funktionaer/{id}` — Einzelabruf
- POST `/funktionaer` — Anlegen
- PUT `/funktionaer/{id}` — Aktualisieren (partiell)
- DELETE `/funktionaer/{id}` — Löschen
Quelle: `backend/services/masterdata/masterdata-api/.../FunktionaerController.kt`
## Standards
- Auth: Standard-Bearer optional je nach Deploymentprofil (siehe Service-Konfig)
- Content-Type: `application/json; charset=utf-8`
- Fehlerfälle: 400 (Validierung), 404 (nicht gefunden)

View File

@ -0,0 +1,37 @@
---
type: Reference
status: DRAFT
owner: Backend Developer
last_update: 2026-04-03
---
# Kassa-API (Entwurf)
Abhängigkeit: Backend Sprint B2 (Kassa-Service) — laut CuratorRoadmap noch offen. Dieses Dokument reserviert die Endpunkte und beschreibt die Erwartungen. Die Implementierungsdetails werden ergänzt, sobald der Service fertiggestellt ist.
Mandantenkontext: Erfordert `X-Event-Id` (ADR0021). Alle KassaOperationen sind tenantlokal.
## Endpunkte (geplant)
- GET `/kassa/saldo` — Liefert den aktuellen Saldo der Veranstaltung und optional pro Turnier.
- Query: `turnierId` (optional, UUID)
- Response: `{ saldoCents: long, currency: "EUR", scope: "veranstaltung"|"turnier", turnierId?: UUID }`
- GET `/zahlvorgaenge` — Listet KassaBuchungen/Zahlvorgänge (paginiert, filterbar).
- Query: `turnierId?`, `teilnehmerId?`, `typ?` (EINZAHLUNG|AUSZAHLUNG|KORREKTUR), `limit`, `offset`
- Response: Liste von Transaktionen mit Betrag, Zeit, Verweis (Teilnehmer/Turnier), Notiz
- POST `/zahlvorgaenge` — Erstellt einen neuen Zahlungsvorgang (Ein-/Auszahlung/Korrektur).
- Body: `{ typ, betragCents, currency, referenz: { teilnehmerId?|turnierId? }, notiz? }`
- Wirkung: Aktualisiert `teilnehmer_konten` bzw. `turnier_kassa` atomar.
## Validierung & Regeln (voraussichtlich)
- Atomare Konsistenz: Transaktion + SaldoUpdate innerhalb einer DBTransaktion.
- Negativsaldo optional durch FeatureFlag blockierbar.
- AuditTrail pro Vorgang (who/when), IdempotenzKey optional.
## Implementierungsstand
- Datenstrukturen `teilnehmer_konten` und `turnier_kassa` sind per Flyway angelegt (siehe [Datenbankschema](../Schema/Database_Schema_V1-V009.md)).
- Endpunkte folgen nach Abschluss Backend B2. Dieses Dokument wird dann auf `status: ACTIVE` gesetzt.

View File

@ -0,0 +1,28 @@
---
type: Reference
status: ACTIVE
owner: Lead Architect
last_update: 2026-04-03
---
# Tenant-Isolation & MultiTenant (Kurzfassung)
Vollständige Entscheidung: [ADR0021: TenantResolutionStrategie (SchemaperTenant)](../01_Architecture/adr/0021-tenant-resolution-strategy-de.md).
## Kernaussagen
- Eine Veranstaltung = ein Tenant = ein Datenbankschema (SchemaperTenant).
- Requests tragen `X-Event-Id`; Backend validiert gegen `control.tenants` und schaltet das Schema je Request.
- Flyway führt Migrationen je TenantSchema aus (eigene `flyway_schema_history`).
- Stammdaten (Reiter/Pferde/Vereine/Funktionäre) sind global und nicht tenantspezifisch; Entries/Kassa sind tenantlokal.
## Umsetzung (Kurz)
- WebLayer: `TenantWebFilter` (Spring) bzw. Plugin (Ktor) liest `X-Event-Id` und legt `TenantContext` ab.
- Persistence: SCHEMAMultitenancy (`SET search_path`) oder Hibernate`MultiTenantConnectionProvider`.
- Registry: `control.tenants(event_id, schema_name, status, db_url?, version, created_at)`.
## Betroffene Bereiche
- Datenmodell tenantlokal: `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`, `teilnehmer_konten`, `turnier_kassa` (siehe [Datenbankschema](./Schema/Database_Schema_V1-V009.md)).
- Services: Der EntriesService arbeitet mandantenfähig; andere Services bleiben SingleTenant/global (vgl. BackendRoadmap).

View File

@ -11,9 +11,15 @@ Dieses Verzeichnis enthält die spezifische Dokumentation für alle Backend-Komp
## Struktur
* `Services/`: Enthält pro Service eine dedizierte Markdown-Datei, die dessen Zweck, API, Datenmodell und Konfiguration beschreibt.
* `API/`: Querliegende API-Referenzen und Übersichten (Stammdaten, Kassa, usw.).
* `Schema/`: Datenbankschemata und Migrationsübersichten (Flyway).
* `Integration/`: Dokumentation zur Interaktion zwischen den Services (z.B. Event-Flows).
## Wichtige Einstiegspunkte
* **[Ping-Service](./Services/PingService_Reference.md):** Dient als technischer Blueprint und einfachstes Beispiel für einen Service.
* **[API-Gateway](../07_Infrastructure/api-gateway.md):** Beschreibung des zentralen Einstiegspunkts für alle externen Anfragen.
* **[Stammdaten-APIs (Reiter, Pferde, Vereine, Funktionäre)](./API/API_Uebersicht_Stammdaten.md):** Konsolidierte Endpunkt-Übersicht (Backend B1 abgeschlossen).
* **[Datenbankschema V1V009](./Schema/Database_Schema_V1-V009.md):** Tabellen und Constraints (veranstaltungen, turniere, bewerbe, abteilungen, teilnehmer_konten, turnier_kassa).
* **[Kassa-API](./API/Kassa_API.md):** Platzhalter für Saldo/Transaktionen; wird ergänzt, sobald Backend B2 Kassa fertig ist.
* **[Tenant-Isolation & MultiTenant kurz](./Multi_Tenant_Kurz.md):** Zusammenfassung gem. ADR0021.

View File

@ -0,0 +1,130 @@
---
type: Reference
status: ACTIVE
owner: Backend Developer
last_update: 2026-04-03
---
# Datenbankschema V1V009 (TenantSchema)
Quelle: FlywayMigrationen im EntriesService (`backend/services/entries/entries-service/src/main/resources/db/tenant/`), insbesondere `V2__domain_hierarchy.sql`.
Hinweis zur Architektur: Je Veranstaltung (Tenant) existiert ein eigenes Datenbankschema (ADR0021). Alle untenstehenden Tabellen werden pro TenantSchema angelegt und sind somit mandantengetrennt.
## Tabellenübersicht
- `veranstaltungen` — Eine Veranstaltung (Singleton im TenantSchema)
- `turniere` — Turniere einer Veranstaltung (1:N zu `veranstaltungen`)
- `bewerbe` — Bewerbe/Prüfungen eines Turniers (1:N zu `turniere`)
- `abteilungen` — Abteilungen/Heats eines Bewerbs (1:N zu `bewerbe`)
- `teilnehmer_konten` — Aggregierte Salden eines Teilnehmers über alle Turniere der Veranstaltung
- `turnier_kassa` — KassaSaldo pro Turnier
## Detaillierte Definitionen (aus V2__domain_hierarchy.sql)
### veranstaltungen
Primärschlüssel: `id (UUID)`
Spalten:
- `id UUID PRIMARY KEY`
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
### turniere
Primärschlüssel: `id (UUID)`
Fremdschlüssel: `veranstaltung_id → veranstaltungen(id) ON DELETE CASCADE`
Spalten:
- `id UUID PRIMARY KEY`
- `veranstaltung_id UUID NOT NULL`
- `oeps_turniernummer VARCHAR(50) NOT NULL`
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
Indizes/Constraints:
- `UNIQUE (oeps_turniernummer)``uq_turniere_oeps_nr`
- `INDEX (veranstaltung_id)``idx_turniere_veranstaltung_id`
### bewerbe
Primärschlüssel: `id (UUID)`
Fremdschlüssel: `turnier_id → turniere(id) ON DELETE CASCADE`
Spalten:
- `id UUID PRIMARY KEY`
- `turnier_id UUID NOT NULL`
- `klasse VARCHAR(50) NOT NULL`
- `hoehe_cm INTEGER NULL`
- `bezeichnung TEXT NOT NULL`
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
Indizes:
- `INDEX (turnier_id)``idx_bewerbe_turnier_id`
- `INDEX (klasse)``idx_bewerbe_klasse`
### abteilungen
Primärschlüssel: `id (UUID)`
Fremdschlüssel: `bewerb_id → bewerbe(id) ON DELETE CASCADE`
Spalten:
- `id UUID PRIMARY KEY`
- `bewerb_id UUID NOT NULL`
- `nr INTEGER NOT NULL`
- `bezeichnung TEXT NOT NULL`
- `typ VARCHAR(32) NOT NULL` (Werte: `SEPARATE_SIEGEREHRUNG`, `ORGANISATORISCH`)
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
Constraints/Indizes:
- `CHECK (typ IN ('SEPARATE_SIEGEREHRUNG','ORGANISATORISCH'))``chk_abteilungen_typ`
- `UNIQUE (bewerb_id, nr)``uq_abteilungen_bewerb_nr`
- `INDEX (bewerb_id)``idx_abteilungen_bewerb_id`
- `INDEX (typ)``idx_abteilungen_typ`
### teilnehmer_konten
Primärschlüssel: `id (UUID)`
Fremdschlüssel: `veranstaltung_id → veranstaltungen(id) ON DELETE CASCADE`
Spalten:
- `id UUID PRIMARY KEY`
- `veranstaltung_id UUID NOT NULL`
- `teilnehmer_id UUID NOT NULL`
- `saldo_cents BIGINT NOT NULL DEFAULT 0`
- `currency CHAR(3) NOT NULL DEFAULT 'EUR'`
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
Indizes/Constraints:
- `UNIQUE (veranstaltung_id, teilnehmer_id)``uq_tkonten_veranstaltung_teilnehmer`
- `INDEX (veranstaltung_id)``idx_tkonten_veranstaltung_id`
- `INDEX (teilnehmer_id)``idx_tkonten_teilnehmer_id`
### turnier_kassa
Primärschlüssel: `id (UUID)`
Fremdschlüssel: `turnier_id → turniere(id) ON DELETE CASCADE`
Spalten:
- `id UUID PRIMARY KEY`
- `turnier_id UUID NOT NULL`
- `saldo_cents BIGINT NOT NULL DEFAULT 0`
- `currency CHAR(3) NOT NULL DEFAULT 'EUR'`
- `created_at TIMESTAMPTZ NOT NULL`
- `updated_at TIMESTAMPTZ NOT NULL`
Indizes/Constraints:
- `UNIQUE (turnier_id)``uq_turnier_kassa_turnier`
- `INDEX (turnier_id)``idx_turnier_kassa_turnier_id`
## Versionierung / Flyway
- Die oben dokumentierten Tabellen sind in `V2__domain_hierarchy.sql` definiert.
- Weitere Migrationen V1V009 betreffen Bootstrap/Erweiterungen; diese Seite wird fortlaufend ergänzt, sobald neue fachrelevante Strukturen hinzukommen.
## Beziehungen (Kurz)
`veranstaltungen (1) ──< (N) turniere (1) ──< (N) bewerbe (1) ──< (N) abteilungen`
Separat aggregierend:
- `teilnehmer_konten` auf Veranstaltungsebene (pro Teilnehmer genau ein Konto)
- `turnier_kassa` auf Turnierebene (pro Turnier genau ein KassaEintrag)

View File

@ -1,3 +1,10 @@
---
type: Reference
status: ACTIVE
owner: Frontend Expert
last_update: 2026-04-03
---
### MVVM + UDF (Unidirectional Data Flow) — Referenz & Vorlage
Ziel: Alle ViewModels folgen einem klaren, einheitlichen Muster. Composables rendern nur `State` und senden `Intent`s. Business-Logik liegt im ViewModel, nicht in den UI-Funktionen.
@ -14,7 +21,7 @@ Ziel: Alle ViewModels folgen einem klaren, einheitlichen Muster. Composables ren
#### Referenz-Implementierung: Veranstalter
Dateien:
- `frontend/features/veranstalter-feature/src/commonMain/.../VeranstalterViewModel.kt`
- `frontend/features/veranstalter-feature/src/commonMain/kotlin/at/mocode/veranstalter/feature/presentation/VeranstalterViewModel.kt`
- `frontend/features/veranstalter-feature/src/jvmMain/.../DefaultVeranstalterRepository.kt`
- `frontend/features/veranstalter-feature/src/jvmMain/.../VeranstalterAuswahlScreen.kt` (verwendet das ViewModel)
@ -99,6 +106,10 @@ fun VeranstalterAuswahlScreen(onZurueck: () -> Unit, onWeiter: (Long) -> Unit) {
- Persistenz/Netzwerk-Zugriffe laufen im Repository. Das ViewModel injiziert das Repository (später per DI).
- State ist die Single Source of Truth pro Screen.
#### Siehe auch
- Weitere Beispiele: `ReiterViewModel`, `PferdeViewModel`, `PingViewModel` in `frontend/features/*/presentation/`
- Koin-Integration (VM-Erzeugung in Composables): `org.koin.compose.viewmodel.koinViewModel`
#### Vorlage für neue ViewModels
1. `data class UiState(...)`
2. `sealed interface Intent { ... }`

View File

@ -2,7 +2,7 @@
type: Reference
status: ACTIVE
owner: Frontend Expert
last_update: 2026-01-15
last_update: 2026-04-03
---
# Frontend-Architektur "Meldestelle Portal"
@ -40,7 +40,9 @@ Das `frontend`-Verzeichnis ist wie folgt strukturiert, um eine klare Trennung de
## Wichtige Dokumente
* **[State-Management Strategie (UDF)](state-management-strategy.md):** Beschreibt die empfohlene Strategie für komplexe Screens.
* **[MVVM + UDF Referenz (ViewModel-Architektur)](MVVM_UDF_Pattern.md):** Verbindliches Muster für ViewModels inkl. Referenz-Implementierung `VeranstalterViewModel`.
* Referenz-Code: `frontend/features/veranstalter-feature/src/commonMain/kotlin/at/mocode/veranstalter/feature/presentation/VeranstalterViewModel.kt`
* (Alt) **State-Management Strategie (UDF)**: Wird durch obige Referenz konsolidiert/ersetzt.
* **[ADR-0010: SQLDelight für Cross-Platform-Persistenz](../01_Architecture/adr/0010-sqldelight-for-cross-platform-persistence.md):** Beschreibt die Entscheidung für SQLDelight.
* **[ADR-0011: Koin für Dependency Injection](../01_Architecture/adr/0011-koin-for-dependency-injection.md):** Beschreibt die Entscheidung für Koin.
* **[Offline-First-Architektur](offline-first-architecture.md):** Detaillierte Beschreibung der Offline-First-Strategie.

View File

@ -42,3 +42,9 @@ Willkommen im "Gehirn" des Projekts. Dieses Verzeichnis ist die **Single Source
* [Master Roadmap](01_Architecture/MASTER_ROADMAP.md)
* [Agent Playbooks](04_Agents)
* [Zora Infrastruktur](07_Infrastructure/Zora_System_Architektur.md)
* [C-3 Proposal: Docs-Unterordner-Struktur](01_Architecture/Proposals/C-3_Docs-Strukturvorschlag.md)
---
## 📦 Hinweis zur Reorganisation (C-3)
Im Rahmen von C-3 wird eine Konsolidierung von Medien/Binärartefakten unter `docs/80_Assets/` sowie eine feinere Gliederung von Reports/Journals vorgeschlagen. Aktuell finden keine Verschiebungen statt Details siehe Proposal oben.