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