shinkan-jinkendo/.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md
Lars e4451e1362
Some checks failed
Test Suite / playwright-tests (push) Waiting to run
Deploy Development / deploy (push) Successful in 43s
Test Suite / pytest-backend (push) Failing after 1s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Has been cancelled
Enhance Exercise Management and AI Integration
- Updated the exercise form to include a tabbed navigation structure, improving user experience with sections for Stammdaten, Anleitung, Einordnung, Varianten, and Medien & Mehr.
- Introduced the concept of **Freigabelevel** (visibility level) in the UI, replacing previous terminology for clarity and consistency across components.
- Implemented new AI endpoints for exercise suggestions and regeneration, allowing for dynamic content generation without direct database writes.
- Removed the legacy `is_primary` flag from exercise skills in the UI, ensuring that intensity levels (`niedrig`, `mittel`, `hoch`) are the primary focus for skill management.
- Enhanced the variant management process with improved saving mechanisms and UI updates to reflect changes more intuitively.
2026-05-22 07:52:31 +02:00

9.9 KiB
Raw Blame History

Einheitliche Zugriffsschicht & Governance Umsetzungsplan

Status: verbindliche Umsetzungsreihenfolge (nachgelagert zum Zielbild in MULTI_TENANCY_RBAC_ARCHITECTURE.md)
Stand: 2026-05-06
Zweck: Drift vermeiden eine nachvollziehbare Schicht für Mandanten-Kontext, Sichtbarkeit und Berechtigungen, auf die alle inhaltsbezogenen Module konsistent aufbauen.

Explizit zurückgestellt (wie vereinbart): kostenpflichtiges Vereins-Membership / Tier-Limits pro Verein (club_subscriptions o. Ä.) kommt nach stabiler Zugriffs- und Datenisolationsbasis.

Separates späteres Konzept: durch Vereinsadmins definierbare Rollen mit feingranularen Rechten (Capability-Bundles in DB/UI); dieser Plan bereitet nur die Capability-Idee und Erweiterungspunkte vor.


1. Leitprinzipien

  1. Ein Mandant für Datenisolierung: club_id ist die Grenze für „vereinsgeteilte“ Inhalte. Nur Ausnahmen: explizit plattformweite/offizielle Objekte und private Objekte des Erstellers.
  2. Ein Kontext pro HTTP-Request: Mitgliedschaft und gewählter aktiver Verein werden einmal aufgelöst und validiert; Folgelogik nutzt nur noch dieses Objekt (kein verteiltes erneutes „Rates“ aus Headers).
  3. Eine fachliche Sichtbarkeits-Semantik über alle Bibliotheks- und Planungsartefakte (Übungen, Vorlagen, Rahmenprogramme, …): gleiche Enums, gleiche Leseprüfung, angepasste Listenfilter.
  4. Sparte optional verschärfen: division_id auf Objekten und später auf Rollenzuweisung ausgewertet ohne Vereinsgrenze zu sprengen.
  5. Community später additive: neue Freigabeebene oder Flags ergänzen die bestehende Semantik, ohne club-Isolation zu ersetzen.

2. Architektur der Zugriffsschicht (Schichtenmodell)

Schicht Verantwortung
Authentifizierung Session / Token → profile_id, globale role (require_auth, bestehend).
TenantContext (neu, zentral) Aus profile_id + Header X-Active-Club-Id (optional) + DB profiles.active_club_id: effektive effective_club_id nur wenn Mitgliedschaft aktiv existiert; sonch klaren Fehler (403/400 nach Konvention). Optional: Cache der Mitgliedschaftszeilen/Rollen einmal pro Request.
Governance / Objekt contra Account Für jedes geschützte Objekt: visibility, club_id, division_id (nullable), created_byeine zentrale Entscheidung can_read / can_write (interne Module, keine Copy-Paste-Logik pro Router).
Funktions-/Feature-Rechte „Darf dieser Nutzer im Verein X Trainergruppe anlegen?“ → Capability-Checks (can_manage_club_org, can_plan_in_club, …); später durch dynamische Rollen → gleiche Capability-Namen.

Ziel: Router werden dünn: laden Daten nur noch durch Hilfen, die TenantContext und Governance bereits berücksichtigen oder explizit prüfen.


3. Scope- und Sichtbarkeitsmodell (einheitlich)

Ausgangslage im Code: private | club | official (siehe club_tenancy).

Zielbild (phasenweise DB/API-Anpassung):

Wert Lesende Regel (kurz)
private Nur created_by (+ Plattform-Admin nach Policy); keine Vereinsliste ohne Ownership.
club Nur aktive Mitglieder des Objekt-club_id; Cross-Verein nie.
division (optional neue Stufe oder club + Pflicht division_id) Nur Mitglieder, die dieser Sparte zugeordnet sind (Regeln gesondert spezifizieren: Mitgliedschaft vs. Gruppe vs. Rolle division_lead).
official Plattform-weit lesbar (Superadmin publiziert/pflegt); weiterhin strikt von club-Daten getrennt.
community (reserviert) Noch nicht implementieren; Design nur additive Felder/Enum-Einträge dokumentieren, wenn erste Stories starten.

Trainer-Flow: „Privat anlegen, dann im Verein teilen“ = Transition von private zu club (oder Kopie + neue Visibility Produktentscheidung; technisch muss club_id gesetzt und Mitgliedschaft geprüft werden).


4. Roadmap (verbindliche Reihenfolge)

Stufe A Foundations & Audit

  • Router-Inventar: Liste aller Endpoints mit Zugriff auf club_id, visibility, organisationalem Bezug oder Listenfiltern (Excel/Markdown-Tabelle im Repo oder unter .claude/docs/working/).
  • Definition of Done je Endpoint: „Default deny“ für tenant-sensitive Listen wenn Kontext fehlt/ungültig.
  • TenantContext-Spezifikation festhalten (Feldnamen, HTTP-Fehlercodes, Superadmin-Ausnahmen).

Stufe B TenantContext (Backend zentral)

  • FastAPI-Dependency z.B. get_tenant_context(session, x_active_club_id) → Objekt mit profile_id, global_role, effective_club_id, club_memberships (optional gekürzt).
  • Alle neuen und bestehenden sicherheitsrelevanten Änderungen nur über diese Dependency oder darauf aufbauende Helfer.
  • Abgleich mit Frontend: X-Active-Club-Id und Persistenz active_club_id (bereits vorhanden) als einzige variabler Vereinskontext-Quellen.

Stufe C Governance vereinheitlichen

  • Eine interne API-Stilebene (auch wenn mehrere Python-Funktionen):
    content_readable(...), content_writable(...) oder zweischichtig „Governance“ vs „Org-Rechte“.
  • Module angleichen: Übungen, Trainingsplanung, Rahmenprogramme, Vorlagen gleiche Regeln für club/official/private; division dort einführen, wo fachlich nötig (einheitliche Filter-Chips in UI).
  • Regressionstests: zwei Vereine, zwei Nutzer, kein Kreuzzugriff auf club-Objekte; Superadmin/Global-Path weiterhin getrennt testen.

Stufe D Sparten-Durchsetzung

  • division_lead und optional division_id auf Mitgliedschaft/Rolle auswerten bei Schreib-/Lesevorgängen für Objekte mit division_id.
  • Dokumentieren: Was gilt für Objekte mit division_id=NULL innerhalb eines Vereins (vereinsweit vs. nur „ohne Sparte“).

Stufe E Capabilities dokumentieren (ohne UI für Custom Roles)

  • Markdown-Tabelle Capability-Fingerprint: Kennungen wie content.share_club, planning.edit_unit, org.manage_members, … mit Zuordnung zu den heutigen festen Vereinsrollen.
  • Ziel: später club_custom_roles nur noch andere Kombination derselben Kennungen keine zweite Philosophie.

Stufe F Community (eigenes Epic)

  • Konzept: Freigabe additiv (Flag oder Enum), Moderation, Sichtbarkeit „öffentlich außerhalb meines Vereins“ ohne bestehende club-Isolation zu brechen.

Zurückgestellt Vereinsabo / Limits

  • Wiederöffnen wenn ACCESS_LAYER Stufe C/D stabil; dann Enforcement vor ausgewählten Writes an einen Billing-Stripe binden.

5. Drift vermeiden (Arbeitsdisziplin)

Mechanismus Inhalt
Cursor / IDE Projektregel .cursor/rules/access-layer.mdc (Router); Agents sollen nicht auf „nur require_auth“ ausweichen.
Heuristik-Check python backend/scripts/check_access_layer_hints.py; CI optional mit ACCESS_LAYER_STRICT=1. Optional danach: cd backend && pytest tests/ (nach pip install -r requirements-dev.txt).
PR-Checkliste Neuer/changed Endpoint: TenantContext verwendet? Governance für Listen + Detail? Tests für zweiten Verein?
Single Source of Truth Sichtbarkeitsregeln nur in Zugriffsmodul(en), nicht in Routers dupliziert.
Änderungen am Enum Nur zusammen mit Migration + Kurzbeschreibung in diesem Dokument (Datum/Changelog-Zeile).
Beziehung zu MULTI_TENANCY-Doc Zielbild und Gap-Analyse §3 dort pflegen (§3.0 = aktueller Umsetzungsstand); operative Reihenfolge hier.

6. Nächste konkrete Artefakte (nach diesem Plan)

  1. TenantContext-Spezifikation (ein Abschnitt in diesem Dokument oder Kurz-ADR): Request-Lebenszyklus, Fehlerbilder, Superadmin.
  2. Endpoint-Audit-Tabelle (Working-Dokument, bei jedem Merge pflegen bis Stufe C abgeschlossen).
  3. Testplan „Cross-Tenant“ (manuell oder pytest): Minimalsetup zweier Vereine — Unit-Tests backend/tests/test_access_layer.py; Integration backend/tests/test_access_layer_integration.py bei ACCESS_LAYER_INTEGRATION=1 / CI im Backend-Container.

Audit-Tabelle (fortlaufend): .claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md


7. Referenzen

  • .claude/docs/technical/MULTI_TENANCY_RBAC_ARCHITECTURE.md übergeordnetes Zielbild & Begriffe.
  • .claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md verbindliche Domänenregeln für Medien-Assets (gleiche Sichtbarkeit wie Übungen, Promotion-Kopplung, Copyright, Papierkorb/Lebenszyklus, externer Speicher). Bei Widerspruch zur Sichtbarkeits-Tabelle in §3 dieses Dokuments: §3 für Enums/library_content_*-Semantik, Medien-Spez für Asset-spezifische Zusatzregeln.
  • backend/club_tenancy.py bestehende Bausteine (assert_club_member, exercise_visible_to_profile, can_plan_in_club, …); Ziel ist Deren schrittweise Zusammenführung unter die neue Zugriffsschicht ohne Big-Bang.

8. Anhang Übungen (Ist-Implementierung, Referenz)

Stand: 2026-05-20 · Detail: EXERCISES_API_SPEC.md Permissions, FEATURES_DELIVERED_2026-Q2.md §16

Feld / Konzept Semantik
created_by Owner der Übung; Varianten erben Rechte
visibility UI: Freigabelevelprivate | club | official
Lesen exercise_visible_to_profileofficial global; private Ersteller + Plattform-Admin; club aktive Mitglieder (+ Plattform-Admin Audit)
Bearbeiten Ersteller; Plattform-Admin; bei club zusätzlich can_plan_in_club (Trainer, Content-Editor, Spartenleitung, Vereins-Admin)
Löschen official → Plattform-Admin; clubclub_admin im Objekt-Verein; private → Ersteller oder Vereins-Admin mit gemeinsamem Verein

Hinweis: Dieser Anhang dokumentiert den produktiven Code-Pfad in exercises.py; die Roadmap in §4 bleibt für die langfristige Vereinheitlichung aller Bibliotheksartefakte maßgeblich.


Letzte Aktualisierung: 2026-05-20