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.
This commit is contained in:
Stefan Mogeritsch 2026-04-03 22:59:41 +02:00
parent 6e484ee9a1
commit dbe7c74a9c
6 changed files with 269 additions and 5 deletions

View File

@ -42,11 +42,11 @@
- [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

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)