shinkan-jinkendo/docs/jinkendo-family/design-principles/ACCESS_LAYER_DESIGN_PRINCIPLES.md
Lars 6c7c24e887
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Test Suite / pytest-backend (push) Successful in 45s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 15s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m35s
Add Jinkendo family design principles and entitlement model docs.
Document cross-app architecture patterns, Mitai alignment, and family entitlement standards. Documentation only; no runtime changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 09:12:48 +02:00

7.8 KiB
Raw Blame History

Access Layer & Tenant Designprinzipien (Extraktion)

Status: Analyse / Arbeitspapier
Stand: 2026-07-04
Geltungsbereich: Modul „Access Layer & Tenant Governance“ — keine Shinkan-Gesamtarchitektur, keine Kampfsport-Domänenlogik

Serie: Designprinzipien für Produktfamilie · Shinkan Dokument 1 von 15
Mitai-Vergleich: kein direktes Gegenstück (Mitai ist profil-zentriert, kein Vereins-Mandant)

Kernkomponenten:

Bereich Pfade
TenantContext backend/tenant_context.py
Governance-Helfer backend/club_tenancy.py
Listenfilter SQL library_content_visibility_sql() in tenant_context.py
Endpoint-Audit .claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md
Cursor-Regel .cursor/rules/access-layer.mdc
Heuristik-Check backend/scripts/check_access_layer_hints.py
Normative Spec .claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md

Modul

Access Layer & Tenant Governance

Zentraler Querschnitt für Mandanten-Kontext (club_id), Sichtbarkeit (private/club/official) und einheitliche Les-/Schreibregeln für Bibliotheksartefakte (Übungen, Medien, Rahmenprogramme, Vorlagen, Progressionsgraphen).


Fachliche Verantwortung

  1. TenantContext pro HTTP-Request — Auflösung aus Session + Header X-Active-Club-Id + Profilfeld active_club_id.
  2. Datenisolierungclub_id als Grenze für vereinsgeteilte Inhalte; Cross-Verein ausgeschlossen.
  3. Einheitliche Sichtbarkeits-Semantik — gleiche Enums und Prüflogik über alle Bibliotheksmodule.
  4. Governance-Transitionen — Regeln beim Wechsel privateclubofficial und beim Löschen.
  5. Listenfilter — SQL-Baustein statt „SELECT *“ in jedem Router.

Administrierte Konfigurationen

Konfiguration Speicherort Inhalt
Aktiver Verein profiles.active_club_id Persistierter UI-Kontext
Request-Override Header X-Active-Club-Id Client-seitiger Mandantenwechsel
Sichtbarkeit Spalte visibility je Objekt private, club, official
Vereinszuordnung Spalte club_id Pflicht bei club-Inhalten

Bewusst nicht hardcodiert

  • Welche Objekte welchen Verein haben (Daten)
  • Individuelle Freigabeentscheidungen (Workflow)

Hardcodiert (Code)

  • Enum-Werte und Leseregeln in club_tenancy.py / library_content_visibility_sql
  • Plattform-Admin-Ausnahmen (is_platform_admin, is_superadmin)
  • Rollencodes für Schreib-/Löschregeln (club_admin, trainer, …)

Designprinzipien

1. Ein Mandant pro Request (TenantContext)

Prinzip Depends(get_tenant_context) liefert profile_id, global_role, effective_club_id, Mitgliedschaften — einmal pro Request.
Begründung Kein verteiltes „Rates“ aus Headers; konsistente Filter in allen Routern.
Quelle tenant_context.py; ACCESS_LAYER_AND_GOVERNANCE_PLAN.md §2
Tragfähigkeit hoch
Einschränkung Nicht alle Endpoints migriert; Audit-Tabelle zeigt Restbestand mit nur require_auth.

2. club_id als Datenisolierungsgrenze

Prinzip Vereinsgeteilte Inhalte sind nur für aktive Mitglieder des Objekt-club_id lesbar — nie Cross-Verein.
Begründung Mandantenfähigkeit für Vereinsplattform; Compliance bei geteilten Trainingsinhalten.
Quelle library_content_visibility_sql(); Tests test_access_layer*.py
Tragfähigkeit hoch
Einschränkung division-Verschärfung noch nicht durchgängig; reserviert im Plan.

3. Einheitliche Visibility-Semantik

Prinzip private | club | official mit gleicher Bedeutung für Übungen, Medien, Rahmen, Module, Graphen.
Begründung Nutzer und Trainer verstehen ein Freigabemodell; UI-Feld „Freigabelevel“ durchgängig.
Quelle club_tenancy.py; FACHLICHE_NUTZERFUNKTIONEN.md §4.7
Tragfähigkeit hoch
Einschränkung community-Stufe nur dokumentiert, nicht implementiert.

4. Zentraler SQL-Filter für Bibliothekslisten

Prinzip Listen nutzen library_content_visibility_sql(alias, profile_id, role, effective_club_id) — nicht handgeschriebene WHERE-Kopien.
Begründung Drift-Vermeidung; ein Fix gilt für alle Kataloge.
Quelle tenant_context.py; Router exercises.py, training_framework_programs.py, …
Tragfähigkeit hoch
Einschränkung Einzelne Legacy-Queries können noch abweichen.

5. Governance-Transitionen explizit prüfen

Prinzip Wechsel von visibility/club_id über assert_library_content_governance_transition + assert_valid_governance_visibility.
Begründung „Privat → Verein teilen“ und „official herabstufen“ sind sicherheitsrelevante Aktionen.
Quelle club_tenancy.py
Tragfähigkeit hoch
Einschränkung Nicht jedes Modul ruft Transition-Helper bei PATCH auf.

6. Löschregeln nach Visibility-Stufe

Prinzip assert_library_content_deletable: privat → Ersteller/Vereinsadmin-Kontext; club → Vereinsadmin; official → Plattform-Admin.
Begründung Schutz vor versehentlichem Löschen fremder oder offizieller Inhalte.
Quelle club_tenancy.py
Tragfähigkeit hoch
Einschränkung Medien-Lifecycle hat zusätzliche Stufen (Papierkorb) — Schnittmenge beachten.

7. Aktiver Verein: Header + Profil synchron

Prinzip Frontend sendet X-Active-Club-Id; Backend validiert gegen Mitgliedschaft; Profil speichert active_club_id.
Begründung Einheitlicher Mandanten-Kontext über API und UI.
Quelle frontend/src/api/client.js (mergeActiveClubHeader); profiles Router
Tragfähigkeit hoch
Einschränkung Onboarding-Nutzer ohne Verein: eingeschränkter Nav-Modus.

8. Plattform-Admin als Audit-Pfad, nicht als Bypass

Prinzip Plattform-Admins sehen fremde club-Inhalte nur mit expliziter Regel (Mitgliedschaft oder Audit-Ausnahme in SQL).
Begründung Superuser-Zugriff ohne Mandanten-Leak in normalen Trainer-Flows.
Quelle library_content_visibility_sqlclub_ok_plat-Zweig
Tragfähigkeit mittel
Einschränkung Feinheiten zwischen admin und superadmin (z. B. official, Legal Hold) separat geregelt.

9. Endpoint-Audit als lebendes Inventar

Prinzip Jeder sicherheitsrelevante Endpoint-Eintrag in ACCESS_LAYER_ENDPOINT_AUDIT.md; PR-Checkliste verlangt Update.
Begründung Sichtbarkeit des Migrationsstands; kein stilles Ausweichen auf require_auth allein.
Quelle .claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md; check_access_layer_hints.py
Tragfähigkeit hoch (prozessual)
Einschränkung CI-Strict-Modus optional, nicht überall aktiv.

Nicht übernehmen

  1. Endpoints nur mit require_auth bei tenant-sensitiven Daten — führt zu IDOR und fehlenden Listenfiltern.
  2. Visibility-Logik pro Router duplizieren — historische Drift zwischen Übungen und Planung.
  3. division vor stabiler Vereins-Isolation — Reihenfolge im Plan: erst Stufe C, dann D.
  4. Community-Freigabe ohne additive Felder — würde club-Isolation brechen.
  5. Client-seitige Mandantenfilter ohne Server-Enforcement — UI-Hiding reicht nicht.

Verwandte Dokumentation