diff --git a/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.1.md b/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.1.md deleted file mode 100644 index abe0a91..0000000 --- a/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.1.md +++ /dev/null @@ -1,154 +0,0 @@ -# AP0.2 – Abschlussbericht Auth, Identity, Tenant & Actor Foundation - -**Status:** abgeschlossen (Implementierung) -**Stand:** 2026-07-04 -**Branch:** `develop` (noch nicht auf `main` gemergt) - ---- - -## 1. Umgesetzte Dateien - -| Datei | Zweck | -|-------|--------| -| `backend/migrations/002_auth_identity_tenant_actor.sql` | Schema User, Session, Tenant, Membership, Actor, Audit | -| `backend/auth.py` | bcrypt, Sessions, login/logout, `require_auth`, `require_portal_admin` | -| `backend/tenant_context.py` | `TenantContext`, `get_tenant_context`, `require_tenant_context` | -| `backend/bootstrap.py` | Env-basierter Admin/Tenant/ Actor-Seed | -| `backend/services/audit.py` | Audit-Log für Auth-Aktionen | -| `backend/services/actors.py` | Actor-Erzeugung + Human-Lookup | -| `backend/routers/auth.py` | Login/Logout | -| `backend/routers/me.py` | `/api/me`, `/api/me/context`, Tenant-Wechsel | -| `backend/main.py` | Router, Bootstrap nach Migrationen | -| `backend/tests/conftest.py` | DB-Fixtures | -| `backend/tests/factories.py` | Testdaten | -| `backend/tests/test_auth.py` | Login, Logout, Session, Context | -| `backend/tests/test_tenant_actor.py` | Actor-Typen, Rollen-Trennung | -| `backend/version.py` | `0.2.0-ap0.2`, Schema `002` | -| `docker-compose.dev-env.yml`, `docker-compose.yml` | Bootstrap/Session-Env | -| `.env.example`, `README.md` | Doku | - ---- - -## 2. Neue Migrationen - -- **`002_auth_identity_tenant_actor.sql`** - - `users` — E-Mail, bcrypt-Hash, `portal_role` (`user` \| `admin`) - - `sessions` — Token, `user_id`, `active_tenant_id`, Ablauf - - `tenants` — Slug, Name, aktiv - - `tenant_memberships` — `tenant_role` (`owner` \| `admin` \| `member`) - - `actors` — `human`, `agent`, `working_group`, `external_system` - - `audit_log` — Auth-Ereignisse - ---- - -## 3. Neue Endpoints - -| Endpoint | Methode | Auth | -|----------|---------|------| -| `/api/auth/login` | POST | — | -| `/api/auth/logout` | POST | `X-Auth-Token` | -| `/api/me` | GET | `X-Auth-Token` | -| `/api/me/context` | GET | `X-Auth-Token` | -| `/api/me/context/required` | GET | `X-Auth-Token` + aktiver Tenant | -| `/api/me/tenant` | POST | `X-Auth-Token` | - -OpenAPI: `/api/docs` (Dev) - ---- - -## 4. Auth-Fluss - -``` -POST /api/auth/login { email, password } - → bcrypt verify - → INSERT sessions (opaque 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 dict (user_id aus DB, nie aus Client-Header) - -POST /api/auth/logout - → DELETE session - → audit: auth.logout -``` - ---- - -## 5. TenantContext-Auflösung - -``` -require_auth → session (user_id, active_tenant_id, portal_role, …) - → tenant_memberships + tenants prüfen (nur aktive) - → human actor: actors WHERE tenant_id + user_id + type=human - → TenantContext( - portal_role, # Plattform - tenant_role, # Mandant - tenant_id/slug/name, - actor_id/type - ) -``` - -Tenant-Wechsel: `POST /api/me/tenant` aktualisiert `sessions.active_tenant_id` nur bei gültiger Membership. - ---- - -## 6. Tests und Testergebnis - -| Testdatei | Abdeckung | -|-----------|-----------| -| `test_auth.py` | Login, Logout, Session ungültig, `/api/me`, Context, Tenant-Wechsel verweigert | -| `test_tenant_actor.py` | Human↔User, Agent/WG/External ohne User, Portal- vs. Tenant-Rolle | -| `test_migrations.py` | Migration 002 erkannt + idempotent | - -Lokal ausführen (Backend-Container): - -```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 -``` - -*(In dieser Session kein Docker lokal — Verifikation über CI nach Push auf `develop`.)* - ---- - -## 7. Abweichungen von den Designprinzipien - -| Prinzip | Abweichung | Begründung | -|---------|------------|------------| -| Mitai `profiles` | Kairo nutzt `users` | Klarere Trennung User ≠ Actor; kein Multi-Profil-Legacy | -| Legacy SHA256-Upgrade | nur bcrypt | Grüne Wiese AP0.2 | -| `require_auth_flexible` (Query-Token) | nicht implementiert | Nicht AP0.2-Scope; SSE/Download später | -| Account-Lifecycle-Gates | fehlen | AP0.3+ | -| Capabilities in TenantContext | leer / nicht modelliert | Bewusst Nicht-Scope | - -Eingehalten: Server-Sessions, `X-Auth-Token`, `Depends(require_auth)` separat, user_id aus Session, Portal- vs. Tenant-Rolle getrennt, TenantContext als eigene Schicht. - ---- - -## 8. Offene Entscheidungen - -1. **Passwort-Policy / Rate-Limiting** für Login — noch nicht implementiert. -2. **Session-Invalidierung** bei Passwort-Reset (Feature kommt später). -3. **Tenant-Erstellung via API** — aktuell nur Bootstrap/DB; Admin-API in späterem AP. -4. **Frontend Auth-UI** — AP0.2 backend-only; SPA-Anbindung folgt. -5. **Prod-Bootstrap** — `KAIRO_BOOTSTRAP_*` in Prod `.env` setzen oder einmalig manuell seeden. - ---- - -## 9. Empfehlung für AP0.3 - -Laut Foundation-Dokument ursprünglich „Capabilities & Rights Registry“ — der User-Auftrag kombinierte Auth+Tenant bereits in AP0.2. - -**AP0.3 Vorschlag:** - -- Capability/Rights Registry (DB + Sync) -- `require_capability()` Dependency -- TenantContext um `capabilities: list[str]` erweitern -- Keine Feature-Limits / Billing -- Optional: Frontend Login-Form + Token-Speicherung - ---- - -*Erstellt im Rahmen Sprint 0 – AP0.2.* diff --git a/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md b/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md new file mode 100644 index 0000000..da29b6f --- /dev/null +++ b/docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md @@ -0,0 +1,248 @@ +# 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`.*