unified failsafe neutralization architecture
This commit is contained in:
parent
7ec8abe314
commit
70649218f1
3 changed files with 488 additions and 129 deletions
200
compliance/Neutralisierung.md
Normal file
200
compliance/Neutralisierung.md
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
# Neutralisierung
|
||||
|
||||
**Stand:** 2026-03-29
|
||||
|
||||
---
|
||||
|
||||
## 1. Grundidee
|
||||
|
||||
Neutralisierung passiert dort, wo **Content entsteht oder ins System einfliesst** — nicht als nachgelagerter Filter vor dem Modell-Call. Wenn Content einmal neutralisiert ist (z. B. im RAG), bleibt er neutralisiert. Kein doppeltes Verarbeiten.
|
||||
|
||||
---
|
||||
|
||||
## 2. Wer fordert Neutralisierung?
|
||||
|
||||
Drei Quellen, von breit nach spezifisch:
|
||||
|
||||
| Quelle | Flag im Code | Bedeutung |
|
||||
|--------|-------------|-----------|
|
||||
| **Feature-Instanz** | `DataNeutraliserConfig.enabled` (hat `featureInstanceId` + `mandateId`) | Alle Daten in dieser Feature-Instanz werden neutralisiert. Betrifft jeden Content-Einstieg innerhalb dieser Instanz. |
|
||||
| **Chat-Workflow / Session** | `ServiceCenterContext.requireNeutralization` (gesetzt z. B. vom AI-Workspace oder Automation) | Dieser Workflow/Turn: jeder Content, der hier verarbeitet wird, wird neutralisiert. |
|
||||
| **Dokument oder Quelle** | `FileItem.neutralize`, `DataSource.neutralize`, `FeatureDataSource.neutralize` | Dieses konkrete Objekt: Content daraus wird neutralisiert, egal ob die Feature-Instanz oder der Workflow es sonst fordern würden. |
|
||||
|
||||
**Auswertung:** Irgendeine Quelle sagt `True` → neutralisieren. Keine Quelle kann eine andere aufheben. Es gibt kein `False`-Override, das ein `True` von woanders aushebelt.
|
||||
|
||||
---
|
||||
|
||||
## 3. Wo passiert die Neutralisierung?
|
||||
|
||||
Am **Punkt der Content-Einspeisung** — dort wo Rohdaten zu verarbeitbarem Content werden:
|
||||
|
||||
| Content-Einstieg | Was passiert | Wer prüft das Flag |
|
||||
|------------------|-------------|---------------------|
|
||||
| **Datei-Indexierung** (RAG) | Text-Chunks werden über `processText` neutralisiert, bevor sie ins Embedding gehen. Medien: nur internes Modell oder nicht indexieren. Ergebnis: RAG enthält nur neutralisierten Content. | `mainServiceKnowledge.indexFile` liest `FileItem.neutralize` |
|
||||
| **Content-Extraktion** (Dokumente für KI-Verarbeitung) | Extrahierter Text/Tabellen werden neutralisiert. PDF, DOCX, XLSX, PPTX über `processFile` (Extract → neutralisieren → zurückschreiben). | Caller kennt die Quelle und deren Flag |
|
||||
| **User-Prompt** (Chat-Eingabe) | Prompt-Text wird durch `processText` neutralisiert, wenn Feature-Instanz oder Workflow es fordern. | `mainServiceAi` prüft Context-Flag / Config |
|
||||
| **DataSource-Download** | Flag wird auf erstellte `FileItem`s vererbt → bei Extraktion/Indexierung greift das File-Flag automatisch. | `mainServiceAgent._resolveDataSource` / `_downloadFromDataSource` |
|
||||
| **FeatureDataSource-Abfrage** | Wenn eine `FeatureDataSource.neutralize=True` hat → Content aus diesem Sub-Agent-Call wird neutralisiert. | `mainServiceAgent._queryFeatureInstance` setzt `requireNeutralization=True` |
|
||||
| **Workflow-Aktion `neutralizeData`** | Expliziter Neutralisierungs-Schritt auf bereits extrahierten ContentParts. | Workflow-Config + `NeutralizationConfig.enabled` |
|
||||
|
||||
**Was NICHT nochmal neutralisiert werden muss:**
|
||||
- RAG-Chunks, die bereits neutralisiert indexiert sind — die sind schon sauber.
|
||||
- Web-Suchergebnisse — enthalten keine Mandantendaten, brauchen keine Neutralisierung.
|
||||
|
||||
**Flag-Änderung:** Ändert sich `FileItem.neutralize` (Toggle) → Index löschen → Re-Indexierung triggern → neuer Index ist im richtigen Zustand.
|
||||
|
||||
---
|
||||
|
||||
## 4. Engine: `NeutralizationService`
|
||||
|
||||
Eine Engine, drei Einstiege, aufgerufen an den Content-Einstiegspunkten aus Abschnitt 3.
|
||||
|
||||
| API | Eingabe | Status |
|
||||
|-----|---------|--------|
|
||||
| `processText(text)` | Rohtext (Prompt, Message, Text-ContentPart, Text-Chunk) | **Ist** |
|
||||
| `processFile(fileId)` | Datei aus DB — wird nach MIME geroutet | **Ist** |
|
||||
| `processBinaryBytes` / `Async` | Bytes + Dateiname + MIME | **Ist** |
|
||||
| **`processImage(imageBytes, fileName)`** | Bild-Datei oder Bild-ContentPart (image/png, image/jpeg, …) | **Soll — fehlt heute** |
|
||||
|
||||
**Ist-Zustand Bilder:** `_processBinaryFile` überspringt Parts mit `typeGroup == 'image'` (unverändert durchgereicht). Eigenständige Bild-Dateien (`image/*` MIME) werden in `_isBinaryMimeType` als Skip behandelt. **Es gibt keinen Bild-Neutralisierungs-Pfad.**
|
||||
|
||||
**Soll:** `processImage` als eigener Einstieg. Ruft internes Vision-Modell (`NEUTRALIZATION_IMAGE` → Private-LLM) auf, um sensible Inhalte in Bildern zu erkennen/entfernen. Kein externer Provider. Modell nicht verfügbar → Bild blockieren (nicht unbehandelt weiterreichen).
|
||||
|
||||
**Ablauf nach MIME:**
|
||||
|
||||
| MIME | Pfad |
|
||||
|------|------|
|
||||
| PDF, DOCX, XLSX, PPTX | `runExtraction` → Text/Table-Parts durch `_neutralizeText`, Bild-Parts durch `processImage` → PDF in-place oder Office-Renderer |
|
||||
| Text, JSON, CSV, XML | `_neutralizeText` direkt (TextProcessor, ListProcessor, BinaryProcessor je nach Inhalt) |
|
||||
| Bilder (image/*) | **`processImage`** → internes Vision-Modell (`NEUTRALIZATION_IMAGE`). Nicht verfügbar → blockieren. |
|
||||
| Video, Audio | Nur internes Modell oder blockieren (analog Bilder, aber niedrigere Priorität) |
|
||||
| Anderes Binary | Skip (nicht unterstützt) |
|
||||
|
||||
**Mapping:** Platzhalter `[typ.uuid]` → Attribute in DB. `resolveText(text)` für Rückübersetzung.
|
||||
|
||||
---
|
||||
|
||||
## 5. Modellauswahl
|
||||
|
||||
| Operation Type | Modelle | Zweck |
|
||||
|----------------|---------|-------|
|
||||
| `NEUTRALIZATION_TEXT` | `poweron-text-general` (Rating 9) | Falls Engine ein LLM für Text braucht |
|
||||
| `NEUTRALIZATION_IMAGE` | `poweron-vision-general` (9), `poweron-vision-deep` (9) | Medien bei Neutralisierungspflicht: nur intern |
|
||||
|
||||
Registriert in `aicorePluginPrivateLlm.py`. Externe Provider haben keine `NEUTRALIZATION_*`-Ratings → werden nie für Neutralisierung gewählt.
|
||||
|
||||
---
|
||||
|
||||
## 6. Fail-safe
|
||||
|
||||
| Situation | Verhalten |
|
||||
|-----------|-----------|
|
||||
| Neutralisierung gefordert, Engine nicht verfügbar | Content **nicht** weiterverarbeiten (blockieren) |
|
||||
| Neutralisierung eines Teils schlägt fehl | Teil entfernen, nicht im Rohzustand weiterleiten |
|
||||
| Kein internes Modell für Medien verfügbar | Medien-Part entfernen |
|
||||
|
||||
---
|
||||
|
||||
## 7. Code-Karte
|
||||
|
||||
| Bereich | Pfad |
|
||||
|---------|------|
|
||||
| Engine | `features/neutralization/serviceNeutralization/mainServiceNeutralization.py` + `subProcess*.py` |
|
||||
| Config + Attribute DB | `features/neutralization/datamodelFeatureNeutralizer.py`, `interfaceFeatureNeutralizer.py` |
|
||||
| Index (Data-at-rest) | `serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` |
|
||||
| Prompt-Neutralisierung | `serviceCenter/services/serviceAi/mainServiceAi.py` (`_shouldNeutralize`, `_neutralizeRequest`) |
|
||||
| Agent / DataSource / Feature | `serviceCenter/services/serviceAgent/mainServiceAgent.py` |
|
||||
| Workflow-Aktion | `workflows/methods/methodContext/actions/neutralizeData.py` |
|
||||
| Modelle / Enums | `datamodels/datamodelAi.py`, `aicore/aicorePluginPrivateLlm.py` |
|
||||
| Flags | `datamodelFiles.py` (`FileItem.neutralize`), `datamodelDataSource.py`, `datamodelFeatureDataSource.py` |
|
||||
| Context | `serviceCenter/context.py` (`ServiceCenterContext.requireNeutralization`) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Umsetzungsplan
|
||||
|
||||
### Schritt 1: `processImage` in Engine bauen
|
||||
|
||||
**Datei:** `mainServiceNeutralization.py`
|
||||
**Was:** Neue Methode `processImage(imageBytes: bytes, fileName: str, mimeType: str) -> Dict` und `processImageAsync`.
|
||||
**Wie:** Internes Vision-Modell aufrufen (`NEUTRALIZATION_IMAGE` via Model Selector / `aiObjects`). Prompt: sensible Inhalte im Bild erkennen und beschreiben, damit Caller entscheiden kann ob Bild blockiert wird. Kein internes Modell verfügbar → `{'status': 'blocked'}` zurückgeben.
|
||||
**Abhängigkeit:** `OperationTypeEnum.NEUTRALIZATION_IMAGE` + Modell-Ratings in `aicorePluginPrivateLlm.py` — **bereits erledigt**.
|
||||
|
||||
### Schritt 2: `_shouldNeutralize` vereinfachen
|
||||
|
||||
**Datei:** `mainServiceAi.py` (Zeile ~560)
|
||||
**Ist:** Prüft `request.requireNeutralization` → `context.requireNeutralization` → `NeutralizationConfig.enabled` (Mandant-Level Config). `request.requireNeutralization=False` bricht sofort ab.
|
||||
**Soll:** Drei Quellen gemäss Abschnitt 2, kein `False`-Override:
|
||||
1. Feature-Instanz: `NeutralizationConfig.enabled` (hat `featureInstanceId`)
|
||||
2. Workflow/Session: `context.requireNeutralization`
|
||||
3. Request: `request.requireNeutralization`
|
||||
|
||||
Irgendein `True` → neutralisieren. `False` in einer Quelle hebt `True` in einer anderen **nicht** auf.
|
||||
**Änderung:** `if request.requireNeutralization is False: return False` **entfernen**. Stattdessen OR-Verknüpfung aller drei Quellen.
|
||||
|
||||
### Schritt 3: `_neutralizeRequest` auf Prompt/Messages beschränken
|
||||
|
||||
**Datei:** `mainServiceAi.py` (Zeile ~592)
|
||||
**Ist:** Neutralisiert `prompt`, `context`, `messages` (String-Content).
|
||||
**Soll:** Zusätzlich Text in `contentParts` und Text-Teile in multimodalen Messages (content-Liste mit `type==text`). Bild-Teile in Messages: bei Neutralisierungspflicht über `processImage` prüfen oder entfernen.
|
||||
**Wichtig:** Hier geht es nur um Prompt-/Sessiondaten. File-Content aus RAG ist bereits neutralisiert (Schritt 5), muss hier nicht nochmal durch.
|
||||
|
||||
### Schritt 4: `indexFile` — Bild-Chunks behandeln
|
||||
|
||||
**Datei:** `mainServiceKnowledge.py` (Zeile ~146 ff.)
|
||||
**Ist:** Nur `textObjects` (contentType == "text") werden bei `_shouldNeutralize` durch `processText` geschickt. Bild-Chunks (`contentType == "image"`) werden unverändert indexiert.
|
||||
**Soll:** Bild-Chunks bei `_shouldNeutralize` über `processImage` (Schritt 1) prüfen. Ergebnis `blocked` → Bild-Chunk nicht indexieren. Ergebnis OK → Bild-Chunk indexieren (internes Modell hat es gesehen, kein externer Provider nötig).
|
||||
**Abhängigkeit:** Schritt 1.
|
||||
|
||||
### Schritt 5: Agent-Tool `readFile` — Content bei Extraktion neutralisieren
|
||||
|
||||
**Datei:** `mainServiceAgent.py`, Tool `_readFile` (Zeile ~540 ff.)
|
||||
**Ist:** Liest aus Knowledge Store (bereits indexiert) oder extrahiert on-demand. Kein Neutralisierungs-Check.
|
||||
**Soll:**
|
||||
- **Knowledge Store Pfad (Zeile ~548):** RAG-Chunks sind bereits neutralisiert wenn `FileItem.neutralize=True` war (Schritt 4) → nichts zu tun.
|
||||
- **On-Demand Extraktion (Zeile ~630 ff.):** Nach `runExtraction` und vor Rückgabe der Text-Objekte: `FileItem.neutralize` laden. Wenn `True` → Text-Objekte durch `processText`, Bild-Objekte durch `processImage`.
|
||||
|
||||
### Schritt 6: Agent-Tool `summarizeContent` — File-Flag prüfen
|
||||
|
||||
**Datei:** `mainServiceAgent.py`, Tool `_summarizeContent` (Zeile ~1921 ff.)
|
||||
**Ist:** Liest Content-Objects aus Knowledge Store, baut `combinedText` und ruft `callAi` auf. Kein Neutralisierungs-Check.
|
||||
**Soll:** Content aus Knowledge Store ist bereits neutralisiert (Schritt 4) → nichts zu tun, **sofern** File indexiert war. Wenn nicht indexiert: File-Flag prüfen, Text vor `callAi` durch `processText`.
|
||||
**Hinweis:** Durch Schritt 4 ist der Regelfall abgedeckt.
|
||||
|
||||
### Schritt 7: Agent-Tool `describeImage` — File-Flag prüfen
|
||||
|
||||
**Datei:** `mainServiceAgent.py`, Tool `_describeImage` (Zeile ~2015 ff.)
|
||||
**Ist:** Lädt Bild-Chunk oder Rohdaten, sendet per `callAi` mit `IMAGE_ANALYSE` an **beliebigen** Provider (inkl. extern). Kein Neutralisierungs-Check.
|
||||
**Soll:** `FileItem.neutralize` laden (fileId ist bekannt). Wenn `True`:
|
||||
- `operationType` auf `NEUTRALIZATION_IMAGE` statt `IMAGE_ANALYSE` → Model Selector wählt nur internes Modell.
|
||||
- Kein internes Modell → Tool gibt Fehler zurück statt Bild an externen Provider zu senden.
|
||||
|
||||
### Schritt 8: `_processBinaryFile` — Bild-Parts nicht mehr überspringen
|
||||
|
||||
**Datei:** `mainServiceNeutralization.py` (Zeile ~298)
|
||||
**Ist:** `if type_group in ('binary', 'image'): neutralized_parts.append(part); continue` — Bild-Parts werden übersprungen.
|
||||
**Soll:** `binary` weiterhin skip. `image` → durch `processImage` (Schritt 1). Ergebnis `blocked` → Part entfernen. Ergebnis OK → Part behalten.
|
||||
**Abhängigkeit:** Schritt 1.
|
||||
|
||||
### Schritt 9: Workflow-Aktion `neutralizeData` — Bild-Parts
|
||||
|
||||
**Datei:** `neutralizeData.py` (Zeile ~130 ff.)
|
||||
**Ist:** Iteriert über ContentParts, neutralisiert nur Parts mit `part.data` (Text). `typeGroup != text/table` → unverändert durchgereicht.
|
||||
**Soll:** Bild-Parts durch `processImage`. Ergebnis `blocked` → Part entfernen.
|
||||
**Abhängigkeit:** Schritt 1.
|
||||
|
||||
### Schritt 10: Tests
|
||||
|
||||
| Test | Was |
|
||||
|------|-----|
|
||||
| T1 | `FileItem.neutralize=True` → `indexFile` → Text-Chunks neutralisiert, Bild-Chunks geprüft/blockiert |
|
||||
| T2 | `readFile` on-demand auf File mit `neutralize=True` → Text neutralisiert |
|
||||
| T3 | `describeImage` auf File mit `neutralize=True` → nur internes Modell |
|
||||
| T4 | Feature-Instanz Config `enabled=True` → Prompt in `callAi` neutralisiert |
|
||||
| T5 | Workflow `requireNeutralization=True` → Prompt neutralisiert |
|
||||
| T6 | `processFile` auf PDF mit Bildern → Text neutralisiert, Bild-Parts durch `processImage` |
|
||||
| T7 | Flag-Toggle → Index gelöscht → Re-Index im richtigen Zustand |
|
||||
|
||||
### Schritt 11: Logging
|
||||
|
||||
**Alle Stellen (Schritte 2–9):** Bei Neutralisierung loggen: welche Quelle (Feature-Instanz / Workflow / File-Flag), welche `fileId` falls vorhanden, Ergebnis (OK / Part entfernt / blockiert). **Kein Klartext** in Logs.
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
Kontext: Wir arbeiten an einer Multi-Tenant-Applikation mit Feature-Store-Modell. Ich möchte UI und Gateway austesten und offene Themen weiterführen. Hier ist der vollständige architektonische Kontext:
|
||||
|
||||
---
|
||||
|
||||
## Architektur-Überblick
|
||||
|
||||
- **Backend (Gateway):** `@poweron/gateway` — FastAPI (Python), PostgreSQL
|
||||
- **Frontend:** `@poweron/frontend_nyla` — React/TypeScript (Vite)
|
||||
- **Konzeptdokument:** `@poweron/wiki/concepts/Multi-Mandate-Onboarding-und-Store-Konzept.md`
|
||||
- **Umsetzungsbericht (103 Punkte OK):** `@poweron/wiki/concepts/Multi-Mandate-Umsetzungsbericht.md`
|
||||
|
||||
---
|
||||
|
||||
## RBAC-Rollenmodell (KRITISCH — nie verwechseln!)
|
||||
|
||||
Es gibt ZWEI vollständig getrennte Rollensysteme. Siehe auch: `@poweron/.cursor/rules/rbac-role-separation.mdc`
|
||||
|
||||
### 1. Mandantenrollen (Mandate Roles)
|
||||
- Labels: `admin`, `user`, `viewer` (generisch)
|
||||
- Gespeichert mit: `featureCode=NULL`, `featureInstanceId=NULL`, `mandateId=<id>`
|
||||
- Templates: `isSystemRole=True`, `mandateId=NULL`, `featureCode=NULL`
|
||||
- Verknüpfung: `UserMandateRole` Junction Table
|
||||
- Logik: Zuordnung User → Mandant erfolgt via `createUserMandate()` in `interfaceDbApp.py`, welche IMMER mindestens eine Mandate-Rolle verlangt (ValueError wenn leer)
|
||||
|
||||
### 2. Feature-Instanz-Rollen (Feature Instance Roles)
|
||||
- Labels: `workspace-admin`, `workspace-user`, `workspace-viewer`, `automation-admin`, etc. (Feature-Prefix!)
|
||||
- Gespeichert mit: `featureCode=<code>`, `featureInstanceId=<id>`, `mandateId=<id>`
|
||||
- Templates: `isSystemRole=False`, `mandateId=NULL`, `featureInstanceId=NULL`, `featureCode=<code>` (globale Vorlagen)
|
||||
- Verknüpfung: `FeatureAccessRole` Junction Table
|
||||
- Logik: Zuordnung User → Feature-Instanz erfolgt via `createFeatureAccess()` in `interfaceDbApp.py`, welche IMMER mindestens eine Instanz-Rolle verlangt (ValueError wenn leer)
|
||||
- Jedes Feature-Modul definiert seine `TEMPLATE_ROLES` in `mainXxx.py`
|
||||
|
||||
### Strikte Regeln:
|
||||
1. NIE eine Mandantenrolle (`admin`) einer `FeatureAccessRole` zuweisen
|
||||
2. NIE eine Feature-Rolle (`workspace-admin`) einer `UserMandateRole` zuweisen
|
||||
3. Admin-Lookup für Feature-Instanzen: `roleLabel.endswith("-admin")`, NICHT `"admin" in roleLabel`
|
||||
4. `_copyTemplateRoles` sucht: `featureCode=X, mandateId=NULL, featureInstanceId=NULL` — nie `isSystemRole=True`
|
||||
5. Alle Pfade, die `FeatureAccess` erstellen, MÜSSEN mindestens eine instanz-scoped roleId mitgeben
|
||||
|
||||
### Datenmodelle:
|
||||
- `Role`: `@poweron/gateway/modules/datamodels/datamodelRbac.py` — Felder: id, roleLabel, description, mandateId, featureInstanceId, featureCode, isSystemRole
|
||||
- `UserMandate`: `@poweron/gateway/modules/datamodels/datamodelMembership.py` — User-Mitgliedschaft in Mandant
|
||||
- `FeatureAccess`: `@poweron/gateway/modules/datamodels/datamodelMembership.py` — User-Zugriff auf Feature-Instanz
|
||||
- `FeatureInstance`: `@poweron/gateway/modules/datamodels/datamodelFeatures.py` — Instanz eines Features in einem Mandanten
|
||||
- `Mandate`: `@poweron/gateway/modules/datamodels/datamodelUam.py` — Mandantenmodell mit isSystem (Root-Schutz), deletedAt. `mandateType` wurde entfernt (keine Geschäftslogik).
|
||||
|
||||
---
|
||||
|
||||
## Feature-Store-Konzept ("Own Instance Pattern")
|
||||
|
||||
- **UI:** `@poweron/frontend_nyla/src/pages/Store.tsx` — Pro Mandant ein "Aktivieren für [Mandant]" Button
|
||||
- **Backend:** `@poweron/gateway/modules/routes/routeStore.py` — `POST /api/store/activate`
|
||||
- **Flow:** User wählt Feature → wählt Mandant → Backend erstellt `FeatureInstance` mit `copyTemplateRoles=True` → findet Admin-Rolle (`endswith("-admin")`) → weist User via `createFeatureAccess(userId, instanceId, roleIds=[adminRoleId])` zu
|
||||
- **Auto-Provisioning:** `GET /api/store/mandates` erstellt automatisch "Home {username}"-Mandate, wenn User keine Admin-Mandate hat
|
||||
- **Home-Mandant:** Jeder User hat ab erstem Login ein Home-Mandat ("Home {username}"). Wird in Login, Register, OAuth-Onboarding und Store einheitlich sichergestellt.
|
||||
- **Template-Rollen-Kopie:** `@poweron/gateway/modules/interfaces/interfaceFeatures.py` — `_copyTemplateRoles()` und `syncRolesFromTemplate()`
|
||||
- **Orphan Control:** Letzer FeatureAccess entfernt → FeatureInstance wird gelöscht
|
||||
|
||||
---
|
||||
|
||||
## Schlüssel-Backend-Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|-------|-------|
|
||||
| `@poweron/gateway/modules/interfaces/interfaceDbApp.py` | Kern-DB-Interface: createUserMandate, createFeatureAccess, _provisionMandateForUser; Domain-Models nutzen `PowerOnModel` / `sys*`-Metadaten |
|
||||
| `@poweron/gateway/modules/interfaces/interfaceFeatures.py` | Feature-Instanz-Verwaltung: _copyTemplateRoles, syncRolesFromTemplate |
|
||||
| `@poweron/gateway/modules/routes/routeStore.py` | Store-API: activate, mandates-list |
|
||||
| `@poweron/gateway/modules/routes/routeAdminFeatures.py` | Admin-API: add_user_to_feature_instance (Rollen-Validierung: nur Instanz-Rollen!), rename instance |
|
||||
| `@poweron/gateway/modules/routes/routeSystem.py` | `/api/navigation` — liefert isAdmin pro FeatureInstance |
|
||||
| `@poweron/gateway/modules/routes/routeSecurityLocal.py` | Login, Register, _provisionMandateForUser |
|
||||
| `@poweron/gateway/modules/shared/attributeUtils.py` | Generiert Attribute aus Pydantic-Models für FormGenerator |
|
||||
| `@poweron/gateway/modules/connectors/connectorDbPostgre.py` | DB-Connector: `sysCreatedAt` / `sysCreatedBy` / `sysModifiedAt` / `sysModifiedBy`; Migration alter `_createdAt`-Spalten via `migrateLegacyUnderscoreSysColumns` (Bootstrap) |
|
||||
| `@poweron/gateway/modules/migration/migrateRootUsers.py` | Root→Personal-Mandate-Migration |
|
||||
|
||||
---
|
||||
|
||||
## Schlüssel-Frontend-Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|-------|-------|
|
||||
| `@poweron/frontend_nyla/src/pages/Store.tsx` | Feature-Store mit Mandate-Kontext |
|
||||
| `@poweron/frontend_nyla/src/components/UnifiedDataBar/UnifiedDataBar.tsx` | UDB: Chats, Files, Sources Tabs |
|
||||
| `@poweron/frontend_nyla/src/components/UnifiedDataBar/ChatsTab.tsx` | Chats: Volltext-Suche, Feature-Code-Gruppierung, Flat-Mode nach lastMessageAt |
|
||||
| `@poweron/frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx` | Files: Scope/Neutralize Icons |
|
||||
| `@poweron/frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx` | Sources: Scope/Neutralize auf Active Sources |
|
||||
| `@poweron/frontend_nyla/src/components/Navigation/MandateNavigation.tsx` | Nav-Tree mit Rename-Icon für Instanz-Admins |
|
||||
| `@poweron/frontend_nyla/src/components/Navigation/TreeNavigation/TreeNavigation.tsx` | Generischer Tree mit actions-Slot |
|
||||
| `@poweron/frontend_nyla/src/components/OnboardingAssistant.tsx` | Globaler Onboarding-Assistent (Dashboard, dismissible, reaktivierbar via UserSection) |
|
||||
| `@poweron/frontend_nyla/src/components/Navigation/UserSection.tsx` | User-Kontextmenü: Guthaben, Einstellungen, Onboarding |
|
||||
| `@poweron/frontend_nyla/src/pages/Settings.tsx` | User-Settings: profile, appearance, voice, neutralization, privacy |
|
||||
| `@poweron/frontend_nyla/src/components/FormGenerator/` | Dynamische Formulare aus Backend-Attribut-Definitionen |
|
||||
| `@poweron/frontend_nyla/src/hooks/useNavigation.ts` | Navigation-Hook mit FeatureInstance.isAdmin |
|
||||
| `@poweron/frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx` | Workspace-Feature-Seite mit Chat-Drag&Drop + RAG-Resolve |
|
||||
| `@poweron/frontend_nyla/src/pages/views/commcoach/CommcoachDossierView.tsx` | CommCoach mit UDB (`hideTabs: chats`), gleicher `instanceId`/`mandateId`-Kontext wie Workspace |
|
||||
| `@poweron/gateway/modules/datamodels/datamodelBase.py` | `PowerOnModel`: `sysCreatedAt`, `sysCreatedBy`, `sysModifiedAt`, `sysModifiedBy` (camelCase, UI-readonly vorbereitet) |
|
||||
|
||||
---
|
||||
|
||||
## System-Felder (DB-Metadaten)
|
||||
|
||||
- **Spalten / Modelle:** `sysCreatedAt`, `sysCreatedBy`, `sysModifiedAt`, `sysModifiedBy` — gepflegt durch den Connector (`connectorDbPostgre.py`); viele Domain-Models erben von `PowerOnModel` in `datamodelBase.py`.
|
||||
- **Legacy:** Frühere `_createdAt`-Spalten werden bei Bootstrap durch `migrateLegacyUnderscoreSysColumns` / `migrateLegacyUnderscoreSysColumnsAllPoweronDatabases` in die `sys*`-Felder übernommen.
|
||||
- **UI:** FormGenerator unterstützt `readonly`-Attribute; wo Metadaten in Listen/Forms explizit gezeigt werden sollen, Felder als readonly markieren (schrittweise je Screen).
|
||||
|
||||
---
|
||||
|
||||
## Produkt-Themen (Stand 2026-03-28)
|
||||
|
||||
1. **CommCoach UDB + Voice:** UDB in `CommcoachDossierView`. Voice-Controller bezieht STT-Sprache dynamisch aus zentralen Preferences.
|
||||
2. **Neutralisierung End-to-End:** `requireNeutralization` vom UI-Toggle bis `AiCallRequest` durchgereicht via ServiceCenterContext. Mandanten-RAG in CommCoach via `searchSessionsByTopicRag`.
|
||||
3. **Settings (5 Tabs):** Profil, Darstellung, Stimme, Datenneutralisierung, Datenschutz.
|
||||
4. **Billing: nur PREPAY_MANDATE:** `PREPAY_USER` komplett entfernt. `budgetAiCHF` in Subscriptions (Trial: 5 CHF, Standard: 10 CHF/Monat). Auto-Recharge-Felder in BillingSettings.
|
||||
5. **mandateType entfernt:** Enum, Feld, Validator in 13+ Dateien gelöscht. `isSystem` als einziger Root-Schutz.
|
||||
6. **Home-Mandant:** "Home {username}" bei erstem Login (Register/OAuth/Invitation) via `_ensureHomeMandate()`.
|
||||
7. **UDB ChatsTab:** Server-seitige Volltext-Suche (`searchWorkflowsByContent`), Flat-Mode nach `lastMessageAt`, zweistufige Baumansicht (Feature-Code-Sektionen > Feature-Instanzen).
|
||||
8. **Chat Drag & Drop + RAG:** Chat-Items aus ChatsTab auf Workspace droppbar. Backend `/resolve-rag` liefert Zusammenfassung.
|
||||
9. **Datenvolumen:** `assertCapacity("dataVolumeMB")` prüft RAG-Index-Grösse (`FileContentIndex.totalSize`). API `/api/subscription/data-volume/{mandateId}` liefert `ragIndexMB`, `filesMB`, `percentUsed`, `warning` (>=80%).
|
||||
10. **Mandate-Cascade:** `deleteMandate(force=True)` löscht alle abhängigen Tabellen: ContentChunk, FileContentIndex, DataNeutralizerAttributes, DataSource, FeatureDataSource, FileItem, ChatMessage/Log/Workflow, FeatureAccessRole, FeatureAccess, FeatureInstance, UserMandateRole, UserMandate, Stripe-Subscriptions, BillingTransaction/Account/Settings, AccessRule, Role, Mandate. Frontend: Namensbestätigungs-Dialog.
|
||||
|
||||
---
|
||||
|
||||
## Coding-Konventionen
|
||||
|
||||
- Alle internen Funktionen beginnen mit `_` Prefix (z.B. `_copyTemplateRoles`)
|
||||
- camelCase für alle Variablen und Funktionsnamen (kein snake_case)
|
||||
- Keine unnötigen Fallbacks — Fehler müssen propagiert werden
|
||||
- Keine Deprecations — alte Logik löschen statt deprecaten
|
||||
- Keine Backwards-Compatibility-Workarounds
|
||||
- Pydantic-Models sind die einzige Quelle für UI-Feld-Definitionen (via `attributeUtils.py`)
|
||||
288
concepts/Kontext-20260329.md
Normal file
288
concepts/Kontext-20260329.md
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
# PowerOn Applikations-Kontext (Stand 2026-03-29)
|
||||
|
||||
Multi-Tenant SaaS-Applikation mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung.
|
||||
|
||||
---
|
||||
|
||||
## 1. Technologie-Stack
|
||||
|
||||
| Layer | Technologie | Pfad |
|
||||
|-------|------------|------|
|
||||
| Backend (Gateway) | FastAPI (Python), PostgreSQL | `@poweron/gateway` |
|
||||
| Frontend | React/TypeScript (Vite) | `@poweron/frontend_nyla` |
|
||||
| AI Core | Multi-Provider (Anthropic, OpenAI, Mistral, Perplexity, Tavily, PrivateLLM) | `@poweron/gateway/modules/aicore` |
|
||||
| DB-Connector | PostgreSQL mit pgvector (Embeddings) | `@poweron/gateway/modules/connectors/connectorDbPostgre.py` |
|
||||
|
||||
---
|
||||
|
||||
## 2. Gateway-Architektur (Backend)
|
||||
|
||||
### Modulstruktur (`gateway/modules/`)
|
||||
|
||||
| Modul | Zweck |
|
||||
|-------|-------|
|
||||
| `aicore/` | Model-Registry, Model-Selector, Provider-Plugins (Anthropic, OpenAI, Mistral, Perplexity, Tavily, PrivateLLM) |
|
||||
| `auth/` | Authentifizierung |
|
||||
| `connectors/` | DB-Connector (PostgreSQL), externe Konnektoren |
|
||||
| `datamodels/` | Pydantic-Datenmodelle (30+ Dateien: Ai, Billing, Chat, Content, Files, Knowledge, Rbac, Subscription, Workflow...) |
|
||||
| `features/` | Feature-Module (autonome Domänen): workspace, automation, automation2, chatbot, commcoach, neutralization, realEstate, trustee, teamsbot |
|
||||
| `interfaces/` | DB-Interfaces (App, Billing, Chat, Knowledge, Management, Subscription), AI-Objects, RBAC, Features, Messaging |
|
||||
| `migration/` | Daten-Migrationen |
|
||||
| `routes/` | REST-API-Routen (30+ Dateien: Admin, Billing, DataFiles, DataSources, Security, Store, System...) |
|
||||
| `security/` | Sicherheits-Middleware |
|
||||
| `serviceCenter/` | Zentrale Service-Orchestrierung (siehe Abschnitt 3) |
|
||||
| `serviceHub/` | Service-Registry und Dependency Injection |
|
||||
| `shared/` | Gemeinsame Utilities (attributeUtils, etc.) |
|
||||
| `system/` | System-Konfiguration |
|
||||
| `workflows/` | Workflow-Engine mit Methoden und Aktionen (siehe Abschnitt 4) |
|
||||
|
||||
### Interfaces (DB-Schicht)
|
||||
|
||||
Die Interfaces kapseln alle Datenbankzugriffe:
|
||||
|
||||
| Interface | Verantwortlich für |
|
||||
|-----------|--------------------|
|
||||
| `interfaceDbApp.py` | User, Mandate, FeatureAccess, UserConnections, Preferences |
|
||||
| `interfaceDbBilling.py` | BillingAccount, BillingTransaction, Subscriptions |
|
||||
| `interfaceDbChat.py` | ChatWorkflow, ChatMessage, ChatDocument |
|
||||
| `interfaceDbKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory (RAG/Knowledge Store) |
|
||||
| `interfaceDbManagement.py` | FileItem, Folder, Prompt, DataSource (mandantenweite Stammdaten) |
|
||||
| `interfaceDbSubscription.py` | Subscription-Verwaltung |
|
||||
| `interfaceAiObjects.py` | AI-Call-Abstraction (Text, Embedding, Vision, Streaming) |
|
||||
| `interfaceFeatures.py` | Feature-Instanz-Lifecycle, Template-Rollen-Kopie |
|
||||
| `interfaceRbac.py` | RBAC-Regelauswertung |
|
||||
|
||||
---
|
||||
|
||||
## 3. ServiceCenter (Kern-Orchestrierung)
|
||||
|
||||
Das ServiceCenter ist die zentrale Schicht, die alle Services verbindet. Es wird pro Request/Session erstellt und propagiert einen **ServiceCenterContext** (`context.py`).
|
||||
|
||||
### Services (`serviceCenter/services/`)
|
||||
|
||||
| Service | Pfad | Zweck |
|
||||
|---------|------|-------|
|
||||
| `serviceAgent` | `mainServiceAgent.py` (3400+ Zeilen) | AI-Agent mit 30+ Tools (readFile, writeFile, searchInFileContent, browseContainer, summarizeContent, readContentObjects, webSearch, sendMail, etc.) |
|
||||
| `serviceAi` | `mainServiceAi.py` (1700+ Zeilen) | AI-Call-Gateway: Neutralisierung, Billing-Preflight, Provider-Selection, Streaming, Extraction, Generation |
|
||||
| `serviceKnowledge` | `mainServiceKnowledge.py` | Knowledge Store: Indexierung, Semantic Search, RAG-Kontext-Aufbau (`buildAgentContext`) |
|
||||
| `serviceBilling` | | Billing-Checks, Transaktionen |
|
||||
| `serviceChat` | | Chat-Persistence |
|
||||
| `serviceExtraction` | | Dokument-Extraktion (PDF, DOCX, XLSX...) |
|
||||
| `serviceGeneration` | | Dokument-Generierung |
|
||||
| `serviceMessaging` | | E-Mail, Notifications |
|
||||
| `serviceSubscription` | | Subscription-Verwaltung |
|
||||
| `serviceWeb` | | Web-Scraping |
|
||||
|
||||
### ServiceCenterContext (`context.py`)
|
||||
|
||||
Propagiert pro Request:
|
||||
- `userId`, `mandateId`, `featureInstanceId`
|
||||
- `requireNeutralization: Optional[bool]` — Chat-Level Neutralisierungsflag
|
||||
- Provider-Restrictions, Billing-Context
|
||||
|
||||
### Agent-Tools (in `mainServiceAgent.py`)
|
||||
|
||||
Der Agent hat 30+ registrierte Tools. Tools liefern direkt Rohdaten — Neutralisierung erfolgt zentral im AI-Service (`mainServiceAi.py`) bevor Daten an ein AI-Modell gesendet werden.
|
||||
|
||||
Datenschutz-relevante DataSource-Tools:
|
||||
- `_resolveDataSource()` — liest `neutralize`-Flag der DataSource als 4. Tuple-Element
|
||||
- `_downloadFromDataSource()` — vererbt `neutralize`-Flag auf erstellte FileItems
|
||||
- `_queryFeatureInstance()` — setzt `requireNeutralization=True` auf Sub-Agent AI-Calls wenn FeatureDataSource `neutralize=True`
|
||||
|
||||
---
|
||||
|
||||
## 4. Workflow-Engine
|
||||
|
||||
### WorkflowManager (`workflows/workflowManager.py`, 1400+ Zeilen)
|
||||
|
||||
Zentrale Workflow-Steuerung für Automation und dynamische Workflows.
|
||||
|
||||
### Methoden (`workflows/methods/`)
|
||||
|
||||
| Methode | Aktionen |
|
||||
|---------|----------|
|
||||
| `methodContext` | `extractContent`, `neutralizeData`, `saveContent`, `transformContent` |
|
||||
| `methodAi` | AI-Analyse, Summarization, Prompt-Processing |
|
||||
| `methodChatbot` | Chatbot-spezifische Aktionen |
|
||||
| `methodSharepoint` | SharePoint-Integration |
|
||||
| `methodOutlook` | Outlook/E-Mail-Integration |
|
||||
| `methodJira` | Jira-Integration |
|
||||
| `methodTrustee` | Trustee-Feature-Aktionen |
|
||||
|
||||
---
|
||||
|
||||
## 5. Neutralisierungs-System (KRITISCH)
|
||||
|
||||
**Architektur, Prozess und Code-Karte (ein Dokument):** [wiki/compliance/Neutralisierung.md](../compliance/Neutralisierung.md)
|
||||
|
||||
### Prinzip: Zentrales Gate — ALLE Daten, die an ein AI-Modell gehen, werden AUSSCHLIESSLICH in `mainServiceAi.py` neutralisiert.
|
||||
|
||||
### Architektur: Einzige zentrale Stelle
|
||||
|
||||
Neutralisierung findet nur an **einer einzigen Stelle** statt: `_shouldNeutralize()` und `_neutralizeRequest()` in `mainServiceAi.py`. Kein anderer Service, kein Tool und kein Workflow prüft oder neutralisiert eigenständig. Failsafe: Wenn Neutralisierung erforderlich ist (`requireNeutralization=True`) und fehlschlägt, wird der AI-Call blockiert (`RuntimeError`).
|
||||
|
||||
### Neutralisierungs-Trigger (Prioritätsreihenfolge)
|
||||
|
||||
1. **Per-Request:** `AiCallRequest.requireNeutralization = True/False` — expliziter Override
|
||||
2. **Chat-Level:** `ServiceCenterContext.requireNeutralization = True` — Session-Level-Flag
|
||||
3. **Mandate-Config:** `NeutralizationConfig.enabled` — mandantenweite Konfiguration
|
||||
|
||||
### Was neutralisiert wird (in `_neutralizeRequest`)
|
||||
|
||||
- `request.prompt` — Benutzer-Prompt
|
||||
- `request.context` — RAG-Kontext (externe Dokumente)
|
||||
- `request.messages` — Chat-Nachrichten (OpenAI-Style)
|
||||
|
||||
### Schlüssel-Dateien
|
||||
|
||||
| Datei | Rolle |
|
||||
|-------|-------|
|
||||
| `features/neutralization/serviceNeutralization/mainServiceNeutralization.py` | `processText(text)` → `{neutralized_text, mappings}`, `resolveText(text)` → Rehydrierung |
|
||||
| `routes/routeDataFiles.py` | `PATCH /{fileId}/neutralize` — Toggle löscht Index synchron, re-indexiert im Background |
|
||||
| `serviceAi/mainServiceAi.py` | **Zentrales Gate:** `_shouldNeutralize()` prüft Request → Context → Config; `_neutralizeRequest()` neutralisiert prompt, context, messages. Hard-Mode bei `requireNeutralization=True` |
|
||||
| `serviceKnowledge/mainServiceKnowledge.py` | `indexFile()` neutralisiert bei `FileItem.neutralize=True` (Data-at-rest-Schutz). RAG-Chunks werden neutral gespeichert |
|
||||
| `serviceAgent/mainServiceAgent.py` | `_resolveDataSource()` liest `neutralize`-Flag der DataSource. `_downloadFromDataSource()` vererbt Flag auf erstellte FileItems. `_queryFeatureInstance()` setzt `requireNeutralization=True` wenn FeatureDataSource neutralize-Flag gesetzt |
|
||||
| `workflows/methods/methodContext/actions/neutralizeData.py` | Explizite Neutralisierungs-Aktion in Workflows (prüft nur Config, nicht Context-Flag) |
|
||||
|
||||
### Failsafe-Kette
|
||||
|
||||
1. **Toggle ON:** Index + Chunks werden synchron gelöscht → kein Leak bei Background-Re-Index-Fehler
|
||||
2. **Indexierung:** `indexFile()` neutralisiert Chunks bei `FileItem.neutralize=True` → Data-at-rest ist sicher
|
||||
3. **DataSource-Download:** neutralize-Flag wird auf erstellte FileItems vererbt
|
||||
4. **FeatureDataSource:** `_queryFeatureInstance()` setzt `requireNeutralization=True` auf Sub-Agent AI-Calls
|
||||
5. **AI-Calls (Zentrales Gate):** Hard-Mode (`requireNeutralization=True`) → Prompt-/Context-Fehler = `RuntimeError` (AI-Call blockiert), Message-Fehler = Message entfernt
|
||||
6. **`_rehydrateResponse()`** bleibt als Utility-Methode verfügbar, wird aber nicht mehr automatisch aufgerufen
|
||||
|
||||
### NeutralizationPanel (Frontend)
|
||||
|
||||
`frontend_nyla/src/pages/views/workspace/NeutralizationPanel.tsx` — zeigt alle Files mit `neutralize`-Flag, deren Status und Platzhalter-Mappings. API: `GET /api/workspace/{instanceId}/files` → `{files: [...]}`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Frontend-Architektur
|
||||
|
||||
### Struktur (`frontend_nyla/src/`)
|
||||
|
||||
| Ordner | Inhalt |
|
||||
|--------|--------|
|
||||
| `pages/` | Seiten: admin/, basedata/, billing/, settings/, views/ (workspace, commcoach, chatbot, trustee, automation) |
|
||||
| `components/` | Wiederverwendbar: FormGenerator, FolderTree, Navigation, UnifiedDataBar, Automation2FlowEditor, OnboardingAssistant |
|
||||
| `hooks/` | useApi, useFiles, useNavigation, useConfirm, usePrompt, useResizablePanels, etc. |
|
||||
| `contexts/` | FileContext, PekContext, ToastContext, WorkflowSelectionContext |
|
||||
| `api/` | API-Client (api.ts) und Feature-spezifische API-Module |
|
||||
| `core/` | PageManager |
|
||||
| `layouts/` | Layout-Komponenten |
|
||||
| `locales/` | i18n |
|
||||
| `types/` | TypeScript-Typen |
|
||||
| `utils/` | Utility-Funktionen |
|
||||
|
||||
### Wichtige UI-Komponenten
|
||||
|
||||
| Komponente | Zweck |
|
||||
|------------|-------|
|
||||
| `UnifiedDataBar (UDB)` | Multi-Tab-Panel: Chats, Files, Sources — wird in Workspace und CommCoach genutzt |
|
||||
| `FormGenerator` | Dynamische Formulare/Tabellen aus Backend-Attribut-Definitionen |
|
||||
| `FolderTree` | Rekursiver Ordnerbaum mit Drag&Drop, Multi-Selection, Inline-Editing |
|
||||
| `MandateNavigation` | Feature-Baum-Navigation mit Mandanten-Kontext |
|
||||
| `Automation2FlowEditor` | n8n-style Flow-Builder für Automation2 |
|
||||
| `WorkspacePage` | AI-Workspace mit Chat, UDB, Agent-Streaming |
|
||||
|
||||
### UI-Regeln
|
||||
|
||||
- **Keine Browser-Dialoge** (alert/confirm/prompt) — stattdessen `useConfirm()` und `usePrompt()` Hooks
|
||||
- Alle internen Funktionen mit `_` Prefix
|
||||
- camelCase für Variablen und Funktionen
|
||||
|
||||
---
|
||||
|
||||
## 7. RBAC-System (Zwei getrennte Rollensysteme!)
|
||||
|
||||
### Mandantenrollen
|
||||
- Labels: `admin`, `user`, `viewer`
|
||||
- Scope: `mandateId`, kein `featureCode`/`featureInstanceId`
|
||||
- Junction: `UserMandateRole`
|
||||
|
||||
### Feature-Instanz-Rollen
|
||||
- Labels: `workspace-admin`, `workspace-user`, `workspace-viewer`, etc.
|
||||
- Scope: `mandateId` + `featureCode` + `featureInstanceId`
|
||||
- Junction: `FeatureAccessRole`
|
||||
|
||||
**Strikte Regel:** NIE eine Mandantenrolle einer FeatureAccessRole zuweisen oder umgekehrt.
|
||||
|
||||
---
|
||||
|
||||
## 8. Billing & Subscriptions
|
||||
|
||||
- **Modell:** PREPAY_MANDATE (kein PREPAY_USER)
|
||||
- **Billing-Check:** Vor jedem AI-Call via `_preflightBillingCheck` und `_checkBillingBeforeAiCall`
|
||||
- **Datenvolumen:** `assertCapacity("dataVolumeMB")` prüft RAG-Index-Grösse
|
||||
- **Trial:** 5 CHF, Standard: 10 CHF/Monat
|
||||
|
||||
---
|
||||
|
||||
## 9. AI-Core (Provider-Abstraction)
|
||||
|
||||
### Model-Registry (`aicoreModelRegistry.py`)
|
||||
Registriert alle Provider-Plugins und deren Modelle dynamisch.
|
||||
|
||||
### Model-Selector (`aicoreModelSelector.py`)
|
||||
Wählt optimal basierend auf: Operation Type, Prompt-Grösse, Provider-Restrictions, Score-Ranking.
|
||||
|
||||
### Provider-Plugins
|
||||
- `aicorePluginAnthropic.py` — Claude Sonnet/Haiku/Opus
|
||||
- `aicorePluginOpenai.py` — GPT-4o, Embeddings (text-embedding-3-small/large), DALL-E
|
||||
- `aicorePluginMistral.py` — Mistral Large/Small, Mistral Embed
|
||||
- `aicorePluginPerplexity.py` — Sonar/Sonar-Pro
|
||||
- `aicorePluginTavily.py` — Web-Search
|
||||
- `aicorePluginPrivateLlm.py` — Private LLM
|
||||
- `aicorePluginInternal.py` — Interne Extraktoren/Generatoren/Renderer
|
||||
|
||||
### Operation Types
|
||||
`dataExtract`, `dataAnalyse`, `agent`, `embedding`, `imageGeneration`, `vision`, `webSearch`
|
||||
|
||||
---
|
||||
|
||||
## 10. Knowledge Store (RAG)
|
||||
|
||||
### Datenmodelle (`datamodelKnowledge.py`)
|
||||
- `FileContentIndex` — Pro File: Struktur, Metadaten, `isNeutralized`, `neutralizationStatus`, `totalObjects`, `totalSize`
|
||||
- `ContentChunk` — Semantische Chunks mit Embedding-Vektor, `fileId`, `data`, `metadata`
|
||||
- `RoundMemory` — Kontext aus früheren Runden (file_ref, etc.)
|
||||
|
||||
### Indexierung (`serviceKnowledge.indexFile()`)
|
||||
1. Extraktion via `serviceExtraction`
|
||||
2. Optional: Neutralisierung via `serviceNeutralization.processText()`
|
||||
3. Chunking + Embedding
|
||||
4. Speicherung in `FileContentIndex` + `ContentChunk`
|
||||
|
||||
### RAG-Kontext (`serviceKnowledge.buildAgentContext()`)
|
||||
1. Semantic Search via pgvector
|
||||
2. Context-Budget: Priorisierte Layer (File-Refs, Instance Docs, Mandate Docs)
|
||||
3. Neutralisierung erfolgt zentral im AI-Service wenn der RAG-Kontext als `request.context` an ein AI-Modell geht
|
||||
|
||||
---
|
||||
|
||||
## 11. Feature-Module
|
||||
|
||||
| Feature | Beschreibung |
|
||||
|---------|-------------|
|
||||
| `workspace` | AI-Agent-Workspace mit Chat, Tools, RAG, Streaming |
|
||||
| `automation` | Workflow-Automatisierung (v1) |
|
||||
| `automation2` | Flow-Editor n8n-Style (v2) |
|
||||
| `chatbot` | Chatbot-Feature |
|
||||
| `commcoach` | Kommunikations-Coach mit Voice, Dossier, UDB |
|
||||
| `neutralization` | Datenneutralisierungs-Service und Config |
|
||||
| `trustee` | Trustee/Treuhand-Feature (Buchhaltung, Positionen) |
|
||||
| `realEstate` | Immobilien-Feature |
|
||||
| `teamsbot` | MS Teams Bot |
|
||||
|
||||
---
|
||||
|
||||
## 12. Coding-Konventionen
|
||||
|
||||
- Alle internen Funktionen beginnen mit `_` Prefix
|
||||
- camelCase für Variablen und Funktionsnamen (kein snake_case)
|
||||
- Keine Browser-Dialoge — `useConfirm()` / `usePrompt()` Hooks
|
||||
- Fehler propagieren — keine stillen Fallbacks bei kritischen Pfaden
|
||||
- Pydantic-Models als einzige Quelle für UI-Feld-Definitionen
|
||||
- `PowerOnModel` als Basis mit `sysCreatedAt`, `sysCreatedBy`, `sysModifiedAt`, `sysModifiedBy`
|
||||
Loading…
Reference in a new issue