shinkan-jinkendo/.claude/docs/technical/MEMBERSHIP_RBAC_DECISIONS_2026-06.md
Lars dd0fae4bf5
Some checks failed
Deploy Development / deploy (push) Successful in 49s
Test Suite / pytest-backend (push) Failing after 43s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 15s
Test Suite / k6 /health Baseline (push) Successful in 44s
Test Suite / playwright-tests (push) Successful in 1m15s
Enhance Planning AI with Roadmap-First Architecture and New Features
- Introduced a roadmap-first approach for the planning AI, allowing for a structured progression graph that aligns with the overall project roadmap.
- Added new functionality to strip off-topic steps from exercise paths, improving the relevance of generated exercise suggestions.
- Implemented a detailed goal text generation for AI proposals, enhancing the context provided for new exercises.
- Updated the ExerciseProgressionPathBuilder component to support new features, including roadmap previews and improved focus area handling.
- Incremented application version to 0.8.205 and updated database schema version to 20260606086 to reflect these changes.
2026-06-08 08:10:53 +02:00

244 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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, `profile_id` aus Session) → Vereins-Kontingent.
**Fairness-Modell (offen, Tendenz):** harte Sub-Budgets (Modell A) — Trainer darf sein Budget nicht überschreiten, auch wenn Verein noch Rest hat.
**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.
---
### 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:** `20260606083` · App **0.8.199** (`backend/version.py`)
**Roadmap (detailliert):** `docs/working/RBAC_ENFORCEMENT_ROADMAP.md`
### 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 | ✅ |
| Consume-Standard + `feature_usage` in Response (`ai_calls`) | ✅ |
| `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) | ✅ Basis | Capabilities + Admin-Freigabe |
| Quota-Bypass via Capability-Grants (083) | ✅ | kein paralleles Exemption-Schema |
| Custom Roles / Co-Trainer | ❌ | bewusst v2 |
| Legacy-Helfer entfernt | ❌ | bewusst parallel |
### 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
| ID | Inhalt |
|----|--------|
| M0 | CI-Isolation / Test-DB |
| M8 | Stripe |
| v2 | Trainer-Budgets, Custom Roles |
---
## 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 voll** | Pläne-CRUD, Rollen-CRUD | ⚠️ Matrix da |
| **E** | Entitlements im Frontend (`hasCapability`) | Entscheidung 1.2 risikoarm |
| **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 |
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 |
## 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.
---
**Changelog**
- 2026-06-06: Initial — Entscheidungen Onboarding, Rollen-Risiko, Kontingente, Trainer-Budget v2; Ist-Stand M1M3; Roadmap AF.
- 2026-06-06: Phase A — `account_onboarding_gate.py`, Frontend `/onboarding`, reduzierte Navigation.
- 2026-06-07: M4M6 Ist-Stand, Roadmap-Verweis, Superadmin-FAQ; Admin-Matrix UX + Enforcement-Audit.
- 2026-06-08: Roadmap Phase 5b / M9 — Vereinsadmin-Kontingentverteilung pro Person; Enforce Dev verifiziert (0.8.202).