Document cross-app architecture patterns, Mitai alignment, and family entitlement standards. Documentation only; no runtime changes. Co-authored-by: Cursor <cursoragent@cursor.com>
14 KiB
Familien-Modell: Entitlements & Limits
Status: Entwurf / verbindliche Zielrichtung (mit bewussten Produkt-Ausnahmen)
Stand: 2026-07-04
Bezüge:
- DESIGN_PRINCIPLES_ALIGNMENT.md — Abgleich Mitai ↔ Shinkan
- Mitai: FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md
- Shinkan: 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:
- Account-Lifecycle — z. B. E-Mail verifiziert, Onboarding abgeschlossen
- Capability(B) — Rolle darf Funktion (Account- und/oder Tenant-Rollen)
- Feature(C) — Kontingent am primären Billing-Subjekt der App (siehe Produkt-Profil)
- 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.
NULLLimit = 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
- API — autoritativ (
403) - Frontend — UX (Badges, disabled Buttons)
- 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)
- Tier- oder Plan-Namen in React-Komponenten hardcoden
- Limit-Logik nur im Frontend
- Shinkan-Vereinslimits über Mitai
check_feature_access(profile_id) - Capability-Check durch Governance ersetzen (oder umgekehrt)
- Neue Feature-IDs nur in SQL-Migration ohne Registry
- Enforcement Phase 4 „vergessen“ bei paid Features ohne dokumentierte Probe-Phase
- 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 | Vollständiger Mitai ↔ Shinkan Abgleich |
| design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md | Shinkan Ist-Prinzipien |
| 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 |