meldestelle/docs/01_Architecture/Reference/Tenant-Konzept_Eine-Veranstaltung-eine-Datenbank.md
StefanMoCoAt 85282ea7b4
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
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.
2026-04-02 23:17:07 +02:00

6.0 KiB
Raw Blame History

type status owner last_update sources
Architecture Reference ACTIVE 🧹 Curator & 🏗️ Lead Architect 2026-04-02
docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md
docs/02_Guides/Event-First-Workflow.md
docs/06_Frontend/Navigation_V3_Screen-Baum_und_Back-Stack.md

TenantKonzept — Eine Veranstaltung = eine Datenbank (ein Tenant)

Dieses Dokument erklärt in einfacher Sprache, wie wir Daten pro Veranstaltung trennen. Grundlage ist ADR0021 (SchemaperTenant). Kurz gesagt: Für jede Veranstaltung gibt es eine eigene „DatenbankSchublade“. Nichts aus Veranstaltung A landet versehentlich in Veranstaltung B.

Weitere Details in der technischen Entscheidung:

  • ADR0021: docs/01_Architecture/adr/0021-tenant-resolution-strategy-de.md

1) Idee in Alltagssprache

  • 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: „SchemaperTenant“. 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) Was bedeutet das fürs DatenbankSchema?

  • Pro Veranstaltung existiert ein eigenes Schema mit denselben Tabellen (z. B. veranstaltungen, turniere, bewerbe, abteilungen, …).
  • Es gibt KEINE tenant_idSpalte in jeder Tabelle. Die Trennung passiert über das eigene Schema.
  • Eine zentrale Registry im controlSchema 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.

Vorteile:

  • Geringeres Risiko von Datenleckagen.
  • Leichtere, DSGVOkonforme Löschung: Ein Schema lässt sich vollständig entfernen/archivieren.
  • Unabhängige Migration und Versionierung je Veranstaltung möglich.

3) Auswirkungen auf die API (Backend)

  • Jeder Request muss wissen, „in welchem VeranstaltungsOrdner“ er arbeiten soll.
  • Primär über den HTTPHeader 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/SynchronisationsEndpunkte dürfen ausnahmsweise einen expliziten eventIdPfadparameter verwenden (Fallback).

Fehlerbilder (vereinheitlicht):

  • Unbekannte Veranstaltung → 404 Unknown event.
  • Veranstaltung gesperrt/archiviert → 423 Locked (oder 403 je EndpointPolicy).

Praktische Hinweise für APIClients:

  • Immer X-Event-Id mitsenden, sobald es fachlich um eine konkrete Veranstaltung geht.
  • AdminOperation „Veranstaltung anlegen“ erzeugt Schema + RegistryEintrag. Erst danach sind FachEndpunkte nutzbar.

4) Auswirkungen auf das Frontend (Navigation V3, OfflineFirst)

  • V3 Routen führen den Kontext über IDs (z. B. eventId, tournamentId, …). Diese IDs bestimmen implizit den aktiven Tenant.
  • Beim Öffnen eines DeepLinks inkl. eventId setzt der Client den X-Event-IdHeader automatisch für BackendAufrufe.
  • Wechsel der Veranstaltung im UI entspricht einem TenantWechsel. Daraus folgen klare Regeln:
    • Der aktuelle NavigationsStack (V3) wird auf die Root der neu gewählten Veranstaltung zurückgesetzt (kein CrossEventState).
    • Datenansichten, Caches und ViewModelStates sind pro Veranstaltung getrennt zu halten.
    • KassenSichten: „VeranstaltungsKassa“ aggregiert nur über Turniere derselben Veranstaltung (nie übergreifend).

OfflineFirst:

  • Lokal wird je Veranstaltung eine eigene Datenbasis geführt (analog zur BackendTrennung). Ein Sync arbeitet immer bezogen auf den aktuellen EventKontext.

UXHinweise:

  • 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 VeranstaltungsAuswahl an.

5) EntwicklerLeitfaden (kurz)

  • Backend

    • In Gateways/Clients stets X-Event-Id setzen, sobald ein EventKontext vorhanden ist.
    • Keine gemeinsamen Queries über mehrere Veranstaltungen im selben Request.
    • FlywayMigrationsskripte tenantsicher halten (keine absoluten SchemaNamen in DDL, sofern sie dynamisch sein müssen).
  • Frontend

    • Routen enthalten die relevanten IDs; keine globalen, veranstaltungsübergreifenden Stores für EventDaten.
    • Beim EventWechsel alle abhängigen ViewModels/Stores invalidieren bzw. neu initialisieren.
    • DeepLinks enthalten eventId; beim Öffnen wird der Navigationspfad synthetisch aufgebaut (siehe V3Dokument).

6) Grenzen & Tradeoffs

  • CrossEventSuche/Auswertung erfordert separate Aggregation (bewusste Entscheidung zugunsten OfflineFirst und Sicherheit).
  • Datenmigration (z. B. Zusammenlegen/Teilen von Veranstaltungen) braucht Tools/Assistenten.

7) Beziehung zur Domäne

  • Ubiquitous Language: Veranstaltung ist die Root. Kassen und TeilnehmerKonten sind auf EventEbene 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
  • EventFirstWorkflow: docs/02_Guides/Event-First-Workflow.md