# Kairo Tenant-Invarianten v0.1 **Status:** verbindlich für Sprint 0 / AP0.7+ **Stand:** 2026-07-05 --- ## Zweck Dieses Dokument legt Mandanten-Invarianten für Kairo fest, damit fachliche Module tenant-sicher bleiben und Cross-Tenant-Leaks vermieden werden. Bei Abweichungen: Architecture Decision Proposal. --- ## Invarianten | # | Invariante | Umsetzung in Kairo | |---|------------|-------------------| | 1 | Jede fachliche Tabelle hat `tenant_id`, sofern nicht global | `initiatives`, `actions`, `action_assignments`, `actors` — alle mit `tenant_id` | | 2 | `tenant_id` kommt aus TenantContext, nicht aus Client-Body | Router nutzen `ctx.tenant_id` aus `require_tenant_context` / `require_capability` | | 3 | Jede fachliche Query filtert nach `tenant_id` | Services und Data Layer: `WHERE tenant_id = %s` | | 4 | Fremde Objekt-IDs → `404`, nicht `403` | Initiatives, Actions, Actors: Cross-Tenant-Zugriff liefert 404 | | 5 | Actor-Zuweisungen nur im selben Tenant | `_actor_in_tenant()` in Services; Assignment-Tests | | 6 | User ≠ Actor | Human Actor verknüpft via `actors.user_id`; Assignments an `actor_id` | | 7 | Agenten/Arbeitsgruppen/externe Systeme sind tenant-scoped Actors | `actors.tenant_id` + `actor_type` | | 8 | Audit Events enthalten mindestens `tenant_id` | `log_audit(..., tenant_id=...)` | | 9 | Neue fachliche Tabellen: explizite Tenant-Entscheidung | Nummerierte Migration + Doku-Ergänzung | | 10 | Router ohne eigene Mandantenlogik | Delegation an Services (Write) und Data Layer (Read-Aggregation) | --- ## Geprüfte Bereiche (AP0.7) | Bereich | Ergebnis | |---------|----------| | `initiatives` CRUD | ✓ tenant_id aus Context | | `actions` CRUD | ✓ tenant_id aus Context | | `action_assignments` | ✓ tenant_id + Actor-Validierung | | `actors` Directory | ✓ nur aktiver Tenant | | `/api/actions/me/open` | ✓ via Data Layer, actor-scoped | | `/api/workspace/*` | ✓ Data Layer, tenant-scoped | | Cross-Tenant Tests | ✓ `test_initiatives_actions`, `test_ap07` | --- ## Anti-Patterns (verboten) - `tenant_id` aus Request-Body übernehmen ohne Membership-Prüfung - Listen ohne `tenant_id`-Filter - Cross-Tenant-Existenz via 403 verraten - User-ID direkt in Assignments statt Actor-ID - Aggregations-SQL in Routern - Frontend-Widgets mit fachlicher KPI-Berechnung statt Data-Layer-Endpoints --- ## Referenzen - `docs/architecture/Kairo_Sprint0_Principle_Gate_v0.1.md` (G-01, G-02, G-03) - Shinkan: Access Layer / tenant-sichere Queries - AP0.7 Abschlussbericht: `docs/sprints/Sprint0_AP0_7_Completion_Report_v0.1.md`