--- description: Mandanten & Governance — TenantContext, Sichtbarkeit, keine Schnellpfade globs: backend/routers/*.py alwaysApply: false --- # Zugriffsschicht (Shinkan) Vor neuen oder geänderten Endpoints in `backend/routers/` kurz prüfen: 1. **Pflichtlektüre** (bei inhaltsbezogenen APIs): `.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md` und `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md`. 2. **Auth**: kein geschützter Endpoint ohne `Depends(require_auth)` bzw. eingebettet in `Depends(get_tenant_context)` (der holt die Session bereits). 3. **Verein / Sichtbarkeit** (`visibility`, `club_id`, Mitglieder-Inhalte): `tenant: TenantContext = Depends(get_tenant_context)` verwenden; Profile-ID aus `tenant.profile_id`, Rolle aus `tenant.global_role`. 4. **Bibliothekslisten** (Übungen, Vorlagen, Rahmenprogramme, Progressionsgraphen, gleiche Semantik): Filter über `library_content_visibility_sql(...)` bzw. gleiche Leseregel wie bestehende Module — nicht „alle Zeilen aus SELECT“. 5. **Schreiben mit Governance**: bei `visibility`/`club_id`-Änderungen `assert_valid_governance_visibility`; bei `club` ohne `club_id` im Body → `tenant.effective_club_id` oder klare 400-Hinweise (wie bei Übungen). 6. **Ausnahmen** nur mit kurzem Kommentar im Code: `# ACCESS_LAYER exempt: …` und Eintrag im Audit oder in `backend/scripts/check_access_layer_hints.py` (EXEMPT-Liste). 7. **Nach Merge**: eine Zeile `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md` anpassen, wenn sich Tenant oder Governance ändert. ```python # ❌ Schnellpfad: nur Session, obwohl Vereinsdaten betroffen @router.get("/foo") def foo(session=Depends(require_auth)): ... # ✅ Konsistent zu clubs/exercises/planning @router.get("/foo") def foo(tenant: TenantContext = Depends(get_tenant_context)): ... ```