diff --git a/TOPICS.md b/TOPICS.md index 93c99b9..87e647f 100644 --- a/TOPICS.md +++ b/TOPICS.md @@ -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) diff --git a/b-reference/platform/audit.md b/b-reference/platform/audit.md new file mode 100644 index 0000000..86d5a8e --- /dev/null +++ b/b-reference/platform/audit.md @@ -0,0 +1,112 @@ + + + +# 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. diff --git a/c-work/1-plan/2026-04-compliance-audit-view-and-navigation-overviews.md b/c-work/4-done/2026-04-compliance-audit-view-and-navigation-overviews.md similarity index 76% rename from c-work/1-plan/2026-04-compliance-audit-view-and-navigation-overviews.md rename to c-work/4-done/2026-04-compliance-audit-view-and-navigation-overviews.md index 5996588..2f265a2 100644 --- a/c-work/1-plan/2026-04-compliance-audit-view-and-navigation-overviews.md +++ b/c-work/4-done/2026-04-compliance-audit-view-and-navigation-overviews.md @@ -1,5 +1,6 @@ - + + # 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` (1–365 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 diff --git a/c-work/3-validate/2026-04-investor-demo-tuesday.md b/c-work/4-done/2026-04-investor-demo-tuesday.md similarity index 100% rename from c-work/3-validate/2026-04-investor-demo-tuesday.md rename to c-work/4-done/2026-04-investor-demo-tuesday.md diff --git a/d-guides/deployment/poweron-sec.kdbx b/d-guides/deployment/poweron-sec.kdbx index a026760..f48e84c 100644 Binary files a/d-guides/deployment/poweron-sec.kdbx and b/d-guides/deployment/poweron-sec.kdbx differ