# RBAC, Kontingente & Enforcement — Roadmap

**Stand:** 2026-06-08 · App **0.8.202** · Schema **20260606084**  
**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)

### 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.

### Request-Kette (Ziel)

```
Auth → Account-State → TenantContext
  → probe_capability (Recht)
  → probe_member_feature_access (Person, v2/M9 — falls Sub-Budget gesetzt)
  → probe_club_feature_access (Vereins-Kontingent)
  → Governance (Objekt)
  → Business-Logik
  → consume (Verein + Person) + merge_feature_usage_into_response
```

**v1 (aktuell):** nur Vereins-Ebene. **v2 (Phase 5b):** Prüfung und Zählung zusätzlich gegen `profile_id` aus der Session.

### 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 |
| **M5** | Hard-Block + vollständiger Consume | ⚠️ `ai_calls` consume + Enforce auf Dev/Prod (0.8.202); Consume andere Features offen |
| **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 |
| 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 |

### 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 |

### 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.

### 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
- [x] `CLUB_FEATURE_ENFORCE=1` auf Dev (Deploy 0.8.202 verifiziert)
- [ ] `CLUB_FEATURE_ENFORCE=1` in Produktion (nach Prod-Deploy bestätigen)
- [ ] 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
- [ ] **M9:** Kontingent-Verteilung Vereinsadmin → Person (`profile_id`), Prüfung + UI
- [ ] `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: Phase 5b / M9 — Kontingent-Verteilung durch Vereinsadmins, personenbezogene Prüfung (`profile_id`); M5 Enforce Dev verifiziert.
