diff --git a/docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md b/docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md index 6d05256f..124e497e 100644 --- a/docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md +++ b/docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md @@ -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: ` (kanonisch). Alternativ kann die Subdomain/Host dies ausdrücken, z. B. `.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` diff --git a/docs/04_Agents/Roadmaps/Curator_Roadmap.md b/docs/04_Agents/Roadmaps/Curator_Roadmap.md index 9b34440a..004d7bb2 100644 --- a/docs/04_Agents/Roadmaps/Curator_Roadmap.md +++ b/docs/04_Agents/Roadmaps/Curator_Roadmap.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` diff --git a/docs/04_Agents/Roadmaps/Frontend_Roadmap.md b/docs/04_Agents/Roadmaps/Frontend_Roadmap.md index 6bd49e45..03e748f8 100644 --- a/docs/04_Agents/Roadmaps/Frontend_Roadmap.md +++ b/docs/04_Agents/Roadmaps/Frontend_Roadmap.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` - - 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) + - [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 + + 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` diff --git a/docs/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md b/docs/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md index d18c6cf0..e29af0ef 100644 --- a/docs/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md +++ b/docs/06_Frontend/Navigation_V2_Screen-Baum_und_Back-Stack.md @@ -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. diff --git a/docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md b/docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md index 76d6eb45..3424e4d5 100644 --- a/docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md +++ b/docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md @@ -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`