- Enhanced the ACCESS_LAYER_AND_GOVERNANCE_PLAN.md with new specifications for capability documentation and community features. - Added references to new documents detailing capability IDs and club membership features. - Updated MULTI_TENANCY_RBAC_ARCHITECTURE.md to include links to the new specifications. - Marked certain features as deprecated in backend/auth.py, indicating migration paths for club feature access. - Incremented DB_SCHEMA_VERSION to 20260606078 in version.py to reflect recent changes.
15 KiB
Multi-Tenancy, Vereins-Membership und Rollenmodell – Zielarchitektur & Umsetzungsplan
Status: verbindliche Zielrichtung (Architekturpapier)
Stand: 2026-05-06
Bezug: functional/shinkan_anforderungsdokument_entwurf.md §5, §17–18 · functional/DOMAIN_MODEL.md (Sichtbarkeit §5.5) · functional/TRAINING_CURRICULUM_AND_GOVERNANCE_CONCEPT.md (CURR-004–008)
Operative Reihenfolge & einheitliche Zugriffsschicht: ACCESS_LAYER_AND_GOVERNANCE_PLAN.md – dort sind Stufen A–F, Drift-Prävention und die Zurückstellung von Vereinsabo/Limits festgehalten; dieses Dokument bleibt das übergeordnete Zielbild.
1. Zweck
Dieses Dokument fasst den Soll-Zustand für Mandantenfähigkeit (Verein = Mandant), rollenbasierte Zugriffskontrolle auf Vereinsebene und ein Membership-/Limitsystem zusammen – und definiert einen phasenweisen Umsetzungsplan, der mit dem bestehenden Governance-Kern (visibility, club_id, created_by) konsistent bleibt.
2. Abgleich mit vorhandener Dokumentation
| Quelle | Inhalt relevant für Tenancy/Rollen | Konsistenz mit Zielbild |
|---|---|---|
shinkan_anforderungsdokument_entwurf.md §5.4 |
Rollen: Superadmin, Vereinsadmin, Trainer, Co-Trainer, Redakteur | Deckt sich; „Superadmin“ entspricht fachlich Systemadmin |
| §17.1 | Erweiterung: Systemadmin, Spartenadmin | Entspricht den gewünschten Spartenverantwortlichen |
| §5.5 / §17 | Sichtbarkeit: privat, Verein, Sparte, global, offiziell | DOMAIN_MODEL listet ähnliche Stufen; Bibliothek private | club | official technisch über Zugriffsschicht durchgesetzt; Sparte/community folgt |
| §18.5 | MVP: Datenmodell mandantenfähig, Rechte zunächst einfach | Bestätigt schrittweise Verschärfung |
DOMAIN_MODEL.md §5.5 |
Freigabeebenen inkl. Sparte | Zielbild; DB/API nutzen derzeit überwiegend private | club | official |
TRAINING_CURRICULUM_AND_GOVERNANCE_CONCEPT.md |
CURR-004–008: Governance-Kern, spätere Policy | Datenfelder vorbereitet; Policy/Erzwingung folgt |
working/SHINKAN_PROJECT_SETUP.md §6 |
„Multi-Tenant-Administration“ ausgeschlossen (MVP-Liste) | Historisch; technische Mandanten sind dennoch Ziel – UI-Komplexität kontrolliert einführen |
Fazit: Die fachlichen Rollen und Sichtbarkeitsebenen sind in den funktionalen Docs skizziert. Für die Kernteile Bibliothek und Vereinskontext ist eine technische Zugriffsschicht (TenantContext, club_members, einheitliche Sichtbarkeits-SQL/-Prüfungen) umgesetzt — Details und Restarbeit (Sparte, Konsolidierung der Hilfen, Planungs-/Admin-Flows) siehe §3 und ACCESS_LAYER_AND_GOVERNANCE_PLAN.md.
3. Ist-Stand im Code (Gap-Analyse)
Hinweis: Die Unterabschnitte 3.1–3.6 enthalten weiterhin historische Problemstellungen (Ausgangsbild). Ergänzend beschreibt 3.0 den aktualisierten Umsetzungsstand nach Mitgliedschafts-, Tenant- und Bibliotheksarbeit. Verbindliche offene Arbeit und Reihenfolge:
ACCESS_LAYER_AND_GOVERNANCE_PLAN.md.
3.0 Aktualisierung des Umsetzungsstands (kurz)
- Mitgliedschaft: Tabellen
club_membersundclub_member_roles; aktiver Verein über Profilfeld und HeaderX-Active-Club-Id; Auflösung inTenantContext(tenant_context.py). - Bibliothek (Übungen, Trainingsplan-Vorlagen, Rahmenprogramme u. a.): gemeinsame Leselogik
library_content_visibility_sql/library_content_visible_to_profile— Vereinsinhalteclubnur bei passendemclub_idund aktiver Mitgliedschaft im Objekt-Verein (normale Nutzer ohne gültigen Vereinskontext: kein „beliebiges club“). GET /api/clubs: Nicht-Admins sehen nur Vereine mit Mitgliedschaft;POST /api/clubs: nur Plattform-Admin, mit Pflichtprimary_admin_profile_id.- Organisation (Sparten/Gruppen): Schreibzugriff über
can_manage_club_org/can_plan_in_clubauf Basis vonclub_member_roles(nicht mehr nur globalesadmin). - Profil-API: eingeschränktes
GET /profiles/{id},DELETE,POST /profiles(Plattform-Admin / Selbstzugriff) — Detailsbackend/routers/profiles.py. - Tests: pytest inkl. optionaler Mandanten-Integration (
ACCESS_LAYER_INTEGRATION); CI-Anbindung siehe.gitea/workflows/test.yml(Ausführung im Backend-Container wie Schwesterprojekt).
3.1 Identität und Rollen
profiles.roleist eine globale Kennzeichnung (admin,superadmin,trainer,user, …).- (Historisch) Fehlende Abbildung von Vereinsrollen ohne eigene Tabellen.
- Ist: Zusätzlich
club_member_rolespro Verein (z. B.club_admin,trainer, …); Sessions liefern weiterprofile_id+ globalerole(auth.py→get_session), Vereinsrechte werden aus Mitgliedschaft abgeleitet.
Konsequenz: Globale Rolle und Vereinsrollen koexistieren; Produkt und Code sollten langfristig klar trennen, was nur global vs. nur über Mitgliedschaft gilt (vgl. Zielarchitektur §4).
3.2 Organisation & APIs
- (Historisch) Zu offene Vereinsliste und Club-Anlage für jeden Trainer/User.
- Ist: siehe 3.0 — gefilterte Liste, eingeschränktes Anlegen, kontextbezogene Organisationsrechte.
Konsequenz: Offene Punkte verlagern sich in feine Produktregeln und Sparten-/Community-Stufen (ACCESS_LAYER Stufe D bzw. spätere Epics).
3.3 Trainingsplanung
- Zugriff auf Einheiten weiterhin stark gruppenbezogen (
training_groups, optionallead_trainer_profile_idauf Einheiten). - Mitgliedschaft/
TenantContextunterstützen andere Endpoints;GET /training-unitshat keinen impliziten Filter nur aufeffective_club_id(Multi-Verein-Kalender; bei Bedarf Queryclub_id).
Konsequenz: Vereinsweite oder „Administrations“-Planungsaufgaben können weiter ausgebaut werden (eigenes Produkt-Thema; nicht identisch mit Bibliotheks-Governance).
3.4 Governance / Sichtbarkeit (Bibliothek)
- (Historisch) Risiko:
club-Objekte ohne Bindung anclub_id/ Mitgliedschaft → mögliche Cross-Tenant-Sicht. - Ist: Listen und Detail für die genannten Bibliotheksmodule nutzen die einheitliche Logik in
club_tenancy/tenant_context(siehe 3.0).
Konsequenz: Die historische „Leak“-Diagnose für Übungen und Rahmenprogramme in dieser Form ist überholt. Verbleibend: Konsolidierung auf wenige Hilfsfunktionen (ACCESS_LAYER Stufe C), Sparte als eigene Stufe, ggf. community.
3.5 Frontend
GET /api/profiles/meliefert u. a.clubs[],active_club_id; Client setztX-Active-Club-Id. Geschützte Backend-Routen nutzenDepends(get_tenant_context)wo im Audit festgehalten.
3.6 Membership (kommerziell/limits)
- Mitai-artige Tabellen (
tiers,subscriptions,tier_limits, …) sind nutzerbezogen, nicht vereinsbezogen. - Kein konzipiertes
club_subscription/club_planim Schema — bewusst nach ACCESS_LAYER-Plan zurückgestellt.
Letzte Überarbeitung dieses Abschnitts (3.x): 2026-05-06.
4. Zielarchitektur
4.1 Begriffe
| Begriff | Definition |
|---|---|
| Mandant | Immer ein Verein (clubs.id). |
| Systemadmin | Global (profiles.role oder dediziertes Flag); darf Plattform-weite Objekte und Vereinslifecycle (Anlegen, Zuweisen Hauptverwalter). |
| Vereinskontext | Pro Session gewählter aktiver Verein (active_club_id), wenn der User Mitglied ist. |
| Vereinsmitgliedschaft | Zeile in einer Junction: User ↔ Verein ↔ eine oder mehrere Rollen. |
| Effektive Berechtigung | Funktion aus: globale Rolle, Mitgliedschaft im aktiven Verein, optional Sparte/Gruppe, Sichtbarkeit des Objekts. |
4.2 Rollenmodell (Schichten)
Schicht A – Plattform (global, kleine Menge)
system_admin/superadmin(bestehende Semantik konsolidieren und benennen).
Schicht B – Verein (pro Mitgliedschaft, mehrere Rollen möglich)
club_admin– Hauptverwalter:in (ein Verein genau eine „primäre“ Admin-Zuweisung empfohlen, siehe 4.4).division_lead– Spartenverantwortliche:r (Scope:division_idoptional an Mitgliedschaft gebunden).trainer– Trainer/Übungsleitung (Abgrenzung zu Co-Trainer siehe Gruppe).content_editor– Redakteur:in / Inhaltsverantwortliche:r (fachlich wie Anforderungsdoc).
Schicht C – Abgeleitet aus Trainingsgruppe (bereits teilweise vorhanden)
- Haupttrainer / Co-Trainer über
training_groups.trainer_idundco_trainer_ids(und ggf.lead_trainer_profile_idauf Einheit).
Mapping Alt → Neu: Bestehendes profiles.role kann Übergangsweise als „Default-Rolle für Pilotverein“ dienen, soll aber mittelfristig nicht die einzige Quelle für Vereinsrechte sein.
4.3 Mitgliedschaft und aktiver Verein
-
Neue Kernstruktur (konzeptionell):
club_members(profile_id,club_id,status,created_at, …)
club_member_roles(club_member_id,role_code, optionaldivision_idfür spartenbezogene Rollen). -
Aktiver Verein:
- Persistenz: Nutzereinstellung (
profiles.default_club_idoder eigene Tabelleprofile_preferences). - Pro Request: Header
X-Active-Club-Idoder Query (einheitlich dokumentieren); Server validiert Mitgliedschaft.
- Persistenz: Nutzereinstellung (
-
Tenant-Switch UI: Bei Mitgliedschaft in >1 Verein Auswahl im Frontend; alle Listen/Aktionen verwenden aktiven Kontext.
4.4 Vereins-Lebenszyklus
- Neuer Verein: nur Systemadmin; Pflichtfelder: Name, initialer
club_admin(bestehendes Profil zuweisen oder Einladungsflow später). - Vereinsadmin verwaltet in „Mein Verein“: Sparten, Gruppen, Trainerzuordnungen, Einladungen (später), interne Sichtbarkeit – ohne andere Vereine zu sehen.
4.5 Daten- und Funktionssicht
| Datenklasse | Leseregel (Ziel) |
|---|---|
| Global offiziell | Alle authentifizierten (ggf. später thematisch eingeschränkt). |
Verein (visibility=club, club_id gesetzt) |
Nur Profile mit Mitgliedschaft in diesem club_id; optional zusätzlich Sparte, wenn division_id am Objekt gepflegt wird. |
| Privat | Nur created_by (und explizite Shares später). |
| Geplante Einheiten | Wie heute über Gruppe + Trainer/Co; zusätzlich Vereinskontext zur Navigation/Audit. |
Einheitlicher Governance-Kern bleibt wie in CURR-005; Ergänzung: division_id auf Bibliotheksobjekten, wenn „Sparte“ technisch durchgesetzt werden soll (DOMAIN_MODEL / §17).
4.6 Membership-System (Vereinsabo / Limits) – Konzept
Ziel: vereinszentrierte Vertrags- und Limitlogik, analog zur bestehenden Tier-Infrastuktur, aber an club_id gebunden.
Empfohlene Bausteine:
club_plans– Produktdefinition (Name, Features, implizite Limits).club_subscriptions– (club_id,plan_id, Status, Laufzeit).club_usage_countersoder Ableitung aus DB – z. B. aktive Nutzer, aktive Trainingsgruppen (periodisch oder on-write).- Enforcement-Schicht – zentrale Funktion
assert_club_limit(club_id, metric)vor/groups-POST, Einladungen, etc.
Offene Produktentscheidungen (vor Implementierung festlegen):
- Zählen „Nutzer“ alle Mitglieder oder nur aktive Trainer?
- Soft-Limits vs. Hard-Stops; Übergang für Pilotverein.
5. Umsetzungsplan (Phasen)
Phase 0 – Foundations (kurz, risikoarm)
- Begriffe und Enums in einem Ort dokumentieren (dieses Dokument + Eintrag in
DATABASE_SCHEMA.mdnach Migration). - Audit-Liste aller Router mit
club_id/visibility/ Listen-Endpunkten.
Phase 1 – Datenmodell Mitgliedschaft & Hauptverwalter
- Migration:
club_members,club_member_roles; optionalclubs.primary_admin_profile_id(oder Primär-Flag auf Mitgliedschaft). - Backfill: bestehende Trainer aus
training_groups→ minimale Mitgliedschafttrainerim jeweiligen Verein (Skript/Migration mit dokumentierter Annahme CURR-008). - Breaking/API: keine – nur erweiterte Datenbasis.
Phase 2 – Aktiver Vereinskontext & API-Kontrakte
- Backend: Validierung
X-Active-Club-Idgegen Mitgliedschaft; Hilfsfunktionget_effective_club_context(session, header). GET /api/clubsfür Nicht-Systemadmins: nur Vereine mit Mitgliedschaft.POST /api/clubs: nur Systemadmin; Vergabeclub_admin-Mitgliedschaft.- Frontend: Club-Switcher + Persistenz.
Phase 3 – Effektive Berechtigungen (RBAC)
- Mitgliederverwaltung per API (ohne UI):
GET/POST /api/clubs/{club_id}/members,GET/PUT/DELETE /api/clubs/{club_id}/members/{profile_id}— nur Plattform-Admin oderclub_adminim Zielverein (Stand Code 0.8.16). - Zentrale Modulfunktion z. B.
authorization/club_permissions.py:
can(club_id, profile_id, permission, division_id=None)— optional später; aktuellclub_tenancy.can_manage_club_org/has_club_role. - Router schrittweise umbinden: Sparten/Gruppen CRUD nach Rolle
club_adminim Kontext; Systemadmin unverändert Vollzugriff.
Phase 4 – Sichtbarkeit & Leaks schließen
- Übungen:
club-Sichtbarkeit nur bei Übereinstimmungexercise.club_idmit Mitgliedschaft (und späterdivision). - Trainingsplan-Vorlagen (
training_plan_templates) und Rahmenprogramme (training_framework_programs): gleiches Muster für Listen/GET (Stand 0.8.17); Schreiben weiterhin nur Ersteller oder Plattform-Admin. - Gleiches Muster für Progressionsgraphen, ggf. Medien (offen).
- Tests: zwei Vereine, zwei Nutzer, keine Kreuzzugriffe.
Phase 5 – Mitgliedschaft / Limits
- Tabellen
club_plans,club_subscriptions; Integration mit Enforcement vor relevanten Writes. - UI „Mein Verein“: Kennzahlenteaser oder Hinweise bei Limit (minimal).
Phase 6 – Verfeinerung
- Einladungsflow (E-Mail), Mehrfachrollen-UI, Audit-Log für Admin-Aktionen.
- Optionale thematische Sperren (Karate vs. Gewaltschutz) als eigene Policy-Schicht.
6. Abhängigkeiten und Risiken
- Übergang: Pilot mit einem Verein nutzt weiterhin einfache Defaults; Multi-Verein erfordert Pflicht aktiver Kontext.
- Performance: Mitgliedschaft und Rolle sollten einmal pro Request geladen und gecacht werden (Request-Scope).
- Konsistenz mit Mitai: Nutzer-Tiers können parallel bleiben; vereinsbezogene Limits sind die neue Quelle für Shinkan-spezifische Kaufmotive.
7. Nächste konkrete Artefakte
- TenantContext-Spezifikation & Endpoint-Audit (siehe
ACCESS_LAYER_AND_GOVERNANCE_PLAN.md§6). - Aktualisierung
DATABASE_SCHEMA.mdbei neuen Governance-/Scope-Feldern. - Sicherheits-Review der
list_*-Endpunkte mitclub-Visibility (fortlaufend bis Governance vereinheitlicht).
8. Verwandtes Dokument
ACCESS_LAYER_AND_GOVERNANCE_PLAN.md– verbindliche Umsetzungsstufen A–F, einheitliche Zugriffsschicht, Scope-Erweiterung (division, später Community), Capability-Vorbereitung ohne Custom-Rollen-UI; Vereinsabo explizit zurückgestellt.CAPABILITY_CATALOG.v1.md– Rollen, Capability-IDs, Account-Lifecycle, Endpoint-Mapping.CLUB_MEMBERSHIP_AND_FEATURES.v1.md– Vereinsabo, Feature-Registry (Mitai-v9c-Pattern), Kontingente.
Letzte Aktualisierung: 2026-06-06