2026-06-07 05:57:13 +02:00
# Membership, RBAC & Kontingente — Produktentscheidungen
**Status:** Verbindlich (Zielbild & Roadmap-Priorisierung)
**Stand:** 2026-06-06
**Bezüge:** `CAPABILITY_CATALOG.v1.md` , `CLUB_MEMBERSHIP_AND_FEATURES.v1.md` , `ACCESS_LAYER_AND_GOVERNANCE_PLAN.md`
Dieses Dokument hält **getroffene Produktentscheidungen** fest (Session 2026-06-06) und ergänzt die v1-Konzept-Specs um Umsetzungsrichtung. Technischer Implementierungsstand: Abschnitt 2.
---
## 1. Getroffene Entscheidungen
### 1.1 Onboarding: `verified_pending_club`
Nutzer **ohne aktive Vereinsmitgliedschaft** (E-Mail verifiziert) dürfen **nur** :
| Erlaubt | Nicht erlaubt (Zielbild) |
|---------|---------------------------|
| Konto / Einstellungen | Übungen, Planung, KI, Medien |
| Vereinsverzeichnis lesen | Vereinsinterne Inhalte (`club`), private Fremdinhalte |
| **Beitrittsantrag** an bestehenden Verein | Vollzugriff auf Bibliothek / offizielle Inhalte (Lesen) — **bewusst gesperrt** bis Mitgliedschaft |
| **Vereinsgründung beantragen** (Prozess M7, Superadmin-Freigabe) | |
**Kein** „Bibliothek durchstöbern“ für Bewerber — reduziert Datenexposition und vereinfacht UX („erst Verein, dann Arbeit“).
Technischer Zustand: `account_state = verified_pending_club` (siehe `CAPABILITY_CATALOG.v1.md` §3).
---
### 1.2 Rollenmodell: Risikoarm statt Big-Bang
**Zielbild (langfristig):**
- **Fest:** nur `superadmin` (Plattform) als nicht konfigurierbare Systemrolle.
- **Dynamisch konfigurierbar:** alle Vereinsrollen und deren Capability-Bundles (später `club_custom_roles` ).
- Optional: `admin` (Plattform) als abgeschwächter Portal-Admin bleibt vorerst bestehen (Ist-Code).
**Entscheidung v1 (risikoarm):**
| Maßnahme | Jetzt | Später |
|----------|-------|--------|
| Alte Helfer (`can_plan_in_club`, `if (club_admin)` in JSX) | **Behalten** — weiter produktiv | Schrittweise durch `entitlements` ersetzen |
| Neue Endpoints / Features | Nur über **Capability-IDs** + Audit | — |
| Neue Vereinsrollen | Als **Systemrollen** ergänzen (z. B. `co_trainer` ) | Custom Roles UI |
| `club_custom_roles` | **Nicht** in v1 | v2 Epic |
**Begründung:** Backend und Frontend haben hunderte Verdrahtungen auf `trainer` / `club_admin` / Plattform-Rollen. Parallelbetrieb Capability-System + Legacy-Helfer ist sicherer als einmaliges Aufbrechen.
**Co-Trainer (geplant als Systemrolle):** weniger Capabilities als `trainer` (z. B. kein `planning.*` , kein `exercises.create` ) — Umsetzung nach Onboarding-Gates + Entitlements-Rollout, nicht vorher.
---
### 1.3 Vereins-Kontingente (Membership-Pakete)
**Jetzt:** Schema und Anzeige vorbereiten; **keine** detaillierte Paket-Logik (z. B. „3 Trainer + 10 Co-Trainer“) implementieren.
| Vorbereitet (DB/Module) | Bewusst zurückgestellt |
|-------------------------|-------------------------|
| `features` , `club_plans` , `club_subscriptions` | Eigene Feature-IDs `trainer_seats` / `co_trainer_seats` |
| Bestands-Limits (`exercises`, `training_groups` , `ai_calls` , …) | Zählregel „nur planungsberechtigte Mitglieder“ vs. alle Mitglieder |
| `GET /me/entitlements` Feature-Teil | Stripe / Rechnung (M8) |
**Prinzip:** Neue Kontingent-Typen = neue `features` -Zeile + Plan-Limits + optional Capability-`linked_feature_id` — ohne Schema-Bruch.
---
### 1.4 Trainer-Budget innerhalb Vereins-Kontingent (v2)
**Anforderung:** Vereins-KI-Kontingent liegt beim Verein; **Vereinsadmin** kann pro Trainer ein **Sub-Budget** vergeben (Fairness, „Kontingent-Fresser“).
**Entscheidung:**
- v1: nur **Vereins-Ebene** (`club_plan_limits`, `club_feature_usage` ).
- v2: neue Tabellen (Skizze):
```sql
-- Skizze — noch nicht migriert
club_member_feature_budgets (club_id, profile_id, feature_id, limit_value, …)
club_member_feature_usage (club_id, profile_id, feature_id, usage_count, reset_at, …)
```
2026-06-08 08:10:53 +02:00
**Prüf-Kette v2:** Capability → Mitglieds-Budget (falls gesetzt, `profile_id` aus Session) → Vereins-Kontingent.
2026-06-07 05:57:13 +02:00
**Fairness-Modell (offen, Tendenz):** harte Sub-Budgets (Modell A) — Trainer darf sein Budget nicht überschreiten, auch wenn Verein noch Rest hat.
2026-06-08 08:10:53 +02:00
**Roadmap:** Phase 5b / Meilenstein **M9** in `docs/working/RBAC_ENFORCEMENT_ROADMAP.md` — Vereinsadmin-UI zur Verteilung, Entitlements mit persönlichem + Vereins-Rest, Auswertung je Person.
2026-06-07 05:57:13 +02:00
---
### 1.5 Enforcement-Phasen (unverändert, bestätigt)
| Phase | Verhalten | Nutzer sichtbar |
|-------|-----------|-----------------|
| 2 (M2/M3) | JSON-Log, kein Block | Nein (außer Logs) |
| 3 (M4) | `GET /me/entitlements` + Badge | Kontingent-Anzeige |
| 4 (M5+) | HTTP 403 + `increment` | Hard-Block |
Env-Schalter: `ACCOUNT_GATE_ENFORCE` (Default `1` , Endpoint-Helfer), `ACCOUNT_GATE_API_ENFORCE` (Default `1` , API-Middleware Phase A), `CAPABILITY_ENFORCE` / `CLUB_FEATURE_ENFORCE` (Default `0` ).
---
## 2. Implementierungsstand (Ist, Codebase)
2026-06-07 15:27:37 +02:00
**DB-Schema:** `20260606083` · App **0.8.199** (`backend/version.py`)
**Roadmap (detailliert):** `docs/working/RBAC_ENFORCEMENT_ROADMAP.md`
2026-06-07 05:57:13 +02:00
### M1 — Feature-Schema v9c ✅
| Deliverable | Status |
|-------------|--------|
| Migration `078_club_features_and_plans.sql` | ✅ |
| Legacy `001` archiviert | ✅ |
| `club_plans` , `club_subscriptions` , Usage-Tabellen | ✅ |
| Seed Features + Pläne (`free`, …) | ✅ |
| `club_features.py` : `check_club_feature_access` , `get_effective_club_plan` | ✅ |
| Backfill Vereine → Plan `free` | ✅ |
### M2 — Feature-Probe (Log only) ✅
| Deliverable | Status |
|-------------|--------|
| `club_feature_logger.py` → `club-feature-usage.log` | ✅ |
| `probe_club_feature_access()` | ✅ |
| Hooks: KI-Endpoints, `POST /exercises` , Medien-Upload, Planungs-KI | ✅ |
2026-06-07 15:27:37 +02:00
| Consume-Standard + `feature_usage` in Response (`ai_calls`) | ✅ |
2026-06-07 05:57:13 +02:00
| `CLUB_FEATURE_ENFORCE=0` (Default) | ✅ |
### M3 — Account-Lifecycle + Capability-Grants ⚠️ teilweise
| Deliverable | Status | Lücke |
|-------------|--------|-------|
| Migration `079_capabilities.sql` + Seed | ✅ | — |
| `account_lifecycle.py` , `resolve_account_state` | ✅ | — |
| `capabilities.py` , `check_capability` , `probe_capability` | ✅ | — |
| `TenantContext.account_state` | ✅ | — |
| `GET /profiles/me` → `account_state` , `club_roles` | ✅ | — |
| Account-Gates auf **Schreib-/KI-Endpoints** | ✅ | Lesepfade für Bewerber noch offen |
| `CAPABILITY_ENFORCE=0` (nur Log) | ✅ | — |
| Onboarding UX: nur Bewerbung/Gründung | ✅ | Phase A: API-Middleware + `/onboarding` + reduzierte Nav |
2026-06-07 15:27:37 +02:00
| `club_creation_requests` (M7) | ✅ Basis | Capabilities + Admin-Freigabe |
| Quota-Bypass via Capability-Grants (083) | ✅ | kein paralleles Exemption-Schema |
2026-06-07 05:57:13 +02:00
| Custom Roles / Co-Trainer | ❌ | bewusst v2 |
| Legacy-Helfer entfernt | ❌ | bewusst parallel |
2026-06-07 15:27:37 +02:00
### M4 — Anzeige ✅ teilweise
| Deliverable | Status |
|-------------|--------|
| `GET /api/me/entitlements` | ✅ |
| `EntitlementsContext` , `hasCapability()` | ✅ (UI nutzt noch kaum) |
| `FeatureUsageBadge` | ✅ nur KI im Übungsformular |
| `featureUsageSync` in `request()` | ✅ |
### M5 — Hard-Block + vollständiger Verbrauch ⚠️
| Deliverable | Status |
|-------------|--------|
| `consume_club_feature_with_usage` Standard | ✅ `ai_calls` |
| `CLUB_FEATURE_ENFORCE=1` produktiv | ❌ Default 0 |
| Consume `exercises` , `exercise_media` , … | ❌ |
### M6 — Admin UI Rollen & Rechte ⚠️
| Deliverable | Status |
|-------------|--------|
| `/admin/rights` Capability-Matrix (Portal + Verein) | ✅ |
| Klartext zuerst, Enforcement-Badge | ✅ 2026-06-07 |
| Kontingent-Bypass + Vereinspläne (Seed) | ✅ |
| Neue Pläne / Rollen anlegen (CRUD) | ❌ |
### Bewusst zurückgestellt
2026-06-07 05:57:13 +02:00
| ID | Inhalt |
|----|--------|
| M0 | CI-Isolation / Test-DB |
| M8 | Stripe |
2026-06-07 15:27:37 +02:00
| v2 | Trainer-Budgets, Custom Roles |
2026-06-07 05:57:13 +02:00
---
## 3. Architektur-Zielbild (kompakt)
```
Request
→ require_auth
→ account_state (Gate)
→ TenantContext
→ assert_capability (Rolle / Funktion)
→ check_club_feature_access (Vereins-Kontingent)
→ [v2] member_feature_budget (Trainer-Budget)
→ Governance (Objekt)
```
**Drei Achsen:** Account-Lifecycle · Capabilities · Features (Kontingente). Governance bleibt vierte Prüfung.
---
## 4. Empfohlene Roadmap (nach Entscheidungen)
| Phase | Paket | Warum zuerst |
|-------|--------|--------------|
| **A** | **Onboarding-Gates vollständig** | ✅ umgesetzt (API + Frontend `/onboarding` ) |
| **B** | **M7 Vereinsgründung beantragen** | **Als Nächstes** — zweiter Pfad für `verified_pending_club` |
| **C** | **M5 Hard-Block `ai_calls`** | Free-Plan `0` wird real; Badge (M4) liefert Erklärung |
2026-06-07 15:27:37 +02:00
| **D** | **M6 voll** | Pläne-CRUD, Rollen-CRUD | ⚠️ Matrix da |
| **E** | Entitlements im Frontend (`hasCapability`) | Entscheidung 1.2 risikoarm |
2026-06-08 08:10:53 +02:00
| **F** | **M9 Kontingent-Verteilung** — Vereinsadmin vergibt Sub-Budgets pro Person (`profile_id`); Prüfung + Consume personenbezogen; UI Vereinsorga | Entscheidung 1.4, Roadmap Phase 5b |
| **G** | `co_trainer` + Custom Roles (v2) | Entscheidung 1.2 |
2026-06-07 05:57:13 +02:00
M0 parallel, nicht blockierend.
---
## 5. Offene Punkte (vor M6 / v2)
1. Fairness Modell A/B/C für Trainer-Budget (Tendenz: A).
2. Ob `admin` (Portal) langfristig neben `superadmin` bleibt.
3. Ob offizielle Inhalte für Bewerber **nie** lesbar bleiben (aktuell: ja).
---
## 6. Referenzen
| Pfad | Inhalt |
|------|--------|
| `CAPABILITY_CATALOG.v1.md` | Capability-IDs, Account-States |
| `CLUB_MEMBERSHIP_AND_FEATURES.v1.md` | Feature-Registry, Kontingente |
| `backend/club_features.py` | Vereins-Features |
| `backend/capabilities.py` | Capability-Auflösung |
| `backend/account_lifecycle.py` | Account-Gates |
2026-06-07 15:27:37 +02:00
## 7. Superadmin im Verein (FAQ)
Siehe ** `docs/working/RBAC_ENFORCEMENT_ROADMAP.md` §4**: Plattform-Admin (`admin`, `superadmin` ) erhält **Capability-Bypass** für Vereins-Funktionen ohne `club_admin` -Mitgliedschaft. Mandant über aktiven Verein wählen; Kontingente via Bypass. Einzelne Legacy-Pfade (z. B. Löschen `visibility=club` ) sind noch nicht vereinheitlicht — Ziel Phase 3.
---
2026-06-07 05:57:13 +02:00
**Changelog**
- 2026-06-06: Initial — Entscheidungen Onboarding, Rollen-Risiko, Kontingente, Trainer-Budget v2; Ist-Stand M1– M3; Roadmap A– F.
- 2026-06-06: Phase A — `account_onboarding_gate.py` , Frontend `/onboarding` , reduzierte Navigation.
2026-06-07 15:27:37 +02:00
- 2026-06-07: M4– M6 Ist-Stand, Roadmap-Verweis, Superadmin-FAQ; Admin-Matrix UX + Enforcement-Audit.
2026-06-08 08:10:53 +02:00
- 2026-06-08: Roadmap Phase 5b / M9 — Vereinsadmin-Kontingentverteilung pro Person; Enforce Dev verifiziert (0.8.202).