AP0.2 Abschlussbericht v0.2 (final) erstellen.
All checks were successful
Deploy Development / deploy (push) Successful in 38s
Test Suite / pytest-backend (push) Successful in 9s
Test Suite / lint-backend (push) Successful in 1s
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
All checks were successful
Deploy Development / deploy (push) Successful in 38s
Test Suite / pytest-backend (push) Successful in 9s
Test Suite / lint-backend (push) Successful in 1s
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>
This commit is contained in:
parent
f8b3ae3011
commit
f9c207c4f6
|
|
@ -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.*
|
||||
248
docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md
Normal file
248
docs/sprints/Sprint0_AP0_2_Completion_Report_v0.2.md
Normal file
|
|
@ -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`.*
|
||||
Loading…
Reference in New Issue
Block a user