All checks were successful
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 42s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 12s
Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
2.5 KiB
Markdown
63 lines
2.5 KiB
Markdown
# 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`
|