# AP0.3 – Abschlussbericht Capability / Rights Registry & Entitlements Snapshot **Status:** abgeschlossen **Stand:** 2026-07-04 **Branch:** `develop` --- ## 1. Umgesetzte Dateien | Datei | Zweck | |-------|--------| | `backend/migrations/004_capabilities_registry.sql` | Tabellen `capabilities`, `role_capability_grants` | | `backend/rights_registry.py` | In-Memory-Registry, Validierung, DB-Sync, Grant-Lookup | | `backend/rights_registrations/__init__.py` | Side-Effect-Import aller Modul-Registrierungen | | `backend/rights_registrations/platform.py` | Platform-Capabilities | | `backend/rights_registrations/tenant_ops.py` | Tenant-/Actor-Capabilities | | `backend/capabilities.py` | Auflösung, `check_capability`, `require_capability` | | `backend/entitlements.py` | Entitlements-Snapshot-Builder | | `backend/sync_rights_registry.py` | CLI-Sync beim Container-Start | | `backend/tenant_context.py` | `TenantContext.capabilities` | | `backend/routers/me.py` | `/entitlements`, `/admin/demo` | | `backend/entrypoint.sh` | Rights-Sync nach Seeds | | `backend/version.py` | `0.3.0-ap0.3`, Schema `004` | | `backend/tests/test_rights_registry.py` | Registry + Sync | | `backend/tests/test_capabilities.py` | Grants, enforce/probe, Demo-Endpoint | | `backend/tests/test_entitlements.py` | Snapshot-Form | | `backend/tests/conftest.py` | Registry-Sync in Test-Session | | `README.md` | API-Doku AP0.3 | --- ## 2. Neue Migrationen **`004_capabilities_registry.sql`** - **`capabilities`** — `capability_key`, `module`, `description`, `is_active` - **`role_capability_grants`** — `role_scope` (`portal` \| `tenant`), `role_code`, `capability_key` Kein Feature-/Limit-Schema in AP0.3 (bewusst AP0.4-Vorbereitung). --- ## 3. Registry-Struktur ``` backend/ ├── rights_registry.py # register_capability(), sync_rights_registry_to_db() ├── rights_registrations/ │ ├── __init__.py # import platform, tenant_ops │ ├── platform.py # admin, context, entitlements │ └── tenant_ops.py # tenant.manage, actor.manage └── sync_rights_registry.py # Startup nach Migrationen/Seeds ``` **Registrierungsmodell:** `@dataclass(frozen=True) CapabilityRegistration` mit `key`, `module`, `description`, `default_grants: (role_scope, role_code)`. **Startup:** `entrypoint.sh` → `python sync_rights_registry.py` (überspringbar via `SKIP_RIGHTS_SYNC=1`). --- ## 4. Endpoints | Endpoint | Methode | Auth / Gate | Neu/Geändert | |----------|---------|-------------|--------------| | `/api/me/context` | GET | Session | **Geändert** — enthält `capabilities[]` | | `/api/me/entitlements` | GET | Session | **Neu** | | `/api/me/admin/demo` | GET | Session + `kairo.admin.access` | **Neu** (Beispiel `require_capability`) | Bestehende Auth-/Me-Endpunkte unverändert in Signatur. --- ## 5. Capability-Auflösungslogik ``` Session (portal_role, active_tenant_id) → tenant_membership → tenant_role (optional) → load_grants_for_roles(portal_role, tenant_role) SELECT capability_key FROM role_capability_grants JOIN capabilities WHERE role_scope/role_code match → Union Portal-Grants + Tenant-Grants → TenantContext.capabilities (frozenset) ``` **`require_capability(key)`:** prüft `key in ctx.capabilities`. | Modus | Env | Verhalten | |-------|-----|-----------| | probe | `CAPABILITY_ENFORCE=probe` (Default) | Zugriff erlaubt, Audit `capability.denied` | | enforce | `CAPABILITY_ENFORCE=enforce` | HTTP 403 bei fehlendem Grant | --- ## 6. Initiale Capabilities & Default-Grants | Capability | Portal admin | Portal user | Tenant owner | Tenant admin | Tenant member | |------------|:------------:|:-----------:|:------------:|:------------:|:-------------:| | `kairo.admin.access` | ✓ | | | | | | `kairo.tenant.manage` | ✓ | | ✓ | ✓ | | | `kairo.actor.manage` | ✓ | | ✓ | ✓ | | | `kairo.context.read` | ✓ | ✓ | ✓ | ✓ | ✓ | | `kairo.entitlements.read` | ✓ | ✓ | ✓ | ✓ | ✓ | --- ## 7. Tests und Testergebnis ```bash docker compose -f docker-compose.dev-env.yml exec backend pip install -r requirements-dev.txt docker compose -f docker-compose.dev-env.yml exec backend python -m pytest tests -ra -vv ``` | Testdatei | Abdeckung | |-----------|-----------| | `test_rights_registry.py` | 5 Capabilities registriert, Sync idempotent, DB-Zeilen | | `test_capabilities.py` | Admin erlaubt, Member verweigert (enforce), Owner-Grants, probe-Modus | | `test_entitlements.py` | Snapshot account/tenant/actor/roles/capabilities/enforcement | | `test_migrations.py` | Migration 004 erkannt | *(Lokale Ausführung in dieser Session über CI/Dev-Container nach Push.)* --- ## 8. Übernommene Muster aus Shinkan | Muster | Kairo-Umsetzung | |--------|-----------------| | Registry-first | `rights_registry.py` + `rights_registrations/` | | `register_capability()` mit Validierung | Pflichtfelder `key`, `module`, `description` | | Frozen Dataclass-Definitionen | `CapabilityRegistration` | | Startup-Sync Registry → DB | `sync_rights_registry_to_db()` | | Modul-Ownership (`module`-Feld) | `platform`, `tenant` | | Default Grants in Code | `default_grants` pro Capability | | `require_capability` Dependency | `capabilities.py` | | `/api/me/entitlements` Snapshot | `entitlements.py` | | Probe vs. Enforce | `CAPABILITY_ENFORCE` | **Nicht übernommen:** `club_id`, Vereinsrollen, Übungs-/Trainings-Capabilities, Club-Feature-Kontingente, `club_quota_bypass`. --- ## 9. Übernommene Muster aus Mitai | Muster | Kairo-Umsetzung | |--------|-----------------| | Entitlements als zentrale Auflösungsschicht | `build_entitlements_snapshot()` | | Probe-vs-Enforce-Denken | Default `probe`, optional `enforce` | | Feature-Registry-Idee vorbereitet | `features: {}` im Snapshot, Enforcement `probe` | **Nicht übernommen:** Tier/Subscription, Usage-Zähler, `check_feature_access`-Legacy, Account-Tier-Limits. --- ## 10. Bewusst nicht übernommen - Shinkan-/Mitai-Domänenbegriffe (`club`, `profile`, Tier) - Feature-Limits, Billing, Coupons, Usage-Zähler - Prompt Registry, Vorhaben-/Projektlogik - MCP, produktive Admin-UI - Capabilities nur in SQL-Migration pflegen - Governance/Object-ACL (AP später) --- ## 11. Abweichungen von Designprinzipien | Thema | Abweichung | Begründung | |-------|------------|------------| | Entitlements-Struktur | flache + verschachtelte Blöcke | Kairo Hybrid: Account + Tenant laut Family Model | | Feature-Registry | leeres Objekt | AP0.4-Scope | | Admin-Grant-Overrides in DB | Sync fügt nur hinzu (`ON CONFLICT DO NOTHING`) | Sprint-0-Minimal; kein Admin-UI für Overrides | | `linked_feature_id` | nicht modelliert | Keine Feature-Limits in AP0.3 | **Eingehalten:** Auth / Capability / Feature getrennt; Prüfung zentral; Portal- vs. Tenant-Rolle getrennt; TenantContext als Auflösungsschicht. --- ## 12. Offene Entscheidungen 1. **Prod `CAPABILITY_ENFORCE`** — Default `probe`; wann auf `enforce` umstellen? 2. **Grant-Overrides** — Admin bearbeitet Grants in DB vs. Re-Sync aus Code 3. **Prod-pytest-Cleanup** für `*@example.com` (aus AP0.2) 4. **Feature-Registry** — Modell und Sync in AP0.4 5. **Frontend** — Entitlements-gestütztes UI-Gating statt Debug-JSON --- ## 13. Empfehlung für AP0.4 Laut Foundation-Dokument **AP0.4 – Prompt, Feature, Config Registry**: - Feature Registry (Metadaten, ohne Limits in Sprint 0) - PromptTemplate / PromptVersion / Placeholder - ConfigurationEntry - Einfaches Prompt-Rendering mit Placeholder-Validation - `features`-Block in Entitlements mit Registry-Sync (ohne Billing) Optional vor AP0.4: Prod-Cleanup-Seed für pytest-Artefakte; Frontend zeigt `/api/me/entitlements`. --- ## Referenzen - `docs/sprints/Jinkendo_Kairo_04_Sprint0_Foundation_v0.3.md` § AP0.3, §9 Entitlements - `docs/reference/design-principles/shinkan/RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md` - `docs/reference/design-principles/shinkan/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md` - `docs/reference/design-principles/alignment/FAMILY_ENTITLEMENT_MODEL.md` - Vorgänger: `docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md` --- *Abgeschlossen im Rahmen Sprint 0 – AP0.3.*