shinkan-jinkendo/.claude/docs/technical/MEMBERSHIP_RBAC_DECISIONS_2026-06.md

211 lines
8.6 KiB
Markdown
Raw Normal View History

# 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, …)
```
**Prüf-Kette v2:** Capability → Mitglieds-Budget (falls gesetzt) → Vereins-Kontingent.
**Fairness-Modell (offen, Tendenz):** harte Sub-Budgets (Modell A) — Trainer darf sein Budget nicht überschreiten, auch wenn Verein noch Rest hat.
---
### 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)
**DB-Schema:** `20260606079` (`backend/version.py`)
**Deploy-Referenz:** Dev mit M2-Logging verifiziert (`club-feature-usage.log`).
### 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 | ✅ |
| `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 |
| `club_creation_requests` (M7) | ❌ | — |
| Custom Roles / Co-Trainer | ❌ | bewusst v2 |
| Legacy-Helfer entfernt | ❌ | bewusst parallel |
### Bewusst zurückgestellt (Roadmap)
| ID | Inhalt |
|----|--------|
| M0 | CI-Isolation / Test-DB |
| M5 | Hard-Block Kontingente |
| M6 | Superadmin Admin-UI (Pläne, Capability-Matrix) |
| M7 | Vereinsgründung beantragen |
| M8 | Stripe |
### Hinweis: M4 im Repo (über M3 hinaus)
Falls bereits deployed: `GET /api/me/entitlements`, `EntitlementsContext`, `FeatureUsageBadge` — gehört zur **Anzeige-Phase 3**, nicht zum M3-Kern. Siehe `entitlements` Modul v1.0.0.
---
## 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 |
| **D** | **M6 Superadmin-UI** | Pläne + Capability-Matrix ohne SQL |
| **E** | Systemrolle `co_trainer` + Entitlements im Frontend | Entscheidung 1.2 risikoarm |
| **F** | Member-Budgets (v2) | Entscheidung 1.4 |
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 |
**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.