# 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.