# AP0.2 – Abschlussbericht Auth, Identity, Tenant & Actor Foundation **Status:** abgeschlossen **Stand:** 2026-07-04 (final) **Branch:** `develop` · Prod-Deploy auf `main` erfolgt und stabil --- ## 1. Scope und Einordnung AP0.2 liefert die **Auth-, Identity-, Tenant- und Actor-Grundlage** für Kairo. Gegenüber dem ursprünglichen Foundation-Dokument (`Jinkendo_Kairo_04_Sprint0_Foundation_v0.3.md`) wurde der für AP0.3 vorgesehene **Auth-/TenantContext-Teil bereits in AP0.2** umgesetzt. | Anforderung (AP0.2 / erweitert) | Status | |----------------------------------|--------| | Tenant, User, Membership | ✓ | | Actor (human, agent, working_group, external_system) | ✓ | | Server-Sessions, Login/Logout | ✓ | | TenantContext + Tenant-Wechsel | ✓ | | Portal-Rolle vs. Tenant-Rolle getrennt | ✓ | | Seed für Admin (Env + Erstregistrierung + Dev-Seed) | ✓ | | Audit bei Auth-Aktionen | ✓ | | Frontend Login/Register (minimal) | ✓ | | Idempotentes Data-Seed-System | ✓ (Erweiterung) | **Bewusst nicht in AP0.2:** Capabilities/Rights Registry, Rate-Limiting, Tenant-Admin-API, Passwort-Reset. --- ## 2. Umgesetzte Artefakte ### Backend – Schema & Migrationen | Datei | Zweck | |-------|--------| | `backend/migrations/002_auth_identity_tenant_actor.sql` | User, Session, Tenant, Membership, Actor, Audit | | `backend/migrations/003_data_seeds_tracking.sql` | Tabelle `data_seeds` für Seed-Tracking | | `backend/run_migrations.py` | Schema-Migrationen (`schema_migrations`) | | `backend/run_seeds.py` | Data-Seeds (Checksum, Dev-Seeds bei jedem Start) | | `backend/entrypoint.sh` | Migrationen + Seeds vor Uvicorn-Start | ### Backend – Domäne & Services | Datei | Zweck | |-------|--------| | `backend/auth.py` | bcrypt, Sessions, `require_auth`, `require_portal_admin` | | `backend/tenant_context.py` | `TenantContext`, `get_tenant_context`, `require_tenant_context` | | `backend/bootstrap.py` | Env-Bootstrap (`KAIRO_BOOTSTRAP_*`) | | `backend/services/registration.py` | Erstregistrierung, `provision_system_admin` | | `backend/services/dev_admin.py` | Dev-Admin sicherstellen (nur Nicht-Prod) | | `backend/services/actors.py` | Actor-Erzeugung, Human-Lookup | | `backend/services/audit.py` | Audit-Log | ### Backend – API | Datei | Zweck | |-------|--------| | `backend/routers/auth.py` | Login, Logout, Register, Setup-Status | | `backend/routers/me.py` | `/api/me`, `/api/me/context`, Tenant-Wechsel | | `backend/main.py` | Router, Startup (Fallback ohne Entrypoint) | ### Data-Seeds | Seed | Umgebung | Zweck | |------|----------|--------| | `seed_001_cleanup_pytest_artifacts.dev.sql` | Dev | Entfernt `*@example.com`, verwaiste Test-Tenants | | `seed_002_bootstrap_admin.py` | Dev + Prod | Admin aus `KAIRO_BOOTSTRAP_*` wenn DB leer | | `seed_003_ensure_dev_admin.dev.py` | Dev | Stellt `lars@stommer.com` als Portal-Admin sicher | Doku: `docs/MIGRATIONS.md` ### Frontend | Datei | Zweck | |-------|--------| | `frontend/src/App.jsx` | Login/Register-Tabs, Session-Anzeige, Setup-Status | | `frontend/src/app.css` | Auth-UI, Tabs, Hinweise | ### Tests | Datei | Abdeckung | |-------|-----------| | `test_auth.py` | Login, Logout, Session, `/api/me`, Context, Tenant-Wechsel | | `test_tenant_actor.py` | Actor-Typen, Portal- vs. Tenant-Rolle | | `test_registration.py` | Erstregistrierung, Setup-Status | | `test_seeds.py` | Seed-Runner, Cleanup, Dev-Admin | | `test_migrations.py` | Migrationen 001–003, Idempotenz | ### Infrastruktur & Doku | Datei | Zweck | |-------|--------| | `docker-compose.dev-env.yml`, `docker-compose.yml` | Postgres pro Stack, Bootstrap/Session-Env, Healthcheck | | `backend/Dockerfile` | Entrypoint für Startup-Reihenfolge | | `.gitea/workflows/deploy-dev.yml` | Deploy Dev + Logs bei Fehler | | `.gitea/workflows/test.yml` | pytest + Seed-Cleanup nach CI | | `README.md`, `docs/DEPLOYMENT.md` | Local Dev, Auth, DB-Volume-Wechsel | **Version:** `APP_VERSION = 0.2.0-ap0.2`, `DB_SCHEMA_VERSION = 003` --- ## 3. Datenmodell (Migration 002) - **`users`** — E-Mail, bcrypt-Hash, `portal_role` (`user` \| `admin`) - **`sessions`** — opaque Token, `user_id`, `active_tenant_id`, Ablauf - **`tenants`** — Slug (unique), Name, aktiv - **`tenant_memberships`** — `tenant_role` (`owner` \| `admin` \| `member`) - **`actors`** — `human`, `agent`, `working_group`, `external_system`; Human verknüpft mit `user_id` - **`audit_log`** — Auth-Ereignisse (JSONB-Details) --- ## 4. API-Endpunkte | Endpoint | Methode | Auth | Beschreibung | |----------|---------|------|--------------| | `/api/auth/setup-status` | GET | — | `registration_open`, `has_users`, `user_count` | | `/api/auth/register` | POST | — | Erster User → Portal-Admin (nur leere DB) | | `/api/auth/login` | POST | — | E-Mail + Passwort → Session-Token | | `/api/auth/logout` | POST | `X-Auth-Token` | Session löschen | | `/api/me` | GET | `X-Auth-Token` | User + Tenant-Liste | | `/api/me/context` | GET | `X-Auth-Token` | TenantContext (Tenant + Human Actor) | | `/api/me/context/required` | GET | `X-Auth-Token` | Wie Context, 403 ohne aktiven Tenant | | `/api/me/tenant` | POST | `X-Auth-Token` | Aktiven Tenant wechseln (nur Memberships) | OpenAPI (Dev): `/api/docs` --- ## 5. Auth-Fluss ``` POST /api/auth/login { email, password } → bcrypt verify → INSERT sessions (token, expires_at, active_tenant_id = erste Membership) → audit: auth.login → Response: { token, expires_at, user } Request mit Header X-Auth-Token → get_session(token) JOIN users → require_auth → session (user_id aus DB, nie aus Client-Body) POST /api/auth/logout → DELETE session → audit: auth.logout ``` **Ersteinrichtung (Priorität):** 1. **Dev:** Seed `seed_003` — `lars@stommer.com` (Portal-Admin, bei jedem Start) 2. **Prod/Dev:** Seed `seed_002` — `KAIRO_BOOTSTRAP_*` wenn DB leer 3. **UI:** `POST /api/auth/register` — nur wenn `user_count == 0` --- ## 6. TenantContext ``` require_auth → session (user_id, active_tenant_id, portal_role) → tenant_memberships + tenants (nur aktiv) → human actor: actors WHERE tenant_id + user_id + type = human → TenantContext(portal_role, tenant_role, tenant, actor) ``` Tenant-Wechsel: `POST /api/me/tenant { tenant_id }` — nur bei gültiger Membership. --- ## 7. Deployment & Betrieb | | Development | Production | |---|-------------|------------| | Verzeichnis | `/home/lars/docker/kairo-dev` | `/home/lars/docker/kairo` | | Ports | 3097 / 8097 | 3004 / 8004 | | Postgres | Eigener Container + Volume pro Stack | Eigener Container + Volume | | Dev-Seeds | Ja (Cleanup + Dev-Admin) | Nein (`.dev.*` übersprungen) | | Admin-Zugang | `lars@stommer.com` (Seed) | `KAIRO_BOOTSTRAP_*` in `.env` | **Startup-Reihenfolge:** Entrypoint → Schema-Migrationen → Data-Seeds → Uvicorn. **DB-Zugangsdaten ändern:** Volume neu anlegen (`docker compose down -v`) — siehe `docs/DEPLOYMENT.md`. **Verifikation (2026-07-04):** Dev und Prod stabil nach Deploy; Dev-DB-Wechsel mit frischem Volume erfolgreich. --- ## 8. Tests & CI ```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 ``` | Bereich | Status | |---------|--------| | pytest-backend (Dev/Prod im Container) | ✓ | | compose-smoke (PR, isolierte Ports) | ✓ | | k6 Health-Baseline | ✓ | | Playwright smoke | ✓ | | Seed-Cleanup nach pytest (Dev) | ✓ | **Hinweis Betrieb:** pytest gegen deployte Instanz erzeugt `*@example.com`-User. Dev-Seed räumt auf; auf Prod bleiben Test-User bestehen (Cleanup-Seed läuft dort nicht). Prod-DB bei Bedarf manuell prüfen. --- ## 9. Abweichungen von Designprinzipien | Thema | Kairo AP0.2 | Begründung | |-------|-------------|------------| | Mitai `profiles` | `users` + separate `actors` | User ≠ Actor, kein Multi-Profil-Legacy | | Passwort-Hash | nur bcrypt | Grüne Wiese | | Query-Token / SSE | nicht implementiert | Später | | Capabilities in TenantContext | fehlen | AP0.3 | | Zentrale Postgres-Instanz | je Stack eigener Container | Isolation wie Shinkan/Mitai | **Eingehalten:** Server-Sessions, `X-Auth-Token`, `Depends(require_auth)`, Portal- vs. Tenant-Rolle, TenantContext-Schicht, nummerierte Migrationen. --- ## 10. Offene Punkte (nach AP0.2) 1. **Rate-Limiting / Passwort-Policy** für Login 2. **Passwort-Reset** + Session-Invalidierung 3. **Tenant-/User-Verwaltung per API** (Admin-Routen) 4. **Prod-pytest-Cleanup** — optional Seed für `*@example.com` auch in Prod 5. **Frontend** — produktive Shell statt Debug-JSON (UX, AP0.3+) --- ## 11. Empfehlung AP0.3 Gemäß Foundation-Dokument: - **Capability / Rights Registry** (DB + Runtime-Sync) - **`require_capability()`** als FastAPI-Dependency - **TenantContext** um `capabilities: list[str]` erweitern - Keine Feature-Limits / Billing in Sprint 0 --- ## 12. Referenzen - Assignment-Kontext: `docs/sprints/Jinkendo_Kairo_04_Sprint0_Foundation_v0.3.md` § AP0.2 - Vorgänger: `docs/sprints/Sprint0_AP0_1_Completion_Report_v0.1.md` - Migrationen/Seeds: `docs/MIGRATIONS.md` - Deployment: `docs/DEPLOYMENT.md` --- *Abgeschlossen im Rahmen Sprint 0 – AP0.2. Ersetzt `Sprint0_AP0_2_Completion_Report_v0.1.md`.*