Update documentation for Navigation V3 and tenant concept: Mark Navigation V2 as deprecated, link replacement documentation, and expand tenant concept details with frontend and backend integration guidelines.
Some checks failed
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
Some checks failed
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
This commit is contained in:
parent
6595ec674f
commit
85282ea7b4
|
|
@ -1,66 +1,114 @@
|
|||
---
|
||||
type: Architecture
|
||||
type: Architecture Reference
|
||||
status: ACTIVE
|
||||
owner: 🏗️ Lead Architect & 🧹 Curator
|
||||
owner: 🧹 Curator & 🏗️ Lead Architect
|
||||
last_update: 2026-04-02
|
||||
sources:
|
||||
- docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md
|
||||
- Domain Workshop 2026-03-24
|
||||
- docs/02_Guides/Event-First-Workflow.md
|
||||
- docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md
|
||||
---
|
||||
|
||||
# Tenant‑Konzept: „Eine Veranstaltung = eine Datenbank“ (in einfacher Sprache)
|
||||
# Tenant‑Konzept — Eine Veranstaltung = eine Datenbank (ein Tenant)
|
||||
|
||||
Kurz gesagt: Jede Veranstaltung bekommt ihre eigene kleine Datenbank. So bleiben Daten sauber getrennt, und die Meldestelle kann offline sicher arbeiten, ohne andere Veranstaltungen zu berühren.
|
||||
Dieses Dokument erklärt in einfacher Sprache, wie wir Daten pro Veranstaltung trennen. Grundlage ist ADR‑0021 (Schema‑per‑Tenant). Kurz gesagt: Für jede Veranstaltung gibt es eine eigene „Datenbank‑Schublade“. Nichts aus Veranstaltung A landet versehentlich in Veranstaltung B.
|
||||
|
||||
Weitere Details in der technischen Entscheidung:
|
||||
|
||||
- ADR‑0021: `docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Warum machen wir das?
|
||||
## 1) Idee in Alltagssprache
|
||||
|
||||
- Sicherheit und Ordnung: Was zu Veranstaltung A gehört, landet nicht aus Versehen bei Veranstaltung B.
|
||||
- Offline‑Tauglichkeit: Eine Datenbank pro Veranstaltung ist klein, lokal und schnell zu sichern/verteilen.
|
||||
- Einfache Abrechnung: Die Veranstaltungs‑Kassa und die TeilnehmerKonten sind klar auf Event‑Ebene definiert.
|
||||
- Stell dir jede Veranstaltung wie einen eigenen Ordner vor. In diesem Ordner liegen alle Tabellen und Daten nur für genau diese Veranstaltung.
|
||||
- Öffnest du eine andere Veranstaltung, arbeitest du automatisch in einem anderen Ordner. Es gibt keine Vermischung.
|
||||
- Dadurch sind Archivierung, Backup, Wiederherstellung oder Löschen pro Veranstaltung einfach und sicher.
|
||||
|
||||
Technisch heißt das: „Schema‑per‑Tenant“. Ein „Schema“ ist wie ein separater Ordner in derselben Datenbank. Optional können sehr große/sensible Veranstaltungen sogar eine ganz eigene physische Datenbank bekommen.
|
||||
|
||||
---
|
||||
|
||||
## 2. Wie wird bestimmt, welche Datenbank benutzt wird?
|
||||
## 2) Was bedeutet das fürs Datenbank‑Schema?
|
||||
|
||||
Siehe Architektur‑Entscheidung (ADR‑0021):
|
||||
- Pro Veranstaltung existiert ein eigenes Schema mit denselben Tabellen (z. B. `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`, …).
|
||||
- Es gibt KEINE `tenant_id`‑Spalte in jeder Tabelle. Die Trennung passiert über das eigene Schema.
|
||||
- Eine zentrale Registry im `control`‑Schema verwaltet alle Veranstaltungen/Tenants, z. B. Tabelle `control.tenants(event_id, schema_name, db_url, status, version, created_at)`.
|
||||
- Migrationen (Flyway) laufen je Schema. Jedes Schema hat eine eigene `flyway_schema_history`.
|
||||
|
||||
- Datei: `docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md`
|
||||
- Kerngedanke: Die App leitet aus dem aktuellen „Arbeitskontext“ (gewählte Veranstaltung) den Tenant ab. Alle Lese/Schreib‑Operationen gehen automatisch in die richtige Event‑Datenbank.
|
||||
Vorteile:
|
||||
- Geringeres Risiko von Datenleckagen.
|
||||
- Leichtere, DSGVO‑konforme Löschung: Ein Schema lässt sich vollständig entfernen/archivieren.
|
||||
- Unabhängige Migration und Versionierung je Veranstaltung möglich.
|
||||
|
||||
---
|
||||
|
||||
## 3. Auswirkungen im Überblick
|
||||
## 3) Auswirkungen auf die API (Backend)
|
||||
|
||||
### a) Datenbank‑Schema (Backend)
|
||||
- Jeder Request muss wissen, „in welchem Veranstaltungs‑Ordner“ er arbeiten soll.
|
||||
- Primär über den HTTP‑Header `X-Event-Id: <event_slug>` (kanonisch). Alternativ kann die Subdomain/Host dies ausdrücken, z. B. `<event>.meldestelle.local`.
|
||||
- Das Backend prüft `X-Event-Id` gegen die Registry (`control.tenants`). Nur aktive Veranstaltungen sind beschreibbar; archivierte sind schreibgeschützt.
|
||||
- Autorisierung: Tokens enthalten erlaubte `events` (Scopes). Der Zugriff auf eine Veranstaltung wird gegen diese Liste geprüft.
|
||||
- Admin/Synchronisations‑Endpunkte dürfen ausnahmsweise einen expliziten `eventId`‑Pfadparameter verwenden (Fallback).
|
||||
|
||||
- Pro Veranstaltung ein eigenes Schema/Datei (z. B. `event-{eventId}.db`).
|
||||
- Tabellen wiederholen sich je Veranstaltung (z. B. `turniere`, `bewerbe`, `abteilungen`, `startlisten`, `kassa_belege`).
|
||||
- Keine Vermischung zwischen Veranstaltungen. Für Auswertungen über mehrere Veranstaltungen braucht es einen Aggregations‑Prozess.
|
||||
Fehlerbilder (vereinheitlicht):
|
||||
- Unbekannte Veranstaltung → `404 Unknown event`.
|
||||
- Veranstaltung gesperrt/archiviert → `423 Locked` (oder 403 je Endpoint‑Policy).
|
||||
|
||||
### b) API‑Design
|
||||
|
||||
- Jeder Request enthält implizit oder explizit den Event‑Kontext (Header, Pfad oder Session‑Scope).
|
||||
- Schreib‑Operationen validieren, dass die Ziel‑IDs (Turnier, Bewerb, Abteilung) zur aktuellen Veranstaltung gehören.
|
||||
- Export/Import: Datenpakete sind pro Veranstaltung abgegrenzt (leichte Weitergabe an Verband oder andere Systeme).
|
||||
|
||||
### c) Frontend (Navigation & State)
|
||||
|
||||
- Beim Eintritt in eine Veranstaltung wird der Tenant gesetzt; alle folgenden Screens arbeiten innerhalb dieses Kontexts.
|
||||
- Wechsel der Veranstaltung leert relevante Caches und setzt den Back‑Stack definiertermaßen zurück (→ Navigation V2).
|
||||
- Multi‑Turnier‑Fälle innerhalb EINER Veranstaltung bleiben möglich (Turnierkassa je Turnier, Konsolidierung in Veranstaltungs‑Kassa).
|
||||
Praktische Hinweise für API‑Clients:
|
||||
- Immer `X-Event-Id` mitsenden, sobald es fachlich um eine konkrete Veranstaltung geht.
|
||||
- Admin‑Operation „Veranstaltung anlegen“ erzeugt Schema + Registry‑Eintrag. Erst danach sind Fach‑Endpunkte nutzbar.
|
||||
|
||||
---
|
||||
|
||||
## 4. Grenzen & Trade‑offs
|
||||
## 4) Auswirkungen auf das Frontend (Navigation V3, Offline‑First)
|
||||
|
||||
- V3 Routen führen den Kontext über IDs (z. B. `eventId`, `tournamentId`, …). Diese IDs bestimmen implizit den aktiven Tenant.
|
||||
- Beim Öffnen eines Deep‑Links inkl. `eventId` setzt der Client den `X-Event-Id`‑Header automatisch für Backend‑Aufrufe.
|
||||
- Wechsel der Veranstaltung im UI entspricht einem Tenant‑Wechsel. Daraus folgen klare Regeln:
|
||||
- Der aktuelle Navigations‑Stack (V3) wird auf die Root der neu gewählten Veranstaltung zurückgesetzt (kein Cross‑Event‑State).
|
||||
- Datenansichten, Caches und ViewModel‑States sind pro Veranstaltung getrennt zu halten.
|
||||
- Kassen‑Sichten: „Veranstaltungs‑Kassa“ aggregiert nur über Turniere derselben Veranstaltung (nie übergreifend).
|
||||
|
||||
Offline‑First:
|
||||
- Lokal wird je Veranstaltung eine eigene Datenbasis geführt (analog zur Backend‑Trennung). Ein Sync arbeitet immer bezogen auf den aktuellen Event‑Kontext.
|
||||
|
||||
UX‑Hinweise:
|
||||
- In Breadcrumbs/TopBar ist die aktive Veranstaltung sichtbar und schnell wechselbar.
|
||||
- Bei ungültigem Kontext (z. B. `eventId` existiert nicht mehr) zeigt die App einen Hinweis und bietet einen Rücksprung zur Veranstaltungs‑Auswahl an.
|
||||
|
||||
---
|
||||
|
||||
## 5) Entwickler‑Leitfaden (kurz)
|
||||
|
||||
- Backend
|
||||
- In Gateways/Clients stets `X-Event-Id` setzen, sobald ein Event‑Kontext vorhanden ist.
|
||||
- Keine gemeinsamen Queries über mehrere Veranstaltungen im selben Request.
|
||||
- Flyway‑Migrationsskripte tenant‑sicher halten (keine absoluten Schema‑Namen in DDL, sofern sie dynamisch sein müssen).
|
||||
|
||||
- Frontend
|
||||
- Routen enthalten die relevanten IDs; keine globalen, veranstaltungsübergreifenden Stores für Event‑Daten.
|
||||
- Beim Event‑Wechsel alle abhängigen ViewModels/Stores invalidieren bzw. neu initialisieren.
|
||||
- Deep‑Links enthalten `eventId`; beim Öffnen wird der Navigationspfad synthetisch aufgebaut (siehe V3‑Dokument).
|
||||
|
||||
---
|
||||
|
||||
## 6) Grenzen & Trade‑offs
|
||||
|
||||
- Cross‑Event‑Suche/Auswertung erfordert separate Aggregation (bewusste Entscheidung zugunsten Offline‑First und Sicherheit).
|
||||
- Datenmigration (z. B. Zusammenlegen/Teilen von Veranstaltungen) braucht Tools/Assistenten.
|
||||
|
||||
---
|
||||
|
||||
## 5. Beziehung zur Domäne
|
||||
## 7) Beziehung zur Domäne
|
||||
|
||||
- Ubiquitous Language: `Veranstaltung` ist die Root. Kassen und TeilnehmerKonten sind auf Event‑Ebene verankert.
|
||||
- Zahlvorgänge können mehrere Rechnungen/Belege aus verschiedenen Turnieren derselben Veranstaltung ausgleichen.
|
||||
|
||||
---
|
||||
|
||||
## 8) Querverweise
|
||||
|
||||
- Technische Details/Begründung: `docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md`
|
||||
- Navigation V3 Regeln: `docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md`
|
||||
- Event‑First‑Workflow: `docs/02_Guides/Event-First-Workflow.md`
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
- [x] Ablauf: Veranstaltung anlegen → Turnier anlegen → Bewerbe anlegen → Abteilungen → Startliste
|
||||
- [x] Dokument in `docs/01_Architecture/` oder `docs/02_Guides/` ablegen → `docs/02_Guides/Event-First-Workflow.md`
|
||||
|
||||
- [x] **A-3** | Navigation-V2 dokumentieren
|
||||
- [x] **A-3** | Navigation-V3 dokumentieren
|
||||
- [x] Aktuellen Screen-Baum und Back-Stack-Verhalten beschreiben
|
||||
- [x] Dokument in `docs/06_Frontend/` ablegen → `docs/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md`
|
||||
- [x] Dokument in `docs/06_Frontend/` ablegen → `docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md`
|
||||
|
||||
- [x] **A-4** | Tenant-Konzept dokumentieren (nach ADR-0021 vom Architect)
|
||||
- [x] ADR-0021 in `docs/01_Architecture/ADRs/` verlinken → `docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md`
|
||||
|
|
|
|||
|
|
@ -24,19 +24,34 @@
|
|||
- frontend/features/veranstalter-feature/src/jvmMain/.../VeranstalterAuswahlScreen.kt (nutzt ViewModel/Intents)
|
||||
|
||||
- [x] **A-2** | Abteilungs-Logik im Bewerb-Dialog berücksichtigen
|
||||
- [x] Beim Anlegen eines Bewerbs: Abteilungs-Auswahl als Teil des Dialogs
|
||||
- [x] CSN-C-NEU: Automatischer Vorschlag der Pflicht-Teilung (ohne/mit Lizenz; R1/R2+)
|
||||
- [x] Abteilungs-Typ setzen: `SEPARATE_SIEGEREHRUNG` oder `ORGANISATORISCH`
|
||||
- [x] Dialog enthält Abteilungs-Auswahl als Teil des „Bewerb anlegen“-Flows (im selben Modal)
|
||||
- [x] CSN-C-NEU: Automatischer Vorschlag der Pflicht-Teilung mit 4 Abteilungen:
|
||||
- [x] Ohne Lizenz · R1
|
||||
- [x] Ohne Lizenz · R2+
|
||||
- [x] Mit Lizenz · R1
|
||||
- [x] Mit Lizenz · R2+
|
||||
- [x] Beim Auto-Vorschlag Default-Setzung des Abteilungs-Typs auf `SEPARATE_SIEGEREHRUNG`
|
||||
- [x] Manuelle Umschaltung des Abteilungs-Typs möglich: `SEPARATE_SIEGEREHRUNG` oder `ORGANISATORISCH`
|
||||
- [x] UX: Bei erkanntem Typ „CSN-C-NEU“ wird ein AssistChip „Pflicht-Teilung vorgeschlagen“ angezeigt
|
||||
|
||||
Referenzen:
|
||||
- frontend/features/turnier-feature/src/commonMain/.../BewerbAnlegenViewModel.kt (State, Intents, Auto-Vorschlag)
|
||||
- frontend/features/turnier-feature/src/jvmMain/.../TurnierBewerbeTab.kt (Button „Bewerb Einfügen“ öffnet Dialog)
|
||||
Akzeptanzkriterien:
|
||||
- [x] Der „Bewerb anlegen“-Dialog zeigt ein Eingabefeld „Bewerbs-Typ“ und eine Auswahl für den Abteilungs-Typ (zwei Chips)
|
||||
- [x] Bei Eingabe „CSN-C-NEU“ wird automatisch die oben definierte 4er-Teilung in der Abteilungs-Liste angezeigt
|
||||
- [x] Die Auto-Teilung kann angezeigt werden, ohne dass der Dialog neu geöffnet werden muss (Live-Reaktion auf Eingabe)
|
||||
- [x] Der gesetzte Abteilungs-Typ ist im State sichtbar und wird vom Dialog korrekt reflektiert
|
||||
- [x] Kein Vorschlag für andere Typen; Liste bleibt leer bis manuell hinzugefügt/implementiert (aktuell out-of-scope)
|
||||
|
||||
Referenzen (konkret):
|
||||
- frontend/features/turnier-feature/src/commonMain/kotlin/at/mocode/turnier/feature/presentation/BewerbAnlegenViewModel.kt
|
||||
- `BewerbAnlegenState`, `BewerbAnlegenIntent`, `applySuggestion()` (Auto-Vorschlag + Default-AbteilungsTyp)
|
||||
- frontend/features/turnier-feature/src/jvmMain/kotlin/at/mocode/turnier/feature/presentation/TurnierBewerbeTab.kt
|
||||
- `BewerbAnlegenDialog(...)`: Eingabe „Bewerbs-Typ“, AssistChip, Auswahl Abteilungs-Typ, Anzeige der vorgeschlagenen Abteilungen
|
||||
|
||||
---
|
||||
|
||||
## 🟠 Sprint B — Kurzfristig (nächste Woche)
|
||||
|
||||
- [ ] **B-1** | ViewModels für alle V2-Screens umsetzen
|
||||
- [ ] **B-1** | ViewModels für alle V3-Screens umsetzen
|
||||
- [ ] `TurnierViewModel`
|
||||
- [ ] `BewerbViewModel` (inkl. Abteilungs-Logik)
|
||||
- [ ] `PferdProfilViewModel`
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
---
|
||||
type: Redirect
|
||||
status: MOVED
|
||||
type: Frontend
|
||||
status: DEPRECATED
|
||||
owner: 🧹 Curator
|
||||
last_update: 2026-04-02
|
||||
moved_to: docs/_archive/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md
|
||||
replaced_by: docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md
|
||||
archive_copy: docs/_archive/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md
|
||||
---
|
||||
|
||||
# Navigation V2 — verschoben ins Archiv
|
||||
# Navigation V2 — DEPRECATED
|
||||
|
||||
Dieses Dokument wurde in das Archiv verschoben und durch „V3“ ersetzt.
|
||||
Diese Datei ist veraltet. Wir haben uns auf Navigation V3 geeinigt. Bitte verwende ab sofort die aktuelle Fassung:
|
||||
|
||||
- Archiv: `docs/_archive/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md`
|
||||
- Aktuelle Version: `docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md`
|
||||
- Aktuelle Version (SSoT): docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md
|
||||
- Archivkopie dieser Datei: docs/_archive/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md
|
||||
|
||||
Hinweis:
|
||||
- Die V3‑Doku spiegelt den jetzt gültigen, startfähigen Stand der Desktop‑App wider (kein erzwungener Login/Ping im MVP, Tab‑Stacks, Drilldown Veranstaltung → Turnier → Bewerb → Abteilung).
|
||||
- Falls du ältere Verweise auf diese Datei findest, bitte auf die V3‑Doku aktualisieren.
|
||||
|
|
|
|||
|
|
@ -123,3 +123,4 @@ Quellen: `frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/deskt
|
|||
- Event‑First‑Workflow: `docs/02_Guides/Event-First-Workflow.md`
|
||||
- Begriffe: `docs/03_Domain/01_Glossary/Ubiquitous_Language.md`
|
||||
- Analyse/Begründung: `docs/06_Frontend/Reports/2026-04-02_Navigation_Versionierung_Analyse_V2_vs_V3.md`
|
||||
- Tenant‑Konzept (eine Veranstaltung = ein Tenant): `docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md`
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user