diff --git a/docs/04_Agents/Roadmaps/Curator_Roadmap.md b/docs/04_Agents/Roadmaps/Curator_Roadmap.md index 17dc8a0a..70c8f409 100644 --- a/docs/04_Agents/Roadmaps/Curator_Roadmap.md +++ b/docs/04_Agents/Roadmaps/Curator_Roadmap.md @@ -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 V1–V009) - - [ ] 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 V1–V009) → `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 diff --git a/docs/05_Backend/API/API_Uebersicht_Stammdaten.md b/docs/05_Backend/API/API_Uebersicht_Stammdaten.md new file mode 100644 index 00000000..48a478a1 --- /dev/null +++ b/docs/05_Backend/API/API_Uebersicht_Stammdaten.md @@ -0,0 +1,63 @@ +--- +type: Reference +status: ACTIVE +owner: Backend Developer +last_update: 2026-04-03 +--- + +# API-Übersicht Stammdaten + +Abdeckung: Backend Sprint B‑1 (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 tenant‑spezifisch. Für domain‑spezifische Vorgänge (Entries, Kassa) gilt ADR‑0021/`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) diff --git a/docs/05_Backend/API/Kassa_API.md b/docs/05_Backend/API/Kassa_API.md new file mode 100644 index 00000000..c577fb6e --- /dev/null +++ b/docs/05_Backend/API/Kassa_API.md @@ -0,0 +1,37 @@ +--- +type: Reference +status: DRAFT +owner: Backend Developer +last_update: 2026-04-03 +--- + +# Kassa-API (Entwurf) + +Abhängigkeit: Backend Sprint B‑2 (Kassa-Service) — laut Curator‑Roadmap 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` (ADR‑0021). Alle Kassa‑Operationen sind tenant‑lokal. + +## 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 Kassa‑Buchungen/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 + Saldo‑Update innerhalb einer DB‑Transaktion. +- Negativsaldo optional durch Feature‑Flag blockierbar. +- Audit‑Trail pro Vorgang (who/when), Idempotenz‑Key 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 B‑2. Dieses Dokument wird dann auf `status: ACTIVE` gesetzt. diff --git a/docs/05_Backend/Multi_Tenant_Kurz.md b/docs/05_Backend/Multi_Tenant_Kurz.md new file mode 100644 index 00000000..0c4a6455 --- /dev/null +++ b/docs/05_Backend/Multi_Tenant_Kurz.md @@ -0,0 +1,28 @@ +--- +type: Reference +status: ACTIVE +owner: Lead Architect +last_update: 2026-04-03 +--- + +# Tenant-Isolation & Multi‑Tenant (Kurzfassung) + +Vollständige Entscheidung: [ADR‑0021: Tenant‑Resolution‑Strategie (Schema‑per‑Tenant)](../01_Architecture/adr/0021-tenant-resolution-strategy-de.md). + +## Kernaussagen + +- Eine Veranstaltung = ein Tenant = ein Datenbankschema (Schema‑per‑Tenant). +- Requests tragen `X-Event-Id`; Backend validiert gegen `control.tenants` und schaltet das Schema je Request. +- Flyway führt Migrationen je Tenant‑Schema aus (eigene `flyway_schema_history`). +- Stammdaten (Reiter/Pferde/Vereine/Funktionäre) sind global und nicht tenant‑spezifisch; Entries/Kassa sind tenant‑lokal. + +## Umsetzung (Kurz) + +- Web‑Layer: `TenantWebFilter` (Spring) bzw. Plugin (Ktor) liest `X-Event-Id` und legt `TenantContext` ab. +- Persistence: SCHEMA‑Multitenancy (`SET search_path`) oder Hibernate‑`MultiTenantConnectionProvider`. +- Registry: `control.tenants(event_id, schema_name, status, db_url?, version, created_at)`. + +## Betroffene Bereiche + +- Datenmodell tenant‑lokal: `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`, `teilnehmer_konten`, `turnier_kassa` (siehe [Datenbankschema](./Schema/Database_Schema_V1-V009.md)). +- Services: Der Entries‑Service arbeitet mandantenfähig; andere Services bleiben Single‑Tenant/global (vgl. Backend‑Roadmap). diff --git a/docs/05_Backend/README.md b/docs/05_Backend/README.md index d6ff22de..2b2e7cff 100644 --- a/docs/05_Backend/README.md +++ b/docs/05_Backend/README.md @@ -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 B‑1 abgeschlossen). +* **[Datenbankschema V1–V009](./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 B‑2 Kassa fertig ist. +* **[Tenant-Isolation & Multi‑Tenant kurz](./Multi_Tenant_Kurz.md):** Zusammenfassung gem. ADR‑0021. diff --git a/docs/05_Backend/Schema/Database_Schema_V1-V009.md b/docs/05_Backend/Schema/Database_Schema_V1-V009.md new file mode 100644 index 00000000..f9b5cb5c --- /dev/null +++ b/docs/05_Backend/Schema/Database_Schema_V1-V009.md @@ -0,0 +1,130 @@ +--- +type: Reference +status: ACTIVE +owner: Backend Developer +last_update: 2026-04-03 +--- + +# Datenbankschema V1–V009 (Tenant‑Schema) + +Quelle: Flyway‑Migrationen im Entries‑Service (`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 (ADR‑0021). Alle untenstehenden Tabellen werden pro Tenant‑Schema angelegt und sind somit mandantengetrennt. + +## Tabellenübersicht + +- `veranstaltungen` — Eine Veranstaltung (Singleton im Tenant‑Schema) +- `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` — Kassa‑Saldo 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 V1–V009 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 Kassa‑Eintrag)