wiki/b-reference/platform/audit.md
ValueOn AG 788b63907a upd
2026-04-14 10:27:48 +02:00

4.6 KiB

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.