2026-06-07 15:27:37 +02:00
# RBAC, Kontingente & Enforcement — Roadmap
2026-06-08 08:10:53 +02:00
**Stand:** 2026-06-08 · App **0.8.202** · Schema **20260606084**
2026-06-07 15:27:37 +02:00
**Bezüge:** `MEMBERSHIP_RBAC_DECISIONS_2026-06.md` , `CAPABILITY_CATALOG.v1.md` , `CLUB_MEMBERSHIP_AND_FEATURES.v1.md`
Diese Roadmap bündelt **was fertig ist** , **was als Standard gilt** und **was noch fehlt** — ohne Insellösungen pro Feature.
---
## 1. Architektur-Standard (verbindlich)
2026-06-07 15:36:31 +02:00
### Registry-first (korrigiert 2026-06-07)
**Nicht:** vollständiger Capability-Katalog in Migration 079.
**Sondern:** Module registrieren Rechte/Kontingente bei Implementierung → `docs/working/RIGHTS_AND_FEATURES_REGISTRY.md` .
Admin-Matrix zeigt nur `capabilities.module IS NOT NULL` — keine vorgetäuschte Vollständigkeit.
2026-06-07 15:27:37 +02:00
### Request-Kette (Ziel)
```
Auth → Account-State → TenantContext
→ probe_capability (Recht)
2026-06-08 08:10:53 +02:00
→ probe_member_feature_access (Person, v2/M9 — falls Sub-Budget gesetzt)
→ probe_club_feature_access (Vereins-Kontingent)
2026-06-07 15:27:37 +02:00
→ Governance (Objekt)
→ Business-Logik
2026-06-08 08:10:53 +02:00
→ consume (Verein + Person) + merge_feature_usage_into_response
2026-06-07 15:27:37 +02:00
```
2026-06-08 08:10:53 +02:00
**v1 (aktuell):** nur Vereins-Ebene. **v2 (Phase 5b):** Prüfung und Zählung zusätzlich gegen `profile_id` aus der Session.
2026-06-07 15:27:37 +02:00
### Frontend-Standard
- `GET /api/me/entitlements` = einzige Quelle für Rechte + Kontingente in der UI
- `request()` synchronisiert `feature_usage` aus API-Responses automatisch (`featureUsageSync.js`)
- Keine parallelen `if (club_admin)` für **Sicherheit** (UX-Fallback nur übergangsweise)
### Admin
- **Rollen & Rechte** (`/admin/rights`): Matrix mit Klartext zuerst, technische ID darunter
- Umsetzungsstand pro Recht: `capability_enforcement_audit.py` → Feld `enforcement` in der Matrix
---
## 2. Ist-Stand nach Meilenstein
| Meilenstein | Inhalt | Status |
|-------------|--------|--------|
| **M1** | Feature-Schema, Pläne, Seeds | ✅ |
| **M2** | Feature-Probe + JSON-Log | ✅ |
| **M3** | Capabilities, Account-Lifecycle, Tenant | ✅ (Legacy parallel) |
| **M4** | `/me/entitlements` , Badge (KI) | ✅ teilweise |
2026-06-08 08:10:53 +02:00
| **M5** | Hard-Block + vollständiger Consume | ⚠️ `ai_calls` consume + Enforce auf Dev/Prod (0.8.202); Consume andere Features offen |
2026-06-07 15:27:37 +02:00
| **M6** | Admin UI Rollen & Rechte | ⚠️ Matrix + Kontingente; kein Plan-/Rollen-CRUD |
| **M7** | Vereinsgründung beantragen | ✅ Basis + Capabilities |
| **M8** | Stripe | ❌ |
| **Sync** | `feature_usage` + `request()` | ✅ |
---
## 3. Roadmap (empfohlene Reihenfolge)
### Phase 1 — Durchsetzung sichtbar machen (kurz)
| # | Paket | Lieferumfang | Aufwand |
|---|--------|--------------|---------|
| 1.1 | **Admin-Matrix UX** | Alle Rechte, Haken-Matrix, Umsetzungs-Badge | ✅ 2026-06-07 |
| 1.2 | **Doku-Sync** | Diese Roadmap, `MEMBERSHIP_RBAC` §2 | ✅ |
| 1.3 | **Audit pflegen** | Bei jedem `probe_capability` → `capability_enforcement_audit.py` | laufend |
### Phase 2 — Kontingente vollständig (M5)
| # | Paket | Lieferumfang |
|---|--------|--------------|
| 2.1 | **Consume erweitern** | `exercises` , `exercise_media` nach Standard-Helfer |
| 2.2 | **Badges** | `FeatureUsageBadge` an Create/Upload, nicht nur KI |
2026-06-08 08:10:53 +02:00
| 2.3 | **Dev: Enforce** | `CLUB_FEATURE_ENFORCE=1` auf Dev, Free `ai_calls=0` testen | ✅ verifiziert |
| 2.4 | **Prod-Rollout** | Enforce schrittweise; Kommunikation an Vereine | ✅ Default Compose=1 |
2026-06-07 15:27:37 +02:00
### Phase 3 — Capabilities an alle Endpoints (C3– C4)
| # | Paket | Lieferumfang |
|---|--------|--------------|
| 3.1 | **Endpoint-Audit** | `ACCESS_LAYER_ENDPOINT_AUDIT.md` — jeder Schreib-Pfad |
| 3.2 | **probe_capability** | `exercises.update/delete` , `planning.*` , `org.*` , Medien-Bibliothek, … |
| 3.3 | **CAPABILITY_ENFORCE=1** | Nach Audit auf Dev, dann Prod |
| 3.4 | **Legacy abbauen** | `can_plan_in_club` nur noch als Fallback, dokumentiert |
### Phase 4 — Frontend auf Entitlements (Phase E)
| # | Paket | Lieferumfang |
|---|--------|--------------|
| 4.1 | **Navigation** | Menüpunkte aus `hasCapability()` |
| 4.2 | **Buttons** | KI, Anlegen, Löschen, Planung — aus Entitlements |
| 4.3 | **Rollen-Labels** | Anzeige `club_roles` statt technischer IDs |
### Phase 5 — Admin & Produkt (M6 voll)
| # | Paket | Lieferumfang |
|---|--------|--------------|
| 5.1 | **Pläne-CRUD** | Neue Vereinspläne anlegen, nicht nur Seed |
| 5.2 | **Systemrolle Co-Trainer** | Seed + Matrix |
2026-06-08 08:10:53 +02:00
### Phase 5b — Kontingent-Verteilung durch Vereinsadmins (M9, Priorität KI-Kosten)
**Ziel:** Vereins-Kontingent bleibt Plan-Ebene; **Vereinsadmin** verteilt Teilkontingente auf **einzelne Personen** (`profile_id`). Verbrauch und Hard-Block gelten **pro Person** und gegen den Vereins-Pool.
| # | Paket | Lieferumfang |
|---|--------|--------------|
| 5b.1 | **Schema** | `club_member_feature_budgets` , `club_member_feature_usage` (Migration); Events mit `profile_id` (bestehend teilweise) |
| 5b.2 | **Prüf-Kette** | `probe_capability` → **Mitglieds-Budget** (`profile_id` aus Session) → Vereins-Kontingent → Governance |
| 5b.3 | **Consume** | Zählung auf Verein **und** Person; `consume_club_feature_with_usage` erweitern |
| 5b.4 | **Entitlements** | `/me/entitlements` : persönliches Budget + Vereins-Rest (z. B. `ai_calls_personal` , `ai_calls_club` ) |
| 5b.5 | **Vereinsadmin-UI** | Kontingente auf Mitglieder verteilen (Liste/Formular pro Trainer); nur `club_admin` im eigenen Verein |
| 5b.6 | **Auswertung** | Admin/Superadmin: Verbrauch **je Person** einsehbar (Fairness, „Kontingent-Fresser“); Filter `profile_id` |
| 5b.7 | **Fairness-Modell** | Harte Sub-Budgets (Modell A, Tendenz): Person darf eigenes Limit nicht überschreiten, auch wenn Verein noch Rest hat |
**Erstes Feature:** `ai_calls` (OpenRouter-Kosten). Später gleiches Muster für andere registrierte Kontingente.
**Registry:** `register_member_quota_feature()` oder Erweiterung `FeatureRegistration` mit `supports_member_budget: true` .
Bezug: `MEMBERSHIP_RBAC_DECISIONS_2026-06.md` §1.4.
2026-06-07 15:27:37 +02:00
### Phase 6 — Abrechnung (M8)
Stripe / Rechnung — bewusst nach funktionierendem Enforce.
---
## 4. Superadmin & Vereinsrechte (Entscheidung)
**Kurz: Superadmin braucht keine Vereinsrolle `club_admin` für die meiste Arbeit.**
| Ebene | Verhalten |
|-------|-----------|
| **Capabilities (neu)** | `admin` und `superadmin` = `platform_admin_bypass` für **alle Vereins-Capabilities** (`capabilities.py`) — unabhängig von `club_member_roles` |
| **Legacy-Helfer** | `can_plan_in_club` , `can_manage_club_org` → `True` für Plattform-Admin ohne Mitgliedschaft |
| **Mandant** | Aktiver Verein über `X-Active-Club-Id` / `active_club_id` — **keine** Mitgliedschaft nötig für Plattform-Admin |
| **Kontingente** | Superadmin: Quota-Bypass (Capability-Grant); zählt nicht gegen Vereins-Kontingent |
| **Ausnahmen Legacy** | Einzelne Pfade prüfen noch **nur** `has_club_role(…, 'club_admin')` ohne Plattform-Bypass — z. B. Löschen von `visibility=club` -Übungen. → Phase 3 bereinigen |
**Empfehlung:** Superadmin **nicht** zwingend als `club_admin` in jeden Verein eintragen. Optional Mitgliedschaft nur für realistische Audit-Tests oder Vereinsorga-Simulation. Produktiv: Mandant per Club-Switcher wählen.
`admin` (Portal-Admin): gleicher Capability-Bypass für Vereins-Funktionen; Portal-Capabilities nur mit explizitem Grant in der Matrix.
---
## 5. Vereinsrollen-Matrix — Semantik (Admin-UI)
| Zustand | Bedeutung | UI |
|---------|-----------|-----|
| **Keine Grants** in DB | Alle aktiven Mitglieder (wenn `min_account_state` reicht) | Zellen zeigen „alle“ |
| **Mindestens ein Grant** | Nur angehakte Rollen | Checkboxen |
| ** „Alle Mitglieder“** | Löscht alle Grants der Zeile | Zurück zum offenen Zustand |
Das ersetzt das frühere Formular „Vereinsrollen-Grant hinzufügen“, das nur bereits eingeschränkte Rechte sichtbar machte.
---
## 6. Offene Lücken (Checkliste)
- [ ] `CAPABILITY_ENFORCE=1` in Produktion
2026-06-08 08:10:53 +02:00
- [x] `CLUB_FEATURE_ENFORCE=1` auf Dev (Deploy 0.8.202 verifiziert)
- [ ] `CLUB_FEATURE_ENFORCE=1` in Produktion (nach Prod-Deploy bestätigen)
2026-06-07 15:27:37 +02:00
- [ ] Consume für alle Features mit Verbrauch (nicht nur `ai_calls` )
- [ ] `probe_capability` auf >90 % der Schreib-Endpoints
- [ ] Frontend ohne Legacy-Rollen-Guards
- [ ] Multipart-Uploads an `featureUsageSync` anbinden
- [ ] Legacy-Löschpfade mit Plattform-Bypass harmonisieren
2026-06-08 08:10:53 +02:00
- [ ] **M9:** Kontingent-Verteilung Vereinsadmin → Person (`profile_id`), Prüfung + UI
2026-06-07 15:27:37 +02:00
- [ ] `HANDOVER.md` / `PROJECT_STATUS` Versionsstand aktualisieren
---
## 7. Referenzen
| Datei | Zweck |
|-------|--------|
| `backend/capability_enforcement_audit.py` | Matrix-Badges „angebunden / Legacy“ |
| `backend/club_features.py` | Consume-Standard |
| `frontend/src/utils/featureUsageSync.js` | Entitlements-Sync |
| `frontend/src/pages/AdminRightsPage.jsx` | Konfiguration |
**Changelog**
- 2026-06-07: Initial nach Session Rollen/Kontingente — Standard, Roadmap Phasen 1– 6, Superadmin-Klärung, Matrix-Semantik.
2026-06-08 08:10:53 +02:00
- 2026-06-08: Phase 5b / M9 — Kontingent-Verteilung durch Vereinsadmins, personenbezogene Prüfung (`profile_id`); M5 Enforce Dev verifiziert.