# AP0.3 – Abschlussbericht Capability / Rights Registry & Entitlements Snapshot **Status:** abgeschlossen **Stand:** 2026-07-04 (final inkl. Prod-Deploy-Nacharbeit) **Branch:** `develop` · Dev-Deploy und Test Suite grün · **Prod verifiziert** (Schema `004`, Health ok) --- ## 1. Scope und Einordnung AP0.3 liefert die **minimale Capability-/Rights-Grundlage** und den **Entitlements-Snapshot** für Sprint 0. Auth, TenantContext und Sessions stammen aus AP0.2; AP0.3 ergänzt Registry, DB-Sync, zentrale Capability-Prüfung und `/api/me/entitlements`. | Anforderung (AP0.3) | Status | |---------------------|--------| | Migration Capabilities + Role-Grants | ✓ | | Runtime Registry + Modul-Registrierungen | ✓ | | Startup-Sync Registry → DB | ✓ | | TenantContext.capabilities | ✓ | | `require_capability()` Dependency | ✓ | | `GET /api/me/entitlements` | ✓ | | Beispiel-Endpoint mit Capability-Gate | ✓ | | Tests (Registry, Sync, Auflösung, Enforce/Probe) | ✓ | | Trennung Auth / Capability / Feature | ✓ | **Bewusst nicht in AP0.3:** Feature-Limits, Billing, Usage-Zähler, Prompt Registry, produktive Admin-UI, Governance/Object-ACL. --- ## 2. 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 | | `frontend/src/App.jsx` | Header AP0.3; `/api/me/context` zeigt Capabilities | | `README.md` | API-Doku AP0.3 | | `.gitea/workflows/deploy-prod.yml` | Backend-Logs bei `--wait`-Fehler (Parität zu Dev) | | `docs/DEPLOYMENT.md` | Abschnitt DB-Passwort Dev/Prod inkl. `ALTER USER`-Fix | **Wesentliche Commits:** `910b1d7` (Implementierung), `eaa0e25` (pytest-Fix), `4069cb0` (GUI-Sprint-Label), `39e8084` (Abschlussbericht v0.2). **Nacharbeit (noch auf `develop`):** `deploy-prod.yml`, `DEPLOYMENT.md`, dieser Bericht v0.3. --- ## 3. 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 (Vorbereitung AP0.4). --- ## 4. Registry-Struktur ``` backend/ ├── rights_registry.py ├── rights_registrations/ │ ├── __init__.py │ ├── platform.py # admin, context, entitlements │ └── tenant_ops.py # tenant.manage, actor.manage └── sync_rights_registry.py ``` **Modell:** `@dataclass(frozen=True) CapabilityRegistration` mit `key`, `module`, `description`, `default_grants`. **Startup:** `entrypoint.sh` → Migrationen → Seeds → `python sync_rights_registry.py` → Uvicorn (`SKIP_RIGHTS_SYNC=1` zum Überspringen). --- ## 5. Endpoints | Endpoint | Methode | Auth / Gate | Status | |----------|---------|-------------|--------| | `/api/me/context` | GET | Session | geändert — `capabilities[]` | | `/api/me/entitlements` | GET | Session | neu | | `/api/me/admin/demo` | GET | Session + `kairo.admin.access` | neu (Beispiel `require_capability`) | OpenAPI (Dev): `/api/docs` --- ## 6. Capability-Auflösungslogik ``` Session (portal_role, active_tenant_id) → tenant_role aus Membership (optional) → load_grants_for_roles(portal_role, tenant_role) → Union Portal-Grants + Tenant-Grants → TenantContext.capabilities (frozenset) ``` **`require_capability(key)`:** prüft Mitgliedschaft in `ctx.capabilities`. | Modus | Env | Verhalten | |-------|-----|-----------| | probe | `CAPABILITY_ENFORCE=probe` (Default) | Zugriff erlaubt; Verweigerung → Audit `capability.denied` | | enforce | `CAPABILITY_ENFORCE=enforce` | HTTP 403 ohne Grant | --- ## 7. Initiale Capabilities | 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` | ✓ | ✓ | ✓ | ✓ | ✓ | --- ## 8. Tests und Verifikation ### pytest (CI, Dev-Container) ```bash docker compose -f docker-compose.dev-env.yml exec backend python -m pytest tests -ra -vv ``` | Testdatei | Abdeckung | Status | |-----------|-----------|--------| | `test_rights_registry.py` | 5 Capabilities, Sync idempotent | ✓ | | `test_capabilities.py` | Admin/Member enforce, Owner-Grants, probe | ✓ | | `test_entitlements.py` | Snapshot-Struktur | ✓ | | `test_migrations.py` | Migration 004 | ✓ | | Gesamt Test Suite (Gitea) | nach Push `develop` | ✓ | ### Manuell (Dev-GUI) | Prüfung | Ergebnis | |---------|----------| | Login `lars@stommer.com` | ✓ | | `/api/me/context` → `capabilities` sichtbar | ✓ | | API Health → `"schema": "004"` | ✓ | | Header Sprint-Anzeige AP0.3 | ✓ | **Hinweis:** Entitlements und Admin-Demo sind in der GUI noch nicht als eigene Karten — prüfbar über Swagger (`/api/docs`) oder DevTools. ### Production (nach Nacharbeit 2026-07-04) | Prüfung | Ergebnis | |---------|----------| | `curl http://localhost:8004/api/health` | ✓ — `0.3.0-ap0.3`, Schema `004`, `db: ok` | | `curl http://localhost:3004/api/health` | ✓ | | Migration 004 auf Prod-Volume | ✓ (nach DB-Reconnect) | | Rights-Sync beim Start | ✓ | | Bootstrap-Admin (`.env`) | unverändert nutzbar | --- ## 9. Prod-Deploy-Nacharbeit (Gitea `deploy-prod` #7154) ### Symptom Push auf `main` → Workflow `deploy-prod` schlug fehl: ``` dependency failed to start: container kairo-api is unhealthy ``` Backend-Logs (Pi): ``` [FAIL] ... FATAL: password authentication failed for user "kairo_user" ``` ### Ursache **Kein AP0.3-Codefehler.** PostgreSQL initialisiert User/Passwort nur beim **ersten Start** des Volumes (`kairo-db-data`). Das Passwort in `/home/lars/docker/kairo/.env` wich vom in der DB gespeicherten Passwort ab — identisches Muster wie beim Dev-Deploy (#7100). Der Entrypoint bricht bei DB-Auth-Fehlern fail-fast ab (seit AP0.2/`f8b3ae3`); Uvicorn startet nicht → Healthcheck scheitert nach wenigen Sekunden. ### Behebung (Prod, ohne Datenverlust) ```bash cd /home/lars/docker/kairo set -a && source .env && set +a docker compose exec -T postgres psql -U kairo_user -d kairo \ -c "ALTER USER kairo_user WITH PASSWORD '${DB_PASSWORD}';" docker compose restart backend docker compose up -d --wait ``` Danach: alle Container `healthy`, API und Frontend-Proxy antworten. ### Prävention / Doku | Maßnahme | Datei | |----------|-------| | Prod-Fix ohne Volume-Löschung dokumentiert | `docs/DEPLOYMENT.md` § Datenbank-Passwort | | Backend-Logs bei `compose up --wait`-Fehler | `.gitea/workflows/deploy-prod.yml` (wie Dev) | **Wichtig:** `docker compose down -v` auf Prod löscht alle Anwendungsdaten. Bei Passwort-Wechsel in `.env` bevorzugt `ALTER USER` verwenden. --- ## 10. Deployment & Betrieb | | Development | Production | |---|-------------|------------| | Verzeichnis | `/home/lars/docker/kairo-dev` | `/home/lars/docker/kairo` | | Ports | 3097 / 8097 | 3004 / 8004 | | Postgres | eigener Container + Volume | eigener Container + Volume (`kairo-db-data`) | | Dev-Seeds | ja | nein | | Admin | `lars@stommer.com` (Seed) | `KAIRO_BOOTSTRAP_*` in `.env` | | Schema nach AP0.3 | `004` | `004` | **Startup-Reihenfolge:** Entrypoint → Schema-Migrationen → Data-Seeds → Rights-Sync → Uvicorn. --- ## 11. Ü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 | `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-/Trainingsrechte, Club-Feature-Kontingente. --- ## 12. Übernommene Muster aus Mitai | Muster | Kairo-Umsetzung | |--------|-----------------| | Entitlements als zentrale Schicht | `build_entitlements_snapshot()` | | Probe-vs-Enforce-Denken | Default `probe`, optional `enforce` | | Feature-Registry vorbereitet | `features: {}` im Snapshot | **Nicht übernommen:** Tier/Subscription, Usage-Zähler, Billing, Legacy `check_feature_access`. --- ## 13. Bewusst nicht übernommen - Shinkan-/Mitai-Domänenbegriffe (`club`, `profile`, Tier) - Feature-Limits, Billing, Coupons - Prompt Registry, Vorhaben-/Projektlogik - MCP, produktive Admin-UI (nur Debug-JSON + Swagger) - Capabilities nur in SQL pflegen - Governance/Object-ACL --- ## 14. Abweichungen von Designprinzipien | Thema | Abweichung | Begründung | |-------|------------|------------| | Entitlements-Struktur | Account- + Tenant-Block | Kairo Hybrid laut Family Entitlement Model | | Feature-Registry | leeres Objekt | AP0.4 | | Grant-Overrides | Sync nur additive Grants | Sprint-0-Minimal | | `linked_feature_id` | nicht modelliert | Keine Limits in AP0.3 | | Frontend | kein Entitlements-Panel | Minimal-UI; AP0.4/UX optional | **Eingehalten:** zentrale Capability-Prüfung; Portal- vs. Tenant-Rolle getrennt; TenantContext als Auflösungsschicht. --- ## 15. Offene Entscheidungen 1. **Prod `CAPABILITY_ENFORCE=enforce`** — wann umstellen? 2. **Grant-Overrides in DB** vs. reiner Code-Kanon 3. **Prod-pytest-Cleanup** (`*@example.com`) — aus AP0.2 offen 4. **Frontend:** Entitlements-Karte + Admin-Demo-Button 5. **Feature-Registry** — AP0.4 --- ## 16. Empfehlung für AP0.4 Laut Foundation **AP0.4 – Prompt, Feature, Config Registry**: - Feature Registry (Metadaten, ohne Billing-Limits in Sprint 0) - PromptTemplate / PromptVersion / Placeholder - ConfigurationEntry - Prompt-Rendering mit Placeholder-Validation - `features`-Block in Entitlements mit Registry-Sync Optional vor AP0.4: Prod-Cleanup-Seed; GUI-Entitlements; `CAPABILITY_ENFORCE=enforce` in Prod nach Kalibrierung. --- ## Referenzen - `docs/sprints/Jinkendo_Kairo_04_Sprint0_Foundation_v0.3.md` § AP0.3, §9 - `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` - `docs/DEPLOYMENT.md` — DB-Passwort Dev/Prod - Vorgänger: `docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md`, `Sprint0_AP0_3_Completion_Report_v0.2.md` --- *Abgeschlossen im Rahmen Sprint 0 – AP0.3. Ersetzt `Sprint0_AP0_3_Completion_Report_v0.2.md`.*