155 lines
5.3 KiB
Markdown
155 lines
5.3 KiB
Markdown
|
|
# 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.*
|