All checks were successful
Deploy Development / deploy (push) Successful in 48s
Test Suite / pytest-backend (push) Successful in 45s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 15s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m35s
Document cross-app architecture patterns, Mitai alignment, and family entitlement standards. Documentation only; no runtime changes. Co-authored-by: Cursor <cursoragent@cursor.com>
317 lines
14 KiB
Markdown
317 lines
14 KiB
Markdown
# Familien-Modell: Entitlements & Limits
|
||
|
||
**Status:** Entwurf / verbindliche Zielrichtung (mit bewussten Produkt-Ausnahmen)
|
||
**Stand:** 2026-07-04
|
||
**Bezüge:**
|
||
|
||
- [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) — Abgleich Mitai ↔ Shinkan
|
||
- Mitai: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md)
|
||
- Shinkan: [CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md)
|
||
|
||
---
|
||
|
||
## 1. Zweck
|
||
|
||
Dieses Dokument definiert das **gemeinsame Entitlement-Modell** der Jinkendo-Produktfamilie:
|
||
|
||
- **Was** für neue Apps und Refactors **Standard** ist
|
||
- **Welche Produkt-Profile** welche Scopes nutzen (Account, Tenant, beides, keins)
|
||
- **Wie** bewusste Abweichungen dokumentiert werden — Abweichung ist erlaubt, **Undokumentiertheit** nicht
|
||
|
||
**Nicht enthalten:** Stripe/SSO (`auth.jinkendo.de`), vollständige Billing-Implementierung, app-spezifische Feature-IDs.
|
||
|
||
---
|
||
|
||
## 2. Leitgedanke: Vier getrennte Fragen
|
||
|
||
Jede geschützte Aktion durchläuft konzeptionell **vier unabhängige Prüfungen**. Nicht jede App implementiert alle vier — siehe §6.
|
||
|
||
| # | Frage | Familien-Begriff | Typische Quelle |
|
||
|---|--------|------------------|-----------------|
|
||
| **A** | Wer ist eingeloggt? | **Auth** (Identität) | Session → `profile_id` |
|
||
| **B** | Darf diese Rolle die **Funktion** ausführen? | **Capability** (Permission) | Rollen-Matrix, `min_account_state` |
|
||
| **C** | Ist das **Kontingent** erschöpft? | **Feature / Limit** (Quota) | Plan, Tier, Usage-Zähler |
|
||
| **D** | Darf ich **dieses Objekt** lesen/ändern? | **Governance** (Object ACL) | `visibility`, `club_id`, Owner |
|
||
|
||
```
|
||
Request → Auth (A) → [Capability (B)] → [Feature-Limit (C)] → [Governance (D)] → Handler
|
||
```
|
||
|
||
**Familien-Regel:** B, C und D **nicht** in React-Widgets oder Router-Inline-Logik vermischen — jeweils eine Auflösungsfunktion pro Ebene.
|
||
|
||
**Shinkan-Ergänzung:** Governance ist dort ausgebaut (`TenantContext`, Access Layer); Mitai fokussiert A+B+C auf Profil-Ebene.
|
||
|
||
---
|
||
|
||
## 3. Familien-Standard: Zwei Subjekt-Ebenen
|
||
|
||
Limits und Pläne können an **zwei Subjekte** hängen. Beide sind im Familienmodell **first-class** — Apps wählen, welche sie nutzen (§6).
|
||
|
||
| Subjekt | ID | Typische Frage | Beispiel |
|
||
|---------|-----|----------------|----------|
|
||
| **Account** | `profile_id` | Was darf **ich** als Nutzer (Tarif)? | Mitai Free vs. Premium |
|
||
| **Tenant** | `tenant_id` (z. B. `club_id`) | Was darf **meine Organisation**? | Shinkan Vereinsplan, KI-Kontingent |
|
||
|
||
### 3.1 Auflösungs-Reihenfolge (wenn beide Ebenen aktiv)
|
||
|
||
Für eine Aktion mit Capability `X` und Feature `Y`:
|
||
|
||
1. **Account-Lifecycle** — z. B. E-Mail verifiziert, Onboarding abgeschlossen
|
||
2. **Capability(B)** — Rolle darf Funktion (Account- und/oder Tenant-Rollen)
|
||
3. **Feature(C)** — Kontingent am **primären Billing-Subjekt** der App (siehe Produkt-Profil)
|
||
4. **Governance(D)** — Objekt sichtbar/bearbeitbar
|
||
|
||
**AND-Verknüpfung:** Alle aktiven Ebenen müssen passieren. Ausnahmen nur in §6.3 dokumentiert.
|
||
|
||
### 3.2 Primäres Billing-Subjekt pro App
|
||
|
||
| Profil | Primäres Subjekt für Limits | Capability-Subjekt |
|
||
|--------|----------------------------|-------------------|
|
||
| Personal App (Mitai) | **Account** | Account |
|
||
| Mandanten-App (Shinkan) | **Tenant** | Account + Tenant-Rolle |
|
||
| Hybrid (Zukunft) | konfigurierbar | beide |
|
||
|
||
---
|
||
|
||
## 4. Familien-Standard: Capabilities vs. Features
|
||
|
||
| Konzept | Familien-Definition | Subjekt | Beispiel |
|
||
|---------|---------------------|---------|----------|
|
||
| **Capability** | Binäre oder rollenbasierte **Erlaubnis** („darf ich?“) | meist Account + Tenant-Kontext | `exercises.ai.suggest` |
|
||
| **Feature** | **Kontingent** oder Boolean-Limit („wie oft/noch?“) | Account **oder** Tenant | `ai_calls` / Monat |
|
||
| **Verknüpfung** | Capability kann `linked_feature_id` haben | — | KI-Capability → KI-Kontingent |
|
||
|
||
**Familien-Regel:**
|
||
|
||
- Capabilities **registry-first** registrieren (Code → DB-Sync, Shinkan-Muster).
|
||
- Feature-IDs **nicht** in UI hardcoden — nur aus Entitlements-Response.
|
||
- `NULL` Limit = unbegrenzt; `0` = deaktiviert (Mitai-Semantik, familienweit).
|
||
|
||
---
|
||
|
||
## 5. Familien-Standard: API & Enforcement
|
||
|
||
### 5.1 Ziel-API (neue Apps)
|
||
|
||
Ein **einheitlicher Snapshot** für das Frontend:
|
||
|
||
```
|
||
GET /api/me/entitlements
|
||
?tenant_id=<optional>
|
||
|
||
Response (skizziert):
|
||
{
|
||
"account": {
|
||
"profile_id": 1,
|
||
"account_state": "active_member",
|
||
"tier_id": "premium", // optional, Account-Apps
|
||
"features": { "ai_calls": { "allowed", "used", "limit", "remaining", "reset_at" } },
|
||
"capabilities": { "analysis.run": { "allowed": true, "reason": null } }
|
||
},
|
||
"tenant": { // null wenn App keinen Tenant kennt
|
||
"tenant_id": 42,
|
||
"tenant_type": "club",
|
||
"plan_id": "pro",
|
||
"features": { ... },
|
||
"capabilities": { ... },
|
||
"roles": ["trainer"]
|
||
},
|
||
"enforcement": {
|
||
"capabilities": "enforce|probe",
|
||
"features": "enforce|probe"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Familien-Regel:** UI liest **nur** diesen Snapshot (oder domänenspezifische Teilmenge) — keine parallelen `/subscription/me` + `/features/usage` + Ad-hoc-Checks in neuen Apps.
|
||
|
||
### 5.2 Ist-API (bestehende Apps — Abweichung dokumentiert)
|
||
|
||
| App | Endpoint heute | Familien-Ziel |
|
||
|-----|----------------|---------------|
|
||
| **Mitai** | `/subscription/me`, `/features/usage`, `check_feature_access` | Snapshot schrittweise; Account-Block reicht |
|
||
| **Shinkan** | `GET /api/me/entitlements?club_id=` | Tenant-Block + Capabilities; Account-Tier fehlt bewusst |
|
||
|
||
Migration: **kein Big-Bang** — alte Endpoints als Facade auf Snapshot mappen.
|
||
|
||
### 5.3 Vier-Phasen-Rollout (familienweit verbindlich)
|
||
|
||
| Phase | Verhalten | Env-Beispiel |
|
||
|-------|-----------|--------------|
|
||
| **1** | Cleanup Legacy-Flags | — |
|
||
| **2** | **Probe** — JSON-Log, HTTP 200 | `*_ENFORCE=0` |
|
||
| **3** | Frontend-Gates aus Entitlements | — |
|
||
| **4** | **Enforce** — HTTP 403 | `*_ENFORCE=1` |
|
||
|
||
**Familien-Regel:** Phase 4 für **neue** kritische Features von Anfang an planbar; Bestands-Apps dürfen in Phase 2–3 bleiben bis kalibriert.
|
||
|
||
### 5.4 Enforcement-Priorität
|
||
|
||
1. **API** — autoritativ (`403`)
|
||
2. **Frontend** — UX (Badges, disabled Buttons)
|
||
3. **Niemals** — nur UI ohne API-Gate
|
||
|
||
---
|
||
|
||
## 6. Produkt-Profile & bewusste Abweichungen
|
||
|
||
Abweichungen vom Familien-Standard sind **zulässig**, wenn sie in der Tabelle **§6.2** stehen und begründet sind.
|
||
|
||
### 6.1 Profil-Matrix (Soll)
|
||
|
||
| Profil | Apps | Account-Limits | Tenant-Limits | Capabilities | Governance (Objekt) |
|
||
|--------|------|----------------|---------------|--------------|---------------------|
|
||
| **P1 Personal** | Mitai | ✅ primär | ❌ | ✅ Account | minimal / privat |
|
||
| **P2 Mandant** | Shinkan | ⚠️ Lifecycle only | ✅ primär | ✅ Account + Tenant-Rollen | ✅ Access Layer |
|
||
| **P3 Minimal** | Miken, Ikigai (geplant) | optional | ❌ | optional | minimal |
|
||
| **P4 Hybrid** | (Reserve) | ✅ | ✅ | ✅ beide | ✅ |
|
||
|
||
### 6.2 Registrierter Abweichungs-Katalog
|
||
|
||
| ID | App | Abweichung vom Familien-Standard | Begründung | Review |
|
||
|----|-----|----------------------------------|------------|--------|
|
||
| **DEV-01** | Mitai | Kein `tenant`-Block in Entitlements | Persönliche Tracking-App; kein Verein | Beibehalten (P1) |
|
||
| **DEV-02** | Mitai | Kein Capability-Katalog (nur Features+Tier) | RBAC = admin/user ausreichend | Optional später `account.*` Capabilities |
|
||
| **DEV-03** | Mitai | Mehrere Nutzer-APIs statt einem Snapshot | Historisch gewachsen | Facade → Snapshot (mittelfristig) |
|
||
| **DEV-04** | Mitai | Legacy Session-Spalten (`ai_enabled`, …) parallel Features | Migrationsschuld | Bereinigen, nicht in neue Apps |
|
||
| **DEV-05** | Shinkan | Kein Account-Tier / `profiles.tier` | Verein zahlt, nicht Trainer | Beibehalten (P2) |
|
||
| **DEV-06** | Shinkan | Capabilities **und** Governance (zwei Achsen) | Trainer vs. Objekt-Rechte | Familien-Vorbild für P2/P4 |
|
||
| **DEV-07** | Shinkan | `check_feature_access` (Mitai-Legacy) explizit verboten | Falsches Subjekt | Beibehalten |
|
||
| **DEV-08** | Shinkan | Enforcement oft Probe-only | Rollout-Sicherheit | → Phase 4 bis Datum X |
|
||
| **DEV-09** | Shinkan | Inventar-Features live gezählt | Drift-Vermeidung | Abweichung OK; in P2 dokumentieren |
|
||
| **DEV-10** | Beide | Kein atomares Check+Increment | Race bei Parallel-Requests | Familien-Backlog; Workaround dokumentieren |
|
||
| **DEV-11** | Neue Apps | dürfen **nur** Account **oder** nur Tenant wählen | MVP | Eintrag hier anlegen vor Launch |
|
||
|
||
**Neue Abweichung:** Zeile in §6.2 + ggf. ein Satz im App-`CLAUDE.md`.
|
||
|
||
### 6.3 Dokumentierte Ausnahmen (Bypass)
|
||
|
||
| Ausnahme | Apps | Regel |
|
||
|----------|------|-------|
|
||
| Plattform-Admin Audit | Shinkan | Quota-Bypass über Grants, nicht pauschal superadmin |
|
||
| Admin ohne Auto-Bypass | Mitai | Admins unterliegen Limits (Produktentscheid) |
|
||
| Öffentliche Routen ohne Auth | alle | Kein Entitlement-Check |
|
||
|
||
---
|
||
|
||
## 7. Mapping: Familien-Begriff ↔ Implementierung
|
||
|
||
### 7.1 Mitai (Profil P1)
|
||
|
||
| Familien | Mitai-Implementierung |
|
||
|----------|----------------------|
|
||
| Account-Features | `features`, `tier_limits`, `user_feature_usage` |
|
||
| Account-Tier | `get_effective_tier()`, `access_grants` |
|
||
| Check | `check_feature_access(profile_id, feature_id)` |
|
||
| Increment | `increment_feature_usage(profile_id, …)` |
|
||
| UI | `UsageBadge`, Widget `allowed` |
|
||
|
||
### 7.2 Shinkan (Profil P2)
|
||
|
||
| Familien | Shinkan-Implementierung |
|
||
|----------|-------------------------|
|
||
| Tenant-Features | `club_plan_limits`, `club_feature_usage`, `club_features.py` |
|
||
| Tenant-Plan | `get_effective_club_plan(club_id)` |
|
||
| Capabilities | `check_capability`, `capabilities` + `rights_registry` |
|
||
| Snapshot | `build_me_entitlements()` → `GET /me/entitlements` |
|
||
| Governance | `TenantContext`, `club_tenancy` — **kein** Ersatz für Capabilities |
|
||
|
||
### 7.3 Gemeinsame Muster (copy-ready)
|
||
|
||
| Muster | Mitai | Shinkan |
|
||
|--------|-------|---------|
|
||
| Feature-Registry in DB | ✅ | ✅ (`app='shinkan'`) |
|
||
| Plan × Feature Matrix | `tier_limits` | `club_plan_limits` |
|
||
| Admin-Override | `user_feature_restrictions` | `club_feature_overrides` |
|
||
| Promo/Trial | `access_grants` | `club_access_grants` |
|
||
| 4-Phasen-Rollout | ✅ | ✅ |
|
||
| Registry-first neue IDs | ⚠️ teils hardcoded | ✅ `rights_registrations/` |
|
||
|
||
---
|
||
|
||
## 8. Entscheidungsregeln für neue Produkte
|
||
|
||
### 8.1 Pflicht (alle Apps mit Auth)
|
||
|
||
- [ ] Session → `profile_id`; kein Client-Header als Autorität
|
||
- [ ] Entitlements-Auflösung **eine Funktion pro Ebene** (Capability, Feature)
|
||
- [ ] API-Enforcement vor UI-Gate
|
||
- [ ] 4-Phasen-Rollout dokumentiert
|
||
- [ ] Produkt-Profil (P1–P4) gewählt + Abweichungen in §6.2
|
||
|
||
### 8.2 Wenn Personal App (P1)
|
||
|
||
- [ ] Primäres Subjekt = Account
|
||
- [ ] `tenant`-Block in API = `null` (DEV-01-Analog)
|
||
- [ ] Feature-Registry + Tier-Matrix
|
||
|
||
### 8.3 Wenn Mandanten-App (P2)
|
||
|
||
- [ ] Primäres Subjekt = Tenant
|
||
- [ ] `TenantContext` + Governance getrennt von Capabilities
|
||
- [ ] Capabilities registry-first
|
||
- [ ] Account nur Lifecycle (verified, member) — kein Tier nötig (DEV-05-Analog erlaubt)
|
||
|
||
### 8.4 Wenn Minimal App (P3)
|
||
|
||
- [ ] Explizit: „keine Limits“ oder nur Boolean-Features — in §6.2 eintragen
|
||
- [ ] Kein halbes Mitai-v9c kopieren
|
||
|
||
---
|
||
|
||
## 9. Konvergenz-Roadmap (optional, nicht blockierend)
|
||
|
||
| Schritt | Mitai | Shinkan | Familie |
|
||
|---------|-------|---------|---------|
|
||
| **Kurz** | Legacy Session-Flags entfernen | `CAPABILITY_ENFORCE` / `CLUB_FEATURE_ENFORCE` Prod | DEV-04, DEV-08 schließen |
|
||
| **Mittel** | `/me/entitlements` Account-Block | Snapshot um `tenant`-Typ metadata erweitern | Facade alte APIs |
|
||
| **Lang** | Optional `tenant_id` reservieren (null) | Optional Account-Tier für Cross-Sell | Shared package `jinkendo_entitlements` |
|
||
| **Vision** | SSO + zentraler Billing | Vereins-Abo Stripe | `CENTRAL_SUBSCRIPTION_SYSTEM` |
|
||
|
||
**Wichtig:** Konvergenz ist **empfohlen**, nicht Pflicht — solange §6.2 aktuell bleibt.
|
||
|
||
---
|
||
|
||
## 10. Anti-Patterns (familienweit verboten)
|
||
|
||
1. Tier- oder Plan-Namen in React-Komponenten hardcoden
|
||
2. Limit-Logik nur im Frontend
|
||
3. Shinkan-Vereinslimits über Mitai `check_feature_access(profile_id)`
|
||
4. Capability-Check durch Governance ersetzen (oder umgekehrt)
|
||
5. Neue Feature-IDs nur in SQL-Migration ohne Registry
|
||
6. Enforcement Phase 4 „vergessen“ bei paid Features ohne dokumentierte Probe-Phase
|
||
7. Undokumentierte Produkt-Abweichung (nicht in §6.2)
|
||
|
||
---
|
||
|
||
## 11. Offene Familien-Entscheidungen (Backlog)
|
||
|
||
| ID | Frage | Optionen | Default wenn unentschieden |
|
||
|----|-------|----------|----------------------------|
|
||
| **FD-01** | Atomares check+increment | DB-Lock / Transaction / Queue | Status quo + Retry-Hinweis in Doku |
|
||
| **FD-02** | Shared Python-Modul | Monorepo-Paket vs. Copy+Sync | Copy+Sync mit gleicher API-Shape |
|
||
| **FD-03** | Capability-Namespace global | `jinkendo.*` vs. app-prefix | `{app}.{domain}.{action}` |
|
||
| **FD-04** | Mitai bekommt Capability-Layer? | ja/nein/später | nein (DEV-02) bis Bedarf |
|
||
| **FD-05** | Ein `features.app` für alle Apps | gemeinsame DB vs. pro Deploy | pro Deploy (heute) |
|
||
|
||
---
|
||
|
||
## 12. Verwandte Dokumente
|
||
|
||
| Dokument | Inhalt |
|
||
|----------|--------|
|
||
| [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) | Vollständiger Mitai ↔ Shinkan Abgleich |
|
||
| [design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md) | Shinkan Ist-Prinzipien |
|
||
| [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./design-principles/ACCESS_LAYER_DESIGN_PRINCIPLES.md) | Governance (Ebene D) |
|
||
| Mitai Foundation #3 | Feature & Entitlement Ist Mitai |
|
||
| Shinkan `CLUB_MEMBERSHIP_AND_FEATURES.v1.md` | Vereins-Abo Detail |
|
||
| Shinkan `CAPABILITY_CATALOG.v1.md` | Capability-IDs |
|
||
|
||
---
|
||
|
||
## 13. Changelog
|
||
|
||
| Datum | Änderung |
|
||
|-------|----------|
|
||
| 2026-07-04 | Entwurf: Familien-Standard, Produkt-Profile P1–P4, Abweichungs-Katalog DEV-01–11 |
|