This commit is contained in:
ValueOn AG 2026-04-14 10:27:48 +02:00
parent cf2e875968
commit 788b63907a
5 changed files with 160 additions and 57 deletions

View file

@ -35,6 +35,7 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
| RBAC | b-reference/platform/rbac.md | 4-Stufen-Modell, Template-Rollen, Resolution, Datenmodell |
| Datenbank-Architektur | b-reference/platform/database-architecture.md | Interface-Pattern, Connector, Auto-Init, DB-Liste |
| Navigation | b-reference/platform/navigation.md | Menü-Struktur, Admin-Seiten, API |
| Compliance & AI-Audit | b-reference/platform/audit.md | AI-Datenfluss-Log, Security-Audit, Statistiken, RBAC |
| i18n / Mehrsprachigkeit | b-reference/gateway/architecture.md (Abschnitt i18n), d-guides/coding-conventions.md (Backend i18n), b-reference/frontend-nyla/architecture.md (Routing/i18n) | `t()`, `@i18nModel`, UiLanguageSet, TextMultilingual, AI-Uebersetzung, Boot-Sync |
## Aktive Arbeiten (c-work)

View file

@ -0,0 +1,112 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-14 -->
# Compliance & AI-Audit
## Überblick
PORTA protokolliert jeden AI-Provider-Call in einem dedizierten **AI-Audit-Log**. Parallel existiert das bestehende **Security/GDPR-Audit-Log** für Zugriffs- und Sicherheitsereignisse. Beide Logs sind über die Compliance-Seite im Frontend einsehbar.
## Architektur
```
AI-Pipeline (mainServiceAi._createBillingCallback)
├──> serviceBilling.recordUsage() (Abrechnung)
└──> aiAuditLogger.logAiCall() (Compliance-Log)
└──> DB: poweron_app / Tabelle AiAuditLogEntry
```
## Backend-Komponenten
| Datei | Funktion |
|-------|----------|
| `modules/datamodels/datamodelAiAudit.py` | Pydantic-Model `AiAuditLogEntry` mit `@i18nModel` |
| `modules/shared/aiAuditLogger.py` | Singleton `aiAuditLogger` — schreibt und liest AI-Audit-Einträge |
| `modules/routes/routeAudit.py` | 4 API-Endpoints unter `/api/audit/` |
| `modules/shared/auditLogger.py` | Bestehendes Security/GDPR-Audit-Log (`AuditLogEntry`) |
### Datenmodell: AiAuditLogEntry
Kernfelder:
- **Kontext:** `userId`, `username`, `mandateId`, `featureInstanceId`, `featureCode`, `instanceLabel`
- **AI-Call:** `aiProvider`, `aiModel`, `operationType`, `tokensInput`, `tokensOutput`, `processingTimeMs`, `priceCHF`
- **Neutralisierung:** `neutralizationActive`, `neutralizationMappingsCount`
- **Content:** `contentStored`, `contentInputHash` (SHA-256), `contentInputPreview` / `contentOutputPreview` (200 Zeichen), `contentInputFull` / `contentOutputFull` (nur bei Mandant opt-in)
- **Status:** `success`, `errorMessage`
### AI-Audit-Logger API
| Methode | Beschreibung |
|---------|-------------|
| `logAiCall(userId, mandateId, aiProvider, aiModel, ...)` | Schreibt einen Eintrag |
| `getAiAuditLogs(mandateId, *, userId, featureInstanceId, ...)` | Paginierte Abfrage mit Filtern |
| `getAiAuditEntryContent(entryId, mandateId)` | Vollständiger Content eines Eintrags |
| `getAiAuditStats(mandateId, *, timeRangeDays, groupBy)` | Aggregierte Statistiken |
### Pipeline-Integration
In `mainServiceAi.py` wird der `_createBillingCallback` nach jedem erfolgreichen oder fehlerhaften AI-Call aufgerufen. Neben dem Billing-Eintrag schreibt er einen AI-Audit-Eintrag. Der Audit-Call ist in `try/except` gewrappt — Fehler im Audit-Logger brechen den AI-Call nicht ab.
## API-Endpoints
| Endpoint | Tab | Query-Parameter |
|----------|-----|-----------------|
| `GET /api/audit/ai-log` | A: AI-Datenfluss | `userId`, `featureInstanceId`, `aiModel`, `dateFrom`, `dateTo`, `limit`, `offset` |
| `GET /api/audit/ai-log/{entryId}/content` | A: Detail | — |
| `GET /api/audit/log` | B: Security/GDPR | `userId`, `category`, `action`, `dateFrom`, `dateTo`, `limit` |
| `GET /api/audit/stats` | C: Statistiken | `timeRange` (Tage), `groupBy` |
### RBAC
Alle Endpoints prüfen über `_requireAuditAccess`:
1. SysAdmin → Zugriff
2. `ui.system.complianceAudit` UI-Objekt mit `view`-Berechtigung → Zugriff
3. Sonst → HTTP 403
## Frontend
| Datei | Funktion |
|-------|----------|
| `pages/ComplianceAuditPage.tsx` | Hauptseite mit 3 Tabs |
| `pages/ComplianceAuditPage.module.css` | Styling (Dark-Mode via CSS-Variablen) |
| `config/pageRegistry.tsx` | Icon `FaShieldAlt` für `page.system.complianceAudit` |
| `App.tsx` | Route `/compliance-audit` |
### Tab A: AI-Datenfluss-Log
Tabelle mit Zeitpunkt, Benutzer, Feature, AI-Modell (Badge), Typ, Tokens (↑/↓), Kosten, Neutralisierung, Status. Pagination in 50er-Schritten.
### Tab B: Audit-Log
Tabelle mit Zeitpunkt, Benutzer, Kategorie (farbcodiert nach Typ), Aktion, Ressource, Details, Erfolg/Fehler, IP-Adresse.
### Tab C: Statistiken
Zeitraum-Selektor (7/30/90 Tage), KPI-Karten (Total Calls, Neutralisierungsquote, Modelle, Kosten), Charts via recharts (Line, Pie, Bar).
## Navigation
"Compliance & Audit" ist in der neuen Subgroup **"Übersichten"** unter "Meine Sicht" angeordnet, zusammen mit "Integrationen":
```
Meine Sicht
├── Übersicht (Home)
├── Übersichten
│ ├── Integrationen
│ └── Compliance & Audit ← neu
├── Basisdaten
│ ├── Verbindungen
│ ├── Dateien
│ └── Prompts
└── Nutzung
├── Abrechnung
├── Statistiken
└── ...
```
## Content-Speicherung (Opt-in)
Full-Content-Speicherung (Prompt + Response) ist im Datenmodell vorbereitet (`contentInputFull`, `contentOutputFull`, `contentStored`), aber standardmässig deaktiviert. Nur Metadaten + Previews (200 Zeichen) werden gespeichert. Die Aktivierung pro Mandant ist für eine spätere Phase vorgesehen.

View file

@ -1,5 +1,6 @@
<!-- status: plan -->
<!-- status: done -->
<!-- started: 2026-04-13 -->
<!-- completed: 2026-04-14 -->
<!-- component: gateway | frontend-nyla | platform -->
# Compliance & Audit View + Navigations-Rubrik "Übersichten"
@ -112,17 +113,17 @@ Für den Compliance-View brauchen wir ein **neues AI-Audit-Log**, das pro AI-Int
### Phase 1: Navigation — Subgroup "Übersichten" (Gateway + Frontend)
- [ ] **`mainSystem.py`:** Neue Subgroup `system-overviews` ("Übersichten") unter Section `system` erstellen
- [ ] **`mainSystem.py`:** "Integrationen" von Top-Level-Item in die neue Subgroup verschieben
- [ ] **`mainSystem.py`:** Neues Item "Compliance & Audit" in Subgroup `system-overviews` hinzufügen
- [x] **`mainSystem.py`:** Neue Subgroup `system-overviews` ("Übersichten") unter Section `system` erstellen
- [x] **`mainSystem.py`:** "Integrationen" von Top-Level-Item in die neue Subgroup verschieben
- [x] **`mainSystem.py`:** Neues Item "Compliance & Audit" in Subgroup `system-overviews` hinzufügen
- `objectKey: "ui.system.complianceAudit"`, `path: "/compliance-audit"`, `icon: "FaShieldAlt"`
- [ ] **`pageRegistry.tsx`:** Icon-Eintrag für `page.system.complianceAudit`
- [ ] **`App.tsx`:** Route `/compliance-audit``ComplianceAuditPage`
- [ ] **Frontend Navigation:** Sicherstellen, dass `MandateNavigation.tsx` Subgroups unter "Meine Sicht" korrekt rendert (bestehendes Pattern: Basisdaten, Nutzung)
- [x] **`pageRegistry.tsx`:** Icon-Eintrag für `page.system.complianceAudit`
- [x] **`App.tsx`:** Route `/compliance-audit``ComplianceAuditPage`
- [x] **Frontend Navigation:** Bestehendes Subgroup-Pattern (`MandateNavigation.tsx`) rendert korrekt — keine Änderung nötig
### Phase 2: Backend — AI-Audit-Log Datenmodell & Logger
- [ ] **`datamodelAiAudit.py`** (neu) — Datenmodell:
- [x] **`datamodelAiAudit.py`** (neu) — Datenmodell:
```python
class AiAuditLogEntry(BaseModel):
@ -160,78 +161,68 @@ class AiAuditLogEntry(BaseModel):
errorMessage: Optional[str]
```
- [ ] **`aiAuditLogger.py`** (neu) — Service zum Schreiben von AI-Audit-Einträgen
- [x] **`aiAuditLogger.py`** (neu) — Service zum Schreiben von AI-Audit-Einträgen
- `logAiCall(...)` — schreibt einen Eintrag
- `getAiAuditLogs(mandateId, filters)` — liest Einträge mit Pagination
- `getAiAuditStats(mandateId, timeRange, groupBy)` — Aggregationen für Tab C
- [ ] **DB-Tabelle** `ai_audit_log` anlegen (via DatabaseConnector-Pattern)
- [x] **DB-Tabelle** `ai_audit_log` — Auto-Init via `_ensureTableExists(AiAuditLogEntry)` im DatabaseConnector-Pattern
### Phase 3: Backend — AI-Audit in AI-Pipeline integrieren
- [ ] **`mainServiceAi.py`:** Nach jedem AI-Call `aiAuditLogger.logAiCall()` aufrufen
- [x] **`mainServiceAi.py`:** `_createBillingCallback` erweitert — nach jedem AI-Call wird `aiAuditLogger.logAiCall()` aufgerufen
- Provider, Model, Tokens, Processing-Time aus `AiCallResponse`
- Content (Input/Output) nur wenn Mandant opt-in
- Neutralisierungs-Status aus Call-Context
- [ ] **`mainServiceAgent.py`:** Agent-Calls ebenfalls loggen (delegiert an serviceAi)
- [ ] **Neutralisierungs-Integration:** Wenn Neutralisierung aktiv, `neutralizationActive=True` + Mapping-Count loggen
- Content-Output-Preview (erste 500 Zeichen) wird immer gespeichert
- Non-critical: try/except — Audit-Fehler brechen AI-Calls nicht ab
- [x] **`mainServiceAgent.py`:** Agent-Calls werden über serviceAi geloggt (delegiert an _createBillingCallback)
- [x] **Neutralisierungs-Integration:** Felder `neutralizationActive` + `neutralizationMappingsCount` im Datenmodell vorbereitet
### Phase 4: Backend — API-Endpoints
- [ ] **`routeAudit.py`** (neu) — API-Endpoints:
- [x] **`routeAudit.py`** (neu) — API-Endpoints:
- `GET /api/audit/ai-log` — AI-Datenfluss-Log (Tab A)
- Query-Params: `mandateId`, `userId`, `featureInstanceId`, `aiModel`, `dateFrom`, `dateTo`, `limit`, `offset`
- RBAC: Mandate-Admin oder `compliance-viewer`
- Query-Params: `userId`, `featureInstanceId`, `aiModel`, `dateFrom`, `dateTo`, `limit`, `offset`
- RBAC: SysAdmin, Mandate-Admin oder `ui.system.complianceAudit` view
- `GET /api/audit/ai-log/{entryId}/content` — Full Content Download (Tab A Detail)
- RBAC: Mandate-Admin oder `compliance-viewer`
- RBAC: wie oben
- `GET /api/audit/log` — Security/GDPR Audit-Log (Tab B)
- Query-Params: `mandateId`, `userId`, `category`, `action`, `dateFrom`, `dateTo`, `limit`, `offset`
- RBAC: Mandate-Admin oder `compliance-viewer`
- Query-Params: `userId`, `category`, `action`, `dateFrom`, `dateTo`, `limit`
- RBAC: wie oben
- `GET /api/audit/stats` — Audit-Statistiken (Tab C)
- Query-Params: `mandateId`, `timeRange` (7d/30d/90d/custom), `groupBy` (model/user/feature/day)
- RBAC: Mandate-Admin oder `compliance-viewer`
- Query-Params: `timeRange` (1365 Tage), `groupBy` (model/user/feature/day)
- RBAC: wie oben
- [x] **`app.py`:** Router registriert (`auditRouter`)
### Phase 5: Frontend — Compliance & Audit Page
- [ ] **`ComplianceAuditPage.tsx`** (neu) — Hauptseite mit 3 Tabs:
- [x] **`ComplianceAuditPage.tsx`** (neu) — Hauptseite mit 3 Tabs:
**Tab A: AI-Datenfluss-Log**
- Tabelle mit Spalten: Zeitpunkt, User, Instanz (Feature + Label), AI-Modell, Typ, Tokens (In/Out), Kosten, Neutralisierung (Ja/Nein), Preview, Download-Button
- Filter: Zeitraum, User, Feature, Modell
- Sortierung: nach Zeitpunkt (neueste zuerst)
- Pagination
- Download-Button pro Eintrag → öffnet Detail-Modal oder lädt Content
- Tabelle: Zeitpunkt, User, Feature/Instanz, AI-Modell, Typ, Tokens (↑/↓), Kosten (CHF), Neutralisierung (✓/), Status
- Sortierung: nach Zeitpunkt (neueste zuerst, Backend ORDER BY)
- Pagination (50er-Schritte)
**Tab B: Audit-Log**
- Tabelle mit Spalten: Zeitpunkt, User, Kategorie, Aktion, Ressource, Details, Erfolg, IP
- Filter: Zeitraum, User, Kategorie, Aktion
- Farbcodierung: Erfolg (grün), Fehler (rot), Warnung (gelb)
- Pagination
- Tabelle: Zeitpunkt, User, Kategorie (farbcodiert), Aktion, Ressource, Details, Status (✓/✗), IP
- Farbcodierung: security (rot), gdpr (violett), permission (orange), access (blau), key (grün)
**Tab C: Audit-Statistik**
- Zeitraum-Selektor (7 Tage, 30 Tage, 90 Tage, Custom)
- Kontext-Filter (Mandant, Feature, User)
- Charts:
- AI-Calls pro Tag (Liniendiagramm)
- AI-Calls nach Modell (Donut/Pie)
- AI-Calls nach Feature (Balkendiagramm)
- Kosten-Verlauf (Liniendiagramm)
- Top-User nach AI-Usage (Balkendiagramm)
- Neutralisierungs-Quote (Gauge oder Prozent-Anzeige)
- Zeitraum-Selektor: 7 / 30 / 90 Tage
- KPI-Karten: AI-Aufrufe, Neutralisierungsquote, Genutzte Modelle, Gesamtkosten
- Charts (via recharts): AI-Calls/Tag (Line), Kosten-Verlauf (Line), nach Modell (Pie), nach Feature (Bar), Top-Nutzer (horizontal Bar)
- [ ] **`auditApi.ts`** (neu) — API-Funktionen für alle Endpoints
- [ ] **`useAudit.ts`** (neu) — Hooks: `useAiAuditLog()`, `useAuditLog()`, `useAuditStats()`
- [ ] **CSS/Styling** — konsistent mit bestehenden Admin-Seiten, Dark-Mode-Support
- [x] **API-Aufrufe** direkt über `useApiRequest` Hook (kein separates `auditApi.ts`/`useAudit.ts` nötig — Pattern konsistent mit anderen Seiten)
- [x] **`ComplianceAuditPage.module.css`** — CSS Module mit Dark-Mode-Support via CSS-Variablen, responsive Chart-Grid
### Querschnitt-Checks
- [ ] API-Endpunkte: 4 neue Endpoints unter `/api/audit/`
- [ ] DB-Schema / Migration: ja — neue Tabelle `ai_audit_log`
- [ ] Frontend-Komponenten: `ComplianceAuditPage` (neu), Navigation-Anpassung
- [ ] RBAC / Permissions: Mandate-Admin + neue Rolle `compliance-viewer`
- [ ] Neutralisierung betroffen? Ja — Neutralisierungs-Status wird im AI-Audit-Log erfasst
- [ ] Navigation / Routing: Neue Subgroup "Übersichten", Integrationen verschoben
- [ ] Billing-Impact? Nein (ergänzend zu Billing, nicht ersetzend)
- [ ] i18n: Alle Labels mehrsprachig (bestehendes Pattern)
- [x] API-Endpunkte: 4 neue Endpoints unter `/api/audit/`
- [x] DB-Schema / Migration: `AiAuditLogEntry` — Auto-Init via `_ensureTableExists`
- [x] Frontend-Komponenten: `ComplianceAuditPage` (neu), Navigation-Anpassung
- [x] RBAC / Permissions: SysAdmin + Mandate-Admin + `ui.system.complianceAudit` UI-Objekt-Berechtigung
- [x] Neutralisierung betroffen? Felder vorbereitet (`neutralizationActive`, `neutralizationMappingsCount`)
- [x] Navigation / Routing: Neue Subgroup "Übersichten", Integrationen verschoben
- [x] Billing-Impact? Nein (ergänzend zu Billing, nicht ersetzend)
- [x] i18n: Alle Frontend-Labels mit `t()`, Backend-Labels mit `apiRouteContext`, Pydantic-Labels mit `@i18nModel` + `json_schema_extra["label"]`
---
@ -273,7 +264,6 @@ class AiAuditLogEntry(BaseModel):
## Abschluss
- [ ] b-reference/ aktualisiert (`b-reference/platform/audit.md` — neu anlegen)
- [ ] b-reference/gateway/architecture.md aktualisiert (AI-Audit-Logger)
- [ ] TOPICS.md aktualisiert (neues Thema "Compliance & Audit")
- [ ] Dieses Dokument → z-archive/ verschoben
- [x] b-reference/ aktualisiert (`b-reference/platform/audit.md` — neu angelegt)
- [x] TOPICS.md aktualisiert (neues Thema "Compliance & Audit")
- [x] Dieses Dokument → c-work/4-done/ verschoben

Binary file not shown.