docs: complete wiki restructuring - new folder hierarchy, canonical reference pages, archive old docs

Made-with: Cursor
This commit is contained in:
ValueOn AG 2026-04-05 23:28:14 +02:00
parent 85ac177caf
commit 8bd4e67be6
251 changed files with 3729 additions and 2 deletions

87
README.md Normal file
View file

@ -0,0 +1,87 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
# PowerOn Portal -- Dokumentation
## Produkt
PowerOn Portal ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung.
| Komponente | Repository | Technologie | Beschreibung |
|-----------|-----------|-------------|-------------|
| Frontend Nyla | `frontend_nyla` | React/TypeScript, Vite | Zentrales UI für alle Features |
| Gateway | `gateway` | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | `private-llm` | Python | Internes LLM für Neutralisierung + sensitive Daten |
| Teams Bot | `service-teams-browser-bot` | Node.js/.NET | Bot für Teams-Meeting-Teilnahme |
| Wiki | `wiki` | Markdown | Dokumentation (dieses Repo) |
---
## Ordnerstruktur
| Ordner | Zweck | Wann nutzen |
|--------|-------|-------------|
| **a-strategy/** | Produkt-Vision, Strategie, Roadmap, Markt, Investor | Richtung setzen, Business-Kontext |
| **b-reference/** | Wie das System funktioniert (code-verifiziert) | System verstehen, Architektur-Fragen |
| **c-work/** | Laufende Arbeit -- Kanban (plan → build → validate → done) | Feature planen, bauen, testen |
| **d-guides/** | How-to: Dev-Setup, Deployment, Testing, Coding-Regeln | Etwas tun, Prozess nachschlagen |
| **e-compliance/** | Sicherheit, Datenschutz, Audit-Dokumente | Regulatorische Fragen |
| **f-decisions/** | Entscheidungen (ADR-light): Kontext, Entscheidung, Konsequenz | Warum wurde X so entschieden? |
| **z-archive/** | Veraltete Docs mit Forward-Link zum Nachfolger | Historischer Kontext |
---
## Lebenszyklus: Feature oder Refactor
```
1. Neues Arbeits-Dokument in c-work/1-plan/ anlegen (Vorlage: c-work/_TEMPLATE.md)
2. Bei Umsetzungsbeginn → nach c-work/2-build/ verschieben
3. Bei Test-Phase → nach c-work/3-validate/
4. Wenn merged/released → nach c-work/4-done/
5. Einmalig: betroffene b-reference/ Seite aktualisieren, TOPICS.md prüfen
6. Arbeits-Dokument → z-archive/ verschieben
```
**Kernregel:** Während Planung, Umsetzung und Testing pflegst du **nur** das eine Arbeits-Dokument in `c-work/`. Kanon-Seiten in `b-reference/` und `TOPICS.md` werden erst am Ende aktualisiert.
---
## b-reference/ Aufbau
```
b-reference/
├── product.md Komponentenübersicht, Repo-Map, Tech-Stack
├── gateway/ Backend-Komponente
│ ├── architecture.md Module, Services, Interfaces
│ ├── ai-agent.md Agent Core, Tools, Knowledge/RAG
│ ├── workflow.md Workflow-Engine, Methoden, Aktionen
│ ├── automation.md Automation v1 + v2
│ ├── billing.md Billing, Subscriptions
│ └── features/ trustee.md, commcoach.md, chatbot.md, ...
├── frontend-nyla/ Frontend-Komponente
│ └── architecture.md Seiten, Komponenten, Hooks, Routing
├── private-llm/ Internes LLM
│ └── architecture.md Setup, Modelle, Gateway-Integration
├── teams-bot/ Teams Meeting Bot
│ └── architecture.md Service, WebSocket, Architektur
└── platform/ Cross-Cutting (repo-übergreifend)
├── neutralization.md Gateway + Private-LLM Zusammenspiel
├── rbac.md Rollensystem (Gateway + Frontend)
└── navigation.md Navigation API (Gateway → Frontend)
```
---
## Für AI-Assistenten
**Immer zuerst laden:** `TOPICS.md` -- dort steht, welche Datei für welches Thema massgeblich ist.
---
## Status-Block (Kopf jeder Kanon-Seite)
```
<!-- status: canonical | draft | superseded -->
<!-- lastReviewed: YYYY-MM-DD -->
<!-- verifiedAgainst: gateway@<sha>, frontend_nyla@<sha> -->
```

45
TOPICS.md Normal file
View file

@ -0,0 +1,45 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
# Themen-Index für AI-Kontext
Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
## Produkt & Strategie
| Thema | Datei | Wann laden |
|-------|-------|------------|
| Produkt-Vision & PMF | a-strategy/product-vision.md | Business-Kontext, Positionierung |
| Produktstrategie | a-strategy/product-strategy.md | Go-to-Market, Preismodell |
| Roadmap | a-strategy/roadmap.md | Priorisierung, Feature-Planung |
## Architektur & Komponenten
| Thema | Datei | Wann laden |
|-------|-------|------------|
| Komponentenübersicht | b-reference/product.md | Repo-übergreifende Fragen, Tech-Stack |
| Gateway-Architektur | b-reference/gateway/architecture.md | Backend-Module, Services, Interfaces |
| AI Agent & Tools | b-reference/gateway/ai-agent.md | Agent-Verhalten, Tool-Registrierung, RAG |
| Workflow-Engine | b-reference/gateway/workflow.md | Methoden, Aktionen, WorkflowManager |
| Automation | b-reference/gateway/automation.md | Automation v1+v2, Templates, Flow-Editor |
| Billing & Subscriptions | b-reference/gateway/billing.md | Abrechnung, Prepaid, State Machine |
| Frontend Nyla | b-reference/frontend-nyla/architecture.md | UI-Seiten, Komponenten, Hooks, Routing |
| Private LLM | b-reference/private-llm/architecture.md | Internes LLM, Neutralisierung |
| Teams Bot | b-reference/teams-bot/architecture.md | Meeting-Bot, WebSocket |
## Cross-Cutting (repo-übergreifend)
| Thema | Datei | Wann laden |
|-------|-------|------------|
| Neutralisierung | b-reference/platform/neutralization.md | Datenschutz, AI-Call-Pipeline, Failsafe |
| RBAC | b-reference/platform/rbac.md | Berechtigungen, Mandate- und Feature-Rollen |
| Navigation | b-reference/platform/navigation.md | Menü-Struktur, Admin-Seiten, API |
## Prozess & Betrieb
| Thema | Datei | Wann laden |
|-------|-------|------------|
| Coding-Regeln | d-guides/coding-conventions.md | Naming, Patterns, Anti-Patterns |
| Testing-Strategie | d-guides/testing-strategy.md | Testpyramide, AC-Format, Test-Pfade |
| Deployment | d-guides/deployment.md | Release-Prozess, Environments |
| Dev-Setup | d-guides/dev-setup.md | Lokale Umgebung starten |

View file

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View file

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View file

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View file

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View file

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
<mxfile host="Electron" modified="2025-12-02T13:13:53.592Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="Qk9c24H_WZZPEQdUvbO1" version="20.3.0" type="device"><diagram name="Module Dependencies" id="module-dependencies">7ZzZcuI4FIafhnvLC8tldxJ6uipT1dVc9LViH4M7xqKECGGefuRYwrJlHJrxoilxlfjIC/yftv8YaeI9bN+/Ubzb/E0iSCeuE71PvMeJ67oL3+V/8sipiCAXzYrImiaRiJWBVfIPiKAjoockgn3lREZIypJdNRiSLIOQVWKYUnKsnhaTtPrUHV6DFliFONWjv5KIbUTUd5yy4C9I1hv5aEeWbLE8WwT2GxyRoxLynibeAyWEFf9t3x8gzeWTwhTXLS+Unj8ZhYxdcwF/PoWouOoNpweohpfiU7KT/O6UHLII8qvRxPt63CQMVjsc5qVHjpvHNmybiuI4SdMHkhL6ca0HKA7imMf3jJJXUEocFMwWL+cSqaqb34NkbCWej+RxUSWQz4/1byxEeAPK4F0JCQW+AdkCoyd+iiidSjyiQi7k8VGhK4ltFLBTEcOiQq3Pty4l5/8I1ZsJRJjhbd5G9hoFtahbErEHQRw0kfAx8uehKSRmwYAkRHdBqE5CLeqYRMxZOE0kYBrwjmMsEm6NxHTINoGTkFDQKMiwHQTKUWMMBHugb0kIelMoCzoeHOZxAIsmDOglAHc0DLMaBX8+IIUkY0Bj3MRBLeq8QSxCv4lEHMxiPlcbiYRfI+EN2x7CA03YqaE9yIKuKcALQBOFlxkK0WhD9HxWozDkEB0DZgfa0BrKgo4poHje3Ct53nSBYCwK9eEZDUnhSOhrnOY2qo5BKel4dHBiN0aN1sHxI9+cQXpQEFxR1tAYZLjjphCCD2ETgvncAT8eC0HdMwwJAKI1IE1/Tfb8NKkCoWxD1iTD6VMZ/VoFU57zTMhOBH8DYyehHT4wUoWlSw9Z9CVPdvDDl5SEr0VomaTykt+H7U5+KkzDNhp7cqBhgyv9SL1gugZxuppOyL90Kz8KKWbJWzWp8l9puJbRqJtWlUad1DhEvDsRg9qHbxkNNZVgXtsI7jQMaRdTy0hU8zsqC5XROCxmdxZG9VLzOw9xcj0fNw6PxZ2HHDcqWblxaMi30nccBgzjyDY3Xu+RzBrJkW12vA1H3RiOhMQ2P96GxIz5FbLNlLchqb7iGQmIbb68DUh1uB8JiG32vBXI+LMs+xy66jMMHEHss+iXgJhh0ZF9Hv0SkPG7K9c2h16dQ5nXXbm2ufTLQMzorqT+dyBGTHdd2zx6C47xRw/b3PllGLUf/o3EwzZzXlPdrAyva5szb6FhyOTKNnPeQsSIwdw2b97GY/zR3DZjrv5G3LzOyrPNml/CYcJrD882W34Jhhmm3LPNlF/CYcKvfDzbLPllGONPqTzbLPlFGKPPp7z/rRvXlrFFnhu7+TK2CO835w9z6/sQhYxZQ0sKay6ERu1ZCSvsGLyzJqmlbhnJcoDqWkERwmmyzvhhCnF+h3xBXxLi9IsIb5Mo+mDftAqxrA/5ys62RYRuG5DrFxEGn68hdBrWEHodrCEseOhTr2WuAUdPMh5/xiegGpzBN+PpXulrd1PoTml9VvXIrVAvGt+0zU73GiP5e6bhRNZnS9+zmGL+bQ9h7nP6kfuWnVx6kPvaFcjdya3Ph1bFNK2fruOWrVp60Hk+eLXWJzvf5XjeV43+861Yulf6vF3dcErrrxVWZxfYi9A37LbSg9DB4FVaf1uwLFJR/eh8y34qPei8GLxC628Bfok8eT999C0bpnQvtOcOXqH1BP/P3D33U51v2ROlB5Wng1fnhlVvDwkNDynmCjuPsOPnQBaeNLmNMZTCQDr9EFlcWe/d7ohck72/Limi1tYr0yTVVvR5xucP0iqfpkgUjYMGiWXs6kyKeMIPkvBPouwzVCHs18kV2R9xUQlPuw9Cn9yoSBdpN/qoBedv3VQx+GG5c3BxerkDs/f0Lw==</diagram></mxfile>

View file

@ -0,0 +1,75 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: frontend_nyla (codebase audit 2026-03-29) -->
# Frontend Nyla -- Architektur
## Überblick
Frontend Nyla ist eine React-Single-Page-Application (SPA) mit TypeScript und Vite. Routing über React Router; Schichten: Presentation (Pages, Components), Business Logic (Hooks, `*Logic`-Module), Data Access (`api.ts`, Feature-API-Module), Infrastructure (Contexts, Provider, Konfiguration). **PageManager** lädt Seiten dynamisch (Lazy Loading, State Preservation, Lifecycle-Hooks). Authentifizierung über Azure MSAL; HTTP über Axios mit Interceptors.
Technologie-Stack (Stand UI-Doku): React 19.x, Vite 5.x, TypeScript 5.8.x, React Router DOM 7.x, Axios, `@azure/msal-browser` / `@azure/msal-react`, Framer Motion, XState, CSS Modules, React Icons.
## Ordnerstruktur (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 |
Ergänzend typische Root-Dateien und Bereiche im Repo: `main.tsx`, `App.tsx`, `api.ts` (Root), `auth/` (MSAL, ProtectedRoute), `assets/` — Feature-Module unter `components/` oft nach Muster: Haupt-`.tsx`, `*.module.css`, `*Logic.tsx`, `*Types.ts`, optional `index.ts`.
## 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 |
## Routing
- **Einstieg:** `main.tsx` rendert `App.tsx` mit Providern (z. B. Sprache, Auth) und **React Router** (`Routes` / `Route`).
- **Geschützte Bereiche:** Route-Guards (z. B. `ProtectedRoute`) prüfen Authentifizierung; Redirect bei fehlender Session.
- **Haupt-App:** Nach Login typischerweise ein Home-/Shell-Layout mit **Sidebar** und **PageManager**.
- **Seiten-Mapping:** `PageManager` + Konfiguration (z. B. `pageConfigs`) — lazy geladene Page-Komponenten, Sidebar-Metadaten, optional `preserveState` für Navigation ohne State-Verlust.
- **i18n / Theme:** global über Context; API-Requests mit Auth-Header (Interceptor in zentralem API-Client).
## UI-Regeln
- **Keine Browser-Dialoge** (`alert` / `confirm` / `prompt`) — stattdessen `useConfirm()` und `usePrompt()` Hooks
- Alle internen Funktionen mit `_` Prefix
- camelCase für Variablen und Funktionen
## Schlüssel-Dateien
| Datei / Bereich | Rolle |
|-----------------|--------|
| `main.tsx` | Application Entry Point |
| `App.tsx` | Root-Komponente, Router-Setup, Provider |
| `api.ts` (Root) | Axios-Instanz, Base URL, Token-Interceptor, 401-Handling |
| `core/` / `components/PageManager/` | Dynamisches Laden, Animationen, Lifecycle, Caching |
| `pageConfigs` (o. ä.) | Lazy Imports, Sidebar-Einträge, Page-Metadaten |
| `auth/authConfig`, `authProvider`, `ProtectedRoute` | MSAL, geschützte Routen |
| `contexts/*` | FileContext, PekContext, Toast, Workflow-Auswahl, etc. |
| `locales/*` | Übersetzungen (z. B. de / en / fr) |
## Regeln / Invarianten
- **Feature-Organisation:** UI, Logic (`*Logic`), Types und CSS Modules pro Feature-Modul trennen; Exporte über `index.ts` wo üblich.
- **Datenfluss:** Pages → Feature-Komponenten → Hooks → `useApi` / API-Module → Gateway; Fehler nicht verschlucken, konsistente Backend-Fehlerdarstellung.
- **Performance:** Seiten lazy laden; bei konfigurierten Seiten State Preservation nutzen.
- **Styling:** CSS Modules, Theme über CSS-Variablen (Light/Dark) wo vorgesehen.
- **Typisierung:** TypeScript durchgängig; API-Response-Typen an den Grenzen definieren.
- **Naming:** Komponenten PascalCase, Hooks `use*`, interne Hilfsfunktionen `_` + camelCase — kein `snake_case` in neuem Frontend-Code.

View file

@ -0,0 +1,237 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# AI Agent & Knowledge Store
## Überblick
Der **AI-Agent** ist der Service `serviceAgent` (`AgentService`) im **ServiceCenter**. Er orchestriert einen **ReAct-Loop** mit nativer Function Calling-Unterstützung: pro Runde ruft das Modell `serviceAi` auf; bei Tool-Calls werden Handler über die **Tool Registry** ausgeführt und Ergebnisse wieder in den Konversationskontext gegeben. Er ist die zentrale Schicht für den **Workspace** (Chat, Streaming, Tools, Dateien, externe Quellen).
Darunter liegt **`serviceAi`** als Low-Level-Gateway (Billing-Preflight, Provider-/Modellwahl, Neutralisierung vor Modellaufruf). **`serviceKnowledge`** liefert **RAG**: Indexierung extrahierter Inhalte, semantische Suche (pgvector) und **`buildAgentContext`** für kontextuelle Injektion vor jeder Agent-Runde.
Der **AI-Core** (`gateway/modules/aicore/`) kapselt Provider-Plugins und die Modellwahl; der Agent nutzt ihn indirekt über `serviceAi` (u. a. `OperationTypeEnum.AGENT`, Embeddings für den Knowledge Store).
---
## Agent Core
### ServiceCenter-Integration
| Registry-Key | Klasse | `objectKey` | Dependencies (laut `registry.py`) |
|--------------|--------|-------------|-----------------------------------|
| `agent` | `AgentService` | `service.agent` | `ai`, `chat`, `utils`, `extraction`, `billing`, `streaming`, `knowledge` |
| `knowledge` | `KnowledgeService` | `service.knowledge` | `ai` |
Pro Request propagiert der **ServiceCenterContext** u. a. `userId`, `mandateId`, `featureInstanceId` und optional `requireNeutralization` (siehe Invarianten).
### Ablauf (Ist-Code)
- **Einstieg:** `AgentService.runAgent` (`mainServiceAgent.py`) — baut die Tool Registry, optional Anreicherung des Prompts mit Datei-Metadaten/`FileContentIndex`, startet `runAgentLoop` (`agentLoop.py`).
- **Loop:** `runAgentLoop``ConversationManager` + Systemprompt; **pro Runde:** optional RAG via `buildRagContextFn`, Budget-Check, **Progressive Summarization** bei Bedarf (`ConversationManager`, Modell-Operation `DATA_ANALYSE`), dann `AiCallRequest` mit `OperationTypeEnum.AGENT`, `messages`, `tools`.
- **Tool Registry:** `_registerCoreTools` in `mainServiceAgent.py` registriert die Kern-Tools; **`ActionToolAdapter`** registriert alle Workflow-Actions mit `dynamicMode=True` als zusätzliche Tools (`method_action` → intern `executeAction`).
- **Parallele Ausführung:** In `_executeToolCalls` werden als **`readOnly=True`** markierte Tool-Calls parallel (`asyncio.gather`), schreibende/übrige sequentiell — vermeidet Race Conditions bei zustandsändernden Tools.
- **Budget:** `AgentConfig.maxCostCHF` — vor jeder Runde Abgleich mit Workflow-Kosten; bei Überschreitung Status `budgetExceeded` und abschliessender Fortschritts-Text (`FINAL`).
- **Rundenlimit:** `AgentConfig.maxRounds` (Default 25); bei Erreichen während `running` → Status `maxRoundsReached` und Fortschritts-Zusammenfassung.
- **Degradation:** Schlägt RAG-Injektion fehl, wird nur geloggt (**non-blocking**); der Agent läuft ohne diesen Kontext weiter. Fehlgeschlagene RoundMemory-Persistenz ebenfalls non-blocking.
- **Streaming:** Optional `aiCallStreamFn` — Chunks als `CHUNK`-Events; Abschluss u. a. `AGENT_SUMMARY` mit Kosten- und Round-Metriken; Trace kann über Knowledge-Entities persistiert werden (`_persistTrace`).
### Konfiguration (`datamodelAgent.AgentConfig`, Ist)
| Feld | Bedeutung |
|------|-----------|
| `maxRounds` | Max. Schleifenrunden (Default 25, 1100) |
| `maxCostCHF` | Optionales Workflow-Budget in CHF |
| `toolSet` | Aktives Tool-Set (Default `"core"`) |
| `temperature` | Optional für den Agent-AI-Call |
### RBAC (Architekturentscheid)
Keine separate Tool-Level-RBAC: Zugriff wird über **Datenbank-RBAC** (z. B. File-Queries), **OAuth/Connections** bei externen Quellen und **`serviceAi`** (Billing, Provider-/Modell-RBAC) sowie **`can_access_service`** für `service.agent` durchgesetzt.
---
## Agent Tools
### Prinzip
Tools sind registrierte Handler mit JSON-Schema für Argumente, **`readOnly`-Flag** (Parallelisierung) und optional `toolSet`. Tool-Ausgaben sind Rohdaten für das Modell; **Neutralisierung vor dem LLM** erfolgt zentral in `serviceAi`, nicht in den Tools.
Zusätzlich zu den unten genannten **Kern-Tools** existieren **dynamische Tools** aus dem Workflow-System: `ActionToolAdapter` liest `methodDiscovery.methods` und registriert jede Action mit `dynamicMode=True` unter einem zusammengesetzten Namen (`{methodShort}_{actionName}`); im Adapter sind diese derzeit **alle als nicht-readOnly** registriert.
### Kern-Tools (registriert in `_registerCoreTools`, 40 Stück)
**Workspace / Dateien**
| Tool | Kurzbeschreibung |
|------|------------------|
| `readFile` | Dateiinhalt lesen (optional zeilenweise) |
| `listFiles` | Dateien filtern (Ordner, Tags, Suche) |
| `searchInFileContent` | Suche im Dateiinhalt |
| `writeFile` | Datei anlegen / anhängen / überschreiben |
| `deleteFile` | Datei löschen |
| `renameFile` | Umbenennen |
| `moveFile` | Verschieben (Ordner) |
| `tagFile` | Tags setzen |
| `copyFile` | Unabhängige Kopie |
| `replaceInFile` | Ersetzen im Text |
**Ordner**
| Tool | Kurzbeschreibung |
|------|------------------|
| `listFolders` | Ordner auflisten |
| `createFolder` | Ordner anlegen |
| `deleteFolder` | Ordner löschen (optional rekursiv) |
| `renameFolder` | Ordner umbenennen |
| `moveFolder` | Ordner verschieben |
**Web & Sprache**
| Tool | Kurzbeschreibung |
|------|------------------|
| `webSearch` | Websuche |
| `readUrl` | Inhalt einer bekannten URL laden |
| `translateText` | Übersetzung (Voice/Translation-Pipeline) |
| `textToSpeech` | TTS |
| `speechToText` | Transkription Audio-Datei |
| `detectLanguage` | Spracherkennung für Text |
**Externe Datenquellen / Mail**
| Tool | Kurzbeschreibung |
|------|------------------|
| `listConnections` | User-Connections auflisten |
| `browseDataSource` | Externe Quelle durchsuchen |
| `searchDataSource` | Suche in Datenquelle |
| `downloadFromDataSource` | Download → FileItem (inkl. Vererbung `neutralize` auf Datei, siehe Invarianten) |
| `uploadToExternal` | Upload zu externer Quelle |
| `sendMail` | E-Mail senden |
**Dokumente / Content-Objekte**
| Tool | Kurzbeschreibung |
|------|------------------|
| `browseContainer` | Struktur-Index (Seiten, Abschnitte, …) |
| `readContentObjects` | Gezielt Content-Objekte lesen |
| `extractContainerItem` | Element aus Container extrahieren |
| `summarizeContent` | KI-Zusammenfassung |
| `describeImage` | Vision-Analyse |
| `renderDocument` | Dokument rendern |
| `generateImage` | Bildgenerierung |
| `createChart` | Chart erzeugen |
**Feature / Workflow**
| Tool | Kurzbeschreibung |
|------|------------------|
| `queryFeatureInstance` | Abfrage anderer Feature-Instanz (setzt bei Bedarf `requireNeutralization` für Sub-Calls) |
| `listWorkflowHistory` | Workflow-Historie |
| `readWorkflowMessages` | Nachrichten eines Workflows lesen |
**Sicherheit / Ausführung**
| Tool | Kurzbeschreibung |
|------|------------------|
| `neutralizeData` | Anonymisierter Text (non-destructive) |
| `executeCode` | Sandboxed Code-Ausführung (siehe `sandboxExecutor.py`) |
---
## AI-Core (Provider-Abstraction)
| Komponente | Datei / Rolle |
|------------|----------------|
| **Model Registry** | `aicoreModelRegistry.py` — registriert Provider-Plugins und Modelle |
| **Model Selector** | `aicoreModelSelector.py` — Auswahl nach Operationstyp, Promptgrösse, Restriktionen, Ranking |
### Provider-Plugins (Dateien unter `gateway/modules/aicore/`)
| Plugin-Modul | Typische Rolle |
|--------------|----------------|
| `aicorePluginAnthropic.py` | Claude-Modelle |
| `aicorePluginOpenai.py` | GPT, Embeddings, Bild |
| `aicorePluginMistral.py` | Mistral Chat / Embed |
| `aicorePluginPerplexity.py` | Sonar / Recherche |
| `aicorePluginTavily.py` | Web-Suche |
| `aicorePluginPrivateLlm.py` | Private LLM |
| `aicorePluginInternal.py` | Interne Extraktion/Generierung/Rendering |
### Operation Types (`datamodelAi.OperationTypeEnum`, Auszug)
u. a. `plan`, `dataAnalyse`, `dataGenerate`, `dataExtract`, `imageAnalyse`, `imageGenerate`, `neutralizationText`, `neutralizationImage`, `webSearch`, `webCrawl`, **`agent`**, **`embedding`**, `speechTeams`.
Der Agent-Loop verwendet **`AGENT`** für Hauptrunden und **`DATA_ANALYSE`** für Summarization-Calls; Embeddings laufen über die Knowledge-Service-Pipeline (`callEmbedding`).
---
## Knowledge Store (RAG)
### Datenmodelle (`datamodelKnowledge.py`)
| Modell | Zweck |
|--------|--------|
| **FileContentIndex** | Strukturindex pro Datei (ohne LLM): `structure`, `objectSummary`, `status`, Spiegelung von Mandat/Instanz über **`scope`** (`personal`, `featureInstance`, `mandate`, `global`), Neutralisierungs-Felder `isNeutralized`, `neutralizationStatus` |
| **ContentChunk** | Persistente Chunks mit Embedding (`vector(1536)`), `data`, `contextRef`, `contentType` |
| **RoundMemory** | Pro Runde: `file_ref`, Tool-Ergebnisse, Entscheidungen — mit Embedding für semantische Wiederverwendung trotz ConversationManager-Kürzung |
| **WorkflowMemory** | Workflow-scoped Key-Value-Cache (Entities, Fakten, inkl. optional Embedding) |
Zugriff über **`interfaceDbKnowledge`** (`FileContentIndex`, `ContentChunk`, RoundMemory, WorkflowMemory).
### Indexierung
**`KnowledgeService.indexFile`** — nach Extraktion (Content-Objekte): übernimmt Scope aus **FileItem** als Single Source of Truth; bei `FileItem.neutralize=True` werden Inhalte vor dem Speichern neutralisiert; Chunking (u. a. `DEFAULT_CHUNK_TOKENS` / Zeichen-Heuristik), Embedding via AI-Service, Persistenz von Index + Chunks; optional Billing-Reconciliation für Mandats-Speicher.
### Semantische Suche & Kontext
**`buildAgentContext`** — priorisierte Schichten (Ist-Code, vereinfacht):
1. **RoundMemory** `file_ref` („Known Files“)
2. **Instance/personal/mandate/global**`semanticSearch` mit Query-Embedding (Limit/Score wie im Code)
3. **RoundMemory** semantisch (`semanticSearchRoundMemory`)
4. **Workflow-Entities** (`getWorkflowEntities`)
5. **Mandate-Scope** — geteilte Mandats-Dokumente („Shared Knowledge“)
6. Optional **Cross-Workflow-Hints** (`workflowHintItems`)
Rückgabe: formatierter String für Injektion in den Agent-Systemkontext. **Wenn Embedding fehlschlägt**, liefert `buildAgentContext` einen **leeren String** (Agent arbeitet ohne diesen RAG-Block).
Erweiterte Hilfen (z. B. **`readSection`**, Caching) für selektives Lesen sind im selben Service dokumentiert.
---
## Schlüssel-Dateien
| Datei | Rolle |
|-------|--------|
| `gateway/modules/serviceCenter/registry.py` | Registrierung `agent`, `knowledge`, Dependencies, `objectKey` |
| `gateway/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py` | `AgentService`, Tool-Registrierung, `runAgent`, DataSource/Neutralize-Hooks |
| `gateway/modules/serviceCenter/services/serviceAgent/agentLoop.py` | ReAct-Loop, Budget, RAG-Injektion, Tool-Dispatch, Summaries |
| `gateway/modules/serviceCenter/services/serviceAgent/toolRegistry.py` | Registrierung, Dispatch, `readOnly`, Function-Calling-Format |
| `gateway/modules/serviceCenter/services/serviceAgent/conversationManager.py` | Kontextfenster, Summarization, Systemprompt |
| `gateway/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` | `AgentConfig`, Events, Trace-Modelle |
| `gateway/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py` | Workflow-Actions → Agent-Tools |
| `gateway/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py` | `executeCode`-Sandbox |
| `gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | Index, `buildAgentContext`, Workflow-/Round-Memory-Helfer |
| `gateway/modules/interfaces/interfaceDbKnowledge.py` | DB-Zugriff Knowledge / RAG |
| `gateway/modules/datamodels/datamodelKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory, WorkflowMemory |
| `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py` | Zentrales Neutralisierungs-Gate vor LLM, Billing, Provider-Aufruf |
| `gateway/modules/aicore/aicoreModelRegistry.py` | Provider-/Modell-Registry |
| `gateway/modules/aicore/aicoreModelSelector.py` | Modellauswahl |
| `gateway/modules/aicore/aicorePlugin*.py` | Provider-Implementierungen |
| `gateway/modules/datamodels/datamodelAi.py` | `OperationTypeEnum`, `AiCallRequest`, Optionen |
---
## Regeln / Invarianten
1. **Neutralisierung vor dem Modell:** Alle an ein LLM gehenden Inhalte (Prompt, Kontext, Messages) werden ausschliesslich in **`serviceAi`** entsprechend Policy neutralisiert bzw. blockiert — nicht in den Agent-Tools.
2. **Tools liefern Rohdaten:** Kein zweites Neutralisieren in Tools; Ausnahme ist bewusste **Data-at-rest**-Neutralisierung beim **Indexieren** (`indexFile` bei `FileItem.neutralize=True`).
3. **DataSource → FileItem:** `_downloadFromDataSource` vererbt das **`neutralize`-Flag** der DataSource auf erzeugte Dateien; **`queryFeatureInstance`** kann Sub-Agent-Calls mit **`requireNeutralization=True`** auslösen, wenn die Feature-Datenquelle das vorsieht.
4. **Kein Tool-RBAC:** Autorisierung über Datenbank-, Connection- und Service-Schicht.
5. **Parallele Tools nur bei `readOnly=True`:** Schreibende Tools nicht parallel zueinander aus demselben Batch.
6. **RAG optional:** Embedding- oder DB-Fehler im Kontextpfad führen nicht zwingend zum Abbruch des Agent-Runs (RAG wird übersprungen/entfällt).
7. **Billing:** AI-Calls und eingebettete Pfade (Embeddings, Summaries) laufen über bestehende Billing-/Subscription-Checks in `serviceAi` bzw. aufrufenden Schichten.
Detaillierte Neutralisierungs-Kette und Compliance: **`wiki/compliance/Neutralisierung.md`**.
Architektur-Roadmap (Unified Workspace, ProviderConnector 1:n, Phasenplan): **`wiki/concepts/AI-Agent-Architecture-Konzept.md`** — als Zielbild lesen, nicht als Ist-Abbild aller Codepfade.

View file

@ -0,0 +1,106 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Gateway -- Architektur
## Überblick
Das Gateway ist das Python-Backend der PowerOn-Plattform (FastAPI, PostgreSQL). Es kapselt Mandanten- und Feature-Logik hinter einer REST-API und folgt einer klaren Schichtenfolge: **Connectors** sprechen externe Systeme und Datenbanken an, **Interfaces** normalisieren Zugriffe und DTOs, **Services** bündeln fachliche Operationen darauf, und das **ServiceCenter** löst diese Services pro Request mit einheitlichem Kontext auf. Routen in `modules/routes/` sind der HTTP-Einstieg; Security-Middleware und gemeinsame Utilities liegen in `modules/security/` bzw. `modules/shared/`. Feature-spezifische Domänen leben in `modules/features/` als weitgehend autonome Module.
## Modulstruktur
Unter `gateway/modules/` (Kontext-Audit):
| 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 (u. a. 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 (u. a. Admin, Billing, DataFiles, DataSources, Security, Store, System) |
| `security/` | Sicherheits-Middleware |
| `serviceCenter/` | Zentrale Service-Orchestrierung (Registry, Resolver, Kontext, Haupt-Services) |
| `serviceHub/` | Service-Registry und Dependency Injection (u. a. `PublicService`-Wrapper) |
| `shared/` | Gemeinsame Utilities (attributeUtils, Konfiguration, Logging, …) |
| `system/` | System-Konfiguration |
| `workflows/` | Workflow-Engine mit Methoden und Aktionen |
## ServiceCenter (Kern-Orchestrierung)
Das ServiceCenter ist die zentrale Schicht, die Kern- und importierbare Services verbindet. Pro Request/Session wird ein **`ServiceCenterContext`** (`serviceCenter/context.py`) mitgeführt und propagiert u. a.:
- `userId`, `mandateId`, `featureInstanceId`
- `requireNeutralization` (optional) — Neutralisierungsflag auf Chat-Ebene
- Provider-Restrictions, Billing-Context
Die öffentliche API umfasst u. a. `getService(key, context)` zur Auflösung einer Service-Instanz; registrierte Services sind in `registry.py` als **CORE_SERVICES** und **IMPORTABLE_SERVICES** hinterlegt, mit feature-spezifischer Auflösung und optionaler Vorabladung (`preWarm`).
### Services (`serviceCenter/services/`)
| Service | Hauptmodul (Auszug) | Zweck |
|---------|---------------------|-------|
| `serviceAgent` | `mainServiceAgent.py` | AI-Agent mit vielen Tools (u. a. Dateien, Suche, Container, Web, Mail) |
| `serviceAi` | `mainServiceAi.py` | AI-Call-Gateway: Neutralisierung, Billing-Preflight, Provider-Auswahl, Streaming, Extraktion, Generierung |
| `serviceKnowledge` | `mainServiceKnowledge.py` | Knowledge Store: Indexierung, semantische Suche, RAG-Kontext (`buildAgentContext`) |
| `serviceBilling` | `mainServiceBilling.py` | Billing-Checks, Transaktionen |
| `serviceChat` | `mainServiceChat.py` | Chat-Persistenz |
| `serviceExtraction` | `mainServiceExtraction.py` | Dokument-Extraktion (PDF, DOCX, XLSX, …) |
| `serviceGeneration` | `mainServiceGeneration.py` | Dokument-Generierung |
| `serviceMessaging` | `mainServiceMessaging.py` | E-Mail, Notifications |
| `serviceSubscription` | `mainServiceSubscription.py` | Subscription-Verwaltung |
| `serviceWeb` | `mainServiceWeb.py` | Web-Scraping |
**Hinweis (Agent):** Agent-Tools liefern Rohdaten; Neutralisierung vor dem Versand an ein Sprachmodell erfolgt zentral im **serviceAi** (`mainServiceAi.py`), nicht in den Tools selbst.
### Einordnung (Framework)
Daten- und Steuerfluss: **Client oder Workflow → Service Center → Service → Interface → Connector → externes System**. Das Service Center bündelt dabei Erkennbarkeit (Registry), Konfiguration und querschnittliche Aspekte wie Logging, RBAC-Objekt-Registrierung (`registerServiceObjects`) und konsistente Service-Lebenszyklen; **`serviceHub`** ergänzt dies mit **`PublicService`**, sodass nur bewusst exponierte Methoden nach außen sichtbar sind.
## Interfaces (DB-Schicht)
Die genannten Module kapseln die Datenbankzugriffe bzw. die zugehörigen Fachverträge (Audit-Liste):
| 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-Abstraktion (Text, Embedding, Vision, Streaming) |
| `interfaceFeatures.py` | Feature-Instanz-Lifecycle, Template-Rollen-Kopie |
| `interfaceRbac.py` | RBAC-Regelauswertung |
Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap) erfüllen dieselbe Normalisierungsrolle gegenüber Connectors bzw. externen APIs; die Tabelle oben entspricht der expliziten DB-/Kern-Zuordnung aus dem Kontext-Audit.
## Schlüssel-Dateien
| Datei / Pfad | Rolle |
|--------------|-------|
| `gateway/app.py` | FastAPI-Anwendung, Einbindung von Routen und Middleware |
| `gateway/modules/serviceCenter/__init__.py` | Service Center: `getService`, `preWarm`, RBAC-Registrierung für Service-Objekte |
| `gateway/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request |
| `gateway/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) |
| `gateway/modules/serviceCenter/resolver.py` | Auflösung von Service-Instanzen inkl. Cache |
| `gateway/modules/serviceHub/__init__.py` | Hub / DI, `PublicService`-Wrapper für kontrollierte Oberflächen |
| `gateway/modules/routes/*.py` | HTTP-Endpunkte, Aufruf in Richtung Service Center / Features |
| `gateway/modules/interfaces/*.py` | Stabile Verträge und DB-Zugriffe (keine direkte Vendor-Logik in Services) |
| `gateway/modules/connectors/*.py` | Vendor-spezifische Adapter (Auth, Transport, Mapping) |
| `gateway/modules/security/*` | CSRF, Token-Refresh-Middleware, JWT/Auth-Utilities |
| `gateway/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
| `gateway/modules/features/init.py` | Initiale Trigger beim App-Start |
| `gateway/modules/workflows/workflowManager.py` | Zentrale Workflow-Steuerung |
## Regeln / Invarianten
- **Schichten:** Connectors sind anbieterspezifisch und ersetzbar; **Services hängen von Interfaces ab, nicht direkt von Connectors**. Geschäftslogik und Guardrails liegen in den Services.
- **Datenbank:** Persistenz und die genannten Domänen-Reads/Writes laufen über die **Interface**-Schicht, nicht ad hoc aus Routen heraus.
- **Service Center:** Aufrufe laufen über die zentrale Auflösung (`getService` + Kontext); Workflows und Routen konsumieren dieselbe Landschaft.
- **Sicherheit & Governance:** RBAC und Geheimnisse werden zentral geführt; Service-Aufrufe und Workflow-Schritte sollen nachvollziehbar sein (Audit); Kontingente und Limits pro Mandant/Service sind vorgesehen.
- **HTTP-Einstieg:** Globale Middleware u. a. CSRF und Token-Refresh; zusätzliche AuthN/AuthZ-Utilities unter `modules/security/`.
- **Code-Konventionen (Projekt):** Interne Hilfsfunktionen mit Präfix **`_`**; Bezeichner in **camelCase** für Variablen und Funktionen.

View file

@ -0,0 +1,97 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Automation
## Überblick
PowerOn hat **mehrere Automatisierungs-Spuren**, die sich die **gleiche Unified Action Library** (`workflows/methods/` + `ActionExecutor`) teilen, aber unterschiedliche **Persistenz**, **Scheduler** und **Execution Engines** nutzen. Die Business Spec beschreibt eine **Ziel-Architektur**: konsolidierte Plattform mit klarer Trennung Mandant / Feature / Feature-Instanz, skalierbarer **Toolbox**-Schicht für Agent-Tools und einem **vereinheitlichten Workflow-Datenmodell** (Draft/Published, Runs, Tracing).
**Leitentscheide (Business Spec):**
- Keine Migration von Altdaten für Automation v1 (nicht produktiv); v1 bleibt bis zur Ablösung.
- **Vier Säulen:** AI Service (Agent, Streaming, Neutralisierung, Failover), Graphical Editor (Flow + künftig Editor-Chat/UDB), Automation Scheduler (Cron/Events/Webhooks), **Unified Action Library** mit Toolboxes.
- **Inkonsistenzen heute:** zwei Workflow-Datenwelten (v1 vs Automation2), zwei DB-Schemas, zwei Scheduler-Patterns, zwei Engines — Ausrichtung über Zielmodell und Übernahme bewährter v1-Scheduler-Patterns in Richtung v2.
---
## Business Spec (Zusammenfassung)
**Ist-Systeme:**
| System | Kurzbeschreibung |
|--------|------------------|
| **Automation v1** | Template + Cron + Placeholders; robuster inkrementeller Scheduler-Sync; keine visuelle Branching-Logik. |
| **Automation2** | n8n-Style Graph; Run/Task; Pause/Resume; Human-in-the-loop; weniger robuster Scheduler-Sync als v1. |
| **AI Workspace** | Chat-Agent mit vielen Tools + RAG; kein persistiertes Workflow-Modell wie im Graph-Editor. |
**Gemeinsame technische Basis:** Alle genannten Pfade führen über **`ActionExecutor.executeAction()`** zur Method/Action Library; der Workspace-Agent mappt `dynamicMode`-Actions via **`ActionToolAdapter`** auf Tools; Automation2-Nodes tragen `_method` / `_action`.
**Toolbox-Konzept (Ziel):** Statt alle Tools flach zu exponieren, **thematische Toolboxes** (`core`, `ai`, `email`, `sharepoint`, `workflow`, …) mit Meta-Tool **`requestToolbox`** — Agent startet schlank, fordert Spezial-Toolboxes nach Bedarf; **`availableToolboxes`** ist pro Feature/RBAC/Connections filterbar.
**Sub-Agents:** Datenintensive Features (z.B. Trustee) kapseln Schema-Wissen in einem **Feature Data Agent**; Main-Agent sieht ein aggregiertes Tool (`queryFeatureInstance`), nicht Dutzende Tabellen-Tools.
**Agent-Run (State Machine, konzeptionell):** `IDLE``THINKING` → bei Tool-Calls `EXECUTING_TOOLS` → optional `TOOLBOX_ESCALATION` / `SUB_AGENT_CALL``COMPLETED` / `FAILED` / `CANCELLED` (Limits: `maxRounds`, `maxCostCHF`).
**RBAC (Kurz):** Zwei getrennte Template-Systeme — **System-Template-Rollen** (Mandant: admin/user/viewer) vs **Feature-Template-Rollen** (Instanz: z.B. workspace-admin); keine Vermischung. Auflösung: höchste Priorität gewinnt bei DATA; View OR über Rollen der Top-Priorität; Item-Spezifität exact > prefix > generic.
---
## Datenmodell (Zusammenfassung)
**Gateway-Schichten (Data Model Doc):** Frontend → **Features** (instanzgebunden) → **Services** (request-scoped) → **Shared Infrastructure** (`workflows/methods`, `workflows/processing`, `workflows/automation2`, `interfaces`, `aicore`, `datamodels`, `security`).
**Feature-Container-Pattern:** `features/<name>/` mit `main*.py` (FEATURE_CODE, UI/RESOURCE/TEMPLATE_ROLES), `routeFeature*.py`, `interfaceFeature*.py`, `datamodelFeature*.py`, optional `nodeDefinitions/`, `service*/`. Discovery über `registry.py` / `ServiceHub` ohne manuelles Wiring sämtlicher Router.
**Ziel-Entitäten (vereinheitlichtes Workflow-Modell, Spec):**
| Entität | Zweck |
|---------|--------|
| **Workflow** | Metadaten, Mandant/Instanz, `active`, optional `eventId` (Scheduler-Job), Zeiger auf aktuelle Version |
| **WorkflowVersion** | Immutabler Snapshot: `graph` (Nodes/Connections), `invocations` (Trigger: manual, schedule, webhook, …), Status **draft / published / archived** |
| **WorkflowRun** | Eine Ausführung: Status (pending → running → completed/failed/paused/cancelled), Trigger-Metadaten, `nodeOutputs`, Pause-/Resume-Kontext, Kostenfelder |
| **RunStepLog** | Pro Node: Input-Snapshot, Output, Dauer, Fehler, Token-Nutzung |
| **HumanTask** | Menschliche Zwischenaufgabe bei Pause (approval/form); Status pending → completed/cancelled/expired |
**Invarianten (Zielmodell):** Pro Workflow höchstens **eine** `PUBLISHED` Version; Scheduler bindet an die veröffentlichte Version. Pause z.B. durch Human-Task-Nodes oder E-Mail-Warten; Resume mit geliefertem Ergebnis.
**Toolbox-Datenmodell (Ziel):** `ToolboxDefinition` (id, label i18n, `tools[]`, optional `requiresConnection`), `ToolboxRegistry`, erweiterte `AgentConfig` mit `initialToolboxes` / `availableToolboxes`.
---
## Automation v1 vs v2
| Aspekt | Automation v1 | Automation2 (v2) |
|--------|----------------|------------------|
| Modell | Template/Cron/Placeholders | Graph + Node-Typen (`nodeDefinitions/`) |
| DB / Schema | `poweron_automation` | `poweron_automation2` |
| Scheduler | Inkrementell, Callback `automation.changed`, `eventId` auf Workflow | u.a. Full re-register, Callback `automation2.workflow.changed` |
| Engine | `WorkflowManager` + `WorkflowProcessor` + `modeAutomation` | `executionEngine.executeGraph` |
| Stärken | Bewährtes Scheduling, Execution-Logs | Branching, Loops, Pause/Resume, visuelles Editing |
**Konsolidierungsrichtung (Spec):** v1-Scheduler-Muster (inkrementell, Job-Handle, Reload+`active`-Check vor Run, capped Logs, `sysCreatedBy` für Kontext) in die v2-Welt übernehmen; einheitliches **Workflow/Version/Run**-Konzept langfristig über beide Welten.
---
## Schlüssel-Dateien
| Bereich | Typische Pfade (`gateway/modules/`) |
|---------|-------------------------------------|
| Action Library | `workflows/methods/`, `workflows/processing/` (`ActionExecutor`, `methodDiscovery`) |
| Automation v1 Feature | `features/automation/` |
| Automation2 Feature | `features/automation2/`, `workflows/automation2/` |
| Agent ↔ Actions | `serviceCenter/services/serviceAgent/` (u.a. Tool-Registrierung, `ActionToolAdapter`) |
| Feature-Discovery | `system/registry.py`, `serviceHub/__init__.py` |
| RBAC | `interfaces/interfaceRbac.py`, `security/`, Rollen/AccessRules in Datamodels |
---
## Regeln / Invarianten
1. **Eine Action Library:** Änderungen an Methods/Actions betreifen Workspace, Automation v1, Automation2 und Agent-Tools gleichzeitig — Kompatibilität und `actionId`-Stabilität beachten.
2. **RBAC strikt trennen:** Mandantenrollen vs Feature-Instanz-Rollen nicht mischen; Permissions über AccessRules und Prioritätsregeln.
3. **Scheduler vs Editor:** Ausführung und Zeitplanung gehören zur **Scheduler-Säule**; der Graph ist **Version**-gebunden (Draft vs Published).
4. **Tool-Skalierung:** Flache Tool-Listen skalieren nicht; Toolbox + `requestToolbox` + connection-basierte Verfügbarkeit sind das vorgesehene Gegenmittel.
5. **Zielmodell vs Ist:** `Workflow` / `WorkflowVersion` / `WorkflowRun` in der Spec sind **Zielarchitektur** — Abgleich mit produktivem Schema bei Implementierungsarbeiten erforderlich.
6. **Neutralisierung / KI:** Plattformweit gelten die zentralen KI-Datenpfade (siehe `workflow.md` / Compliance); Automation nutzt dieselben Services wie der Rest des Gateways.

View file

@ -0,0 +1,186 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Billing & Subscriptions
## Überblick
Die Plattform trennt zwei Ebenen:
1. **Usage-Billing (LLM-Verbrauch):** Prepaid-Guthaben in CHF, Buchung pro AI-Operation (`priceCHF`), Transaktionen mit Mandanten- und Provider-Kontext. Zentrale Erfassung über Billing-Interfaces und `serviceBilling`; Integration im AI-Pfad (`mainServiceAi`).
2. **Mandanten-Subscription (SaaS-Lizenz):** Wiederkehrende Pläne, Kapazitäten (User-Seats, Feature-Instanzen), Stripe für Plattformgebühr und Zahlungsstatus. Vorgesehen als eigener Domänen-Service `serviceSubscription`, gekoppelt an Billing-Checks.
**Gateway-Audit (2026-03-29):** Produktseitig liegt der Schwerpunkt auf **PREPAY_MANDATE** (gemeinsames Mandantenkonto); Billing-Checks und Datenvolumen-Assertions laufen vor AI-Calls. Ergänzend beschreiben die Konzeptdokumente Subscription-Pflicht, Stripe und eine explizite Zustandsmaschine.
Ohne gültige, zahlungswirksame Subscription (soweit implementiert) sollen **nur AI-Calls** blockiert werden; Lesen, Navigation und Datenhaltung bleiben möglich. `Mandate.enabled` bleibt für technische Sperren; Subscription steuert die geschäftliche Nutzbarkeit von KI-Funktionen.
---
## Billing-Modell
### Abrechnungseinheit und Hierarchie
- **Mandant** ist die zentrale Kostenstelle; Benutzer können mehreren Mandanten angehören — Verbrauch wird pro Mandant getrennt erfasst.
- Kosten entstehen an **AICore-Connectoren** (z. B. `anthropic`, `openai`, `perplexity`, `tavily`, `internal`); die erlaubte Provider-Liste ist dynamisch (Model Registry / Plugins).
### Abrechnungsmodelle (`BillingSettings.billingModel`)
| Modell | Kostenstelle | Kurzbeschreibung |
|--------|--------------|------------------|
| `PREPAY_MANDATE` | Mandant | Gemeinsames Guthaben für alle User des Mandanten |
| `PREPAY_USER` | User im Mandanten-Kontext | Eigenes Guthaben pro User; automatisches Startguthaben v. a. für **Root-Mandant** / Bootstrap (`defaultUserCredit`, z. B. 5 CHF) |
| `UNLIMITED` | — | Keine Guthabenlimitierung (interne Mandanten) |
- **`CREDIT_POSTPAY`** ist entfernt; gespeicherte Legacy-Werte werden beim Lesen auf **`PREPAY_MANDATE`** normalisiert (ohne separate DB-Migration).
- **Audit-Hinweis:** Im Gateway-Kontext wird der operative Fokus als **PREPAY_MANDATE** (kein PREPAY_USER im Sinne des Standard-Mandanten-Produkts) geführt; **Root** bleibt im Konzept mit **PREPAY_USER** und Startguthaben beschrieben.
### Kernentitäten
- **`BillingAccount`:** Guthaben (`balance` CHF), optional `userId` bei `PREPAY_USER`, `accountType` MANDATE | USER, `warningThreshold`, `enabled`.
- **`BillingTransaction`:** `CREDIT` | `DEBIT` | `ADJUSTMENT`; Referenzen (`referenceType` / `referenceId`, `workflowId`, `featureInstanceId`, `aicoreProvider`). Mandanten-Kontext über **`BillingAccount.mandateId`** — Chat-Modelle bleiben user-owned ohne `mandateId` in `ChatWorkflow`; Zuordnung für Statistiken über Transaktionen.
- **`BillingSettings`:** Modell, `defaultUserCredit`, `warningThresholdPercent`, `notifyEmails`, `notifyOnWarning`; Erweiterung **`stripeCustomerId`** (Organisation = Mandant, nicht einzelne Subscription).
- **`UsageStatistics`:** Aggregationen nach Periode, Provider und Feature (Konzept; Auswertung aus Transaktionen).
### Preise und Währung
- Verrechnung in **CHF**; Plugin-seitig typisch **`calculatePriceCHF()`** mit dokumentiertem Aufschlag (Konzept: z. B. 50 % auf Provider-Kosten), Werte in den AICore-Plugins gepflegt.
### Provider-Steuerung (RBAC)
- Ressourcen: `resource.aicore.{connectorType}` mit Aktion `USE`.
- Keine parallele Provider-Whitelist in den Chat-Tabellen; Filterung bei Modellauswahl über erlaubte Provider / RBAC.
---
## Subscription-System
### Abgrenzung zu Usage-Billing
- **Billing:** Verbrauch, Guthaben, Transaktionen.
- **Subscription:** Vertrag, Laufzeit, Stripe-Subscription, Kapazitätsregeln, Status für „darf der Mandant KI nutzen“.
Empfohlene Platzierung: **`serviceSubscription`** parallel zu `serviceBilling` im Service Center; Persistenz im gemeinsamen Billing-Kontext (z. B. DB `poweron_billing`). **`BillingService.checkBalance`** soll intern **`SubscriptionService.assertActive(mandateId)`** aufrufen, damit Call-Sites (z. B. `mainServiceAi`) eine zusammengefasste Prüfung behalten.
### Pläne und Kapazität
- **Katalog `SubscriptionPlan`:** u. a. `planKey`, mehrsprachige Texte, `billingPeriod` (`monthly` | `yearly` | `none`), `pricePerUserCHF` / `pricePerFeatureInstanceCHF`, optional `maxUsers` / `maxFeatureInstances` (`None` = unbegrenzt), `trialDays`, `successorPlanKey`, Stripe-Product/Price-IDs für User- und Instance-Items.
- **Instanz `MandateSubscription`:** `mandateId`, `planKey`, Snapshot-Preise, Status, Laufzeit (`startedAt`, `endedAt`, `currentPeriodStart` / `currentPeriodEnd`, `trialEndsAt`), Stripe-IDs (`stripeSubscriptionId`, Item-IDs für User/Instanzen).
### Nutzungsbasierte Mengen (Stripe)
- Zwei Subscription-Items mit dynamischer **Quantity:** aktive `UserMandate` (`enabled = true`) und aktive `FeatureInstance` (`enabled = true`). Änderungen an User/Instanz → DB-Update → **Stripe `subscription_items.update`** mit Proration (Standard: `create_prorations`).
- **Trial:** harte Caps (Konzept: z. B. `maxUsers: 1`, `maxFeatureInstances: 3`). **Standard/Enterprise:** ohne harte Plan-Caps, rein nutzungsbasiert. **Root:** Plan `ROOT`, `billingPeriod: none`, keine Stripe-Subscription, unbegrenzt; Usage-Billing kann **PREPAY_USER** mit Startguthaben bleiben.
### Source of Truth
- **App** führt Plan-Definitionen und Entitlements; Anlage/Änderung von Products/Prices über Stripe-API aus der App, nicht ad hoc im Dashboard.
- **Stripe** liefert Source of Truth für **Zahlungsstatus**; Webhooks (`invoice.paid`, `invoice.payment_failed`, `customer.subscription.updated`, …) synchronisieren in die lokale DB.
### Integration (Konzept)
- **AI-Hot-Path:** Subscription-Status (gecacht, TTL z. B. 60 s) + bestehende Balance-Prüfung; erweiterte `BillingCheckResult`-Gründe (`SUBSCRIPTION_INACTIVE`, …) und UI-Pfade (`subscriptionUiPath`, `userAction`).
- **Mutationen:** Cap-Check nur bei Plänen mit Limits; danach Stripe-Quantity-Sync. Periodischer Job: Abgleich Stripe-Quantity vs. DB-Counts.
- **Downgrade:** nur wenn `aktive User/Instanzen ≤ neue Plan-Caps`.
Referenz **Gateway-Audit** zu Prepaid-Beispielen: Trial **5 CHF**, Standard **10 CHF/Monat** — als kompakte Audit-Angabe; detaillierte Plan-Beispiele (z. B. CHF pro Seat/Instanz und Periode) stehen in den Subscription-Konzepttabellen.
---
## Subscription State Machine
### Grundregeln
- Pro Mandant ist höchstens **eine** Subscription **operativ** im Sinne von **`ACTIVE` oder `TRIALING`** (für volle KI-Nutzung laut Konzept; siehe unten zu `PAST_DUE`).
- Zusätzlich höchstens eine in **`PENDING`** oder **`SCHEDULED`** (Wechsel while Vorgänger läuft).
- Wechsel bei laufendem Abo: Vorgänger **`recurring = false`** (Stripe `cancel_at_period_end`), neues Abo startet nach Periodenende des Vorgängers bzw. laut Scheduler/Webhook.
- **`CANCELLED` als Status entfällt:** gekündigt = **`ACTIVE`** mit **`recurring = false`** bis Periodenende, danach **`EXPIRED`**.
### Felder (Ergänzung zum Instanzmodell)
- **`recurring: bool`** — automatische Verlängerung vs. Auslauf am Periodenende.
- **`effectiveFrom: Optional[datetime]`** — bei `SCHEDULED`: Wirksamkeit ab Periodenende des Vorgängers; `None` = sofort.
### Zustände
| State | Bedeutung |
|-------|-----------|
| **PENDING** | Checkout gestartet, Zahlung noch nicht bestätigt |
| **SCHEDULED** | Bestätigt, wartet auf Ende des Vorgänger-Abos |
| **TRIALING** | Testphase |
| **ACTIVE** | Bezahlt / laufend (ggf. `recurring` false bei Kündigung zum Laufzeitende) |
| **PAST_DUE** | Zahlung fehlgeschlagen, Stripe-Retry-Phase |
| **EXPIRED** | Beendet (terminal) |
**AI-Gate (Produktregel aus Mandanten-Konzept):** Für die Freigabe von AI-Calls gelten **`ACTIVE`** und **`TRIALING`**; bei **`PAST_DUE`**, **`EXPIRED`** und fehlender Subscription sind **AI-Calls blockiert** (auch wenn die Stripe-State-Maschine `PAST_DUE` als „Grace“ modelliert).
### Erlaubte Statusübergänge (Kernmenge)
Alle Writes mit expliziter **`subscriptionId`**; Validierung zentral (z. B. `transitionStatus(from, to)`).
- `PENDING``ACTIVE` | `SCHEDULED` | `EXPIRED`
- `SCHEDULED``ACTIVE` | `EXPIRED`
- `TRIALING``EXPIRED`
- `ACTIVE``PAST_DUE` | `EXPIRED`
- `PAST_DUE``ACTIVE` | `EXPIRED`
Typische Trigger: Stripe-Webhooks (`checkout.session.completed`, `invoice.payment_failed`, `customer.subscription.updated` / `deleted`), Admin-Aktionen (Kündigung = `recurring` false, Force-Cancel = sofort `EXPIRED`), Trial-Ende (Cron/Webhook).
---
## Billing-Checks
### AI-Call (Hot Path)
- **`mainServiceAi`:** `_preflightBillingCheck` und **`_checkBillingBeforeAiCall`** vor Provider-Auswahl bzw. Call.
- Reihenfolge (Zielbild nach Konzept): zuerst **Subscription aktiv** (`assertActive` / eingebettet in `checkBalance`), dann **Guthaben** (`checkBalance` / Prepaid), um unnötige DB-Runden zu vermeiden.
- **Datenvolumen:** **`assertCapacity("dataVolumeMB")`** prüft die RAG-Index-Grösse (Gateway-Kontext).
### Mutationen (kein Hot Path)
- Kapazitäts-Caps (**`assertCapacity`**) bei User-Zuordnung und Feature-Instanz-Erstellung, nicht bei jedem AI-Request.
- Nach Änderungen: Stripe-Quantity-Sync.
### Konsistenz-Job
- Vergleich Stripe-Quantities mit DB-Counts; bei Drift Korrektur Richtung DB und Benachrichtigung.
---
## Schlüssel-Dateien
| Datei / Bereich | Rolle |
|-----------------|--------|
| `serviceCenter/services/serviceBilling/` | Balance, Usage-Recording, Orchestrierung mit Subscription-Assert (Zielbild) |
| `serviceCenter/services/serviceAi/mainServiceAi.py` | `_preflightBillingCheck`, `_checkBillingBeforeAiCall`, zentrales AI-Gate |
| `serviceCenter/services/serviceSubscription/` | Subscription-Domäne, Cache, Stripe-Sync, Trial (vorgesehen) |
| `serviceCenter/registry.py` | Registrierung `billing`, `subscription` |
| `interfaces/interfaceDbBilling.py` | `BillingAccount`, `BillingTransaction`, `checkBalance` |
| `interfaces/interfaceDbSubscription.py` | Subscription-CRUD, `assertActive`, `assertCapacity` (vorgesehen) |
| `interfaces/interfaceDbApp.py` | `createUserMandate` / Root-Zuordnung — Hooks für Cap + Stripe-Quantity |
| `routes/routeBilling.py` | Billing-APIs, Stripe Checkout Top-Up / Webhooks |
| `routes/routeAdminFeatures.py` | `create_feature_instance` — Cap + Quantity-Sync (vorgesehen) |
| `routes/routeSubscription.py` | Plan-Aktivierung, Status, Wechsel (vorgesehen) |
| `datamodels/datamodelBilling.py` | `BillingSettings`, Transaktionen, `stripeCustomerId` |
| `datamodels/datamodelSubscription.py` | `SubscriptionPlan`, `MandateSubscription` (vorgesehen) |
| `features/workspace/routeFeatureWorkspace.py` | Pattern für Billing-/Fehlerantworten an UI |
| `aicore/aicoreModelSelector.py` | Filter nach erlaubten Providern |
| `aicore/*Plugin*.py` | `connectorType`, Preislogik CHF |
| `frontend_nyla/src/pages/billing/*` | Dashboard, Admin, Stripe-Flow, Subscription-UI |
| `frontend_nyla/src/hooks/useBilling.ts` | Billing-Settings / Subscription-Daten |
| `frontend_nyla/src/pages/views/workspace/useWorkspace.ts` | `billingUiPath` / User-Actions — gleiches Muster für Subscription-Pfade |
---
## Regeln / Invarianten
1. **Zwei Ebenen:** LLM-Verbrauch (Prepaid/Transaktionen) und Plattform-Subscription (Pläne, Stripe, Caps) — gemeinsames Gate vor AI-Calls.
2. **Mandant** ist die primäre Verrechnungseinheit für Usage; Transaktionen tragen den Mandanten-Kontext über das **BillingAccount**, nicht über Chat-Stammdaten.
3. **Pro Mandant** höchstens eine operative Subscription **`ACTIVE`/`TRIALING`** für KI-Freigabe; **`PAST_DUE`** und **`EXPIRED`** blockieren AI gemäß Mandanten-Konzept.
4. **Kündigung:** Nutzung bis **Ende der bezahlten Periode** (`recurring = false`, Stripe `cancel_at_period_end`); kein separater Status `CANCELLED`.
5. **Status-Änderungen** nur über definierte Transitionen mit **`subscriptionId`** — kein implizites Scannen nach „aktueller“ Zeile allein über `mandateId` bei Writes.
6. **Provider-Zugriff** über RBAC `resource.aicore.*`, konsistent mit Billing-Erfassung pro `aicoreProvider`.
7. **Aktive Zählung:** nur `UserMandate.enabled` und `FeatureInstance.enabled`; Einladungen und Deaktivierte zählen nicht für Quantity/Caps.
8. **`BillingService.checkBalance`** soll **`SubscriptionService.assertActive`** kapseln, damit der AI-Pfad nicht doppelt verteilt ist.
9. **Kapazität** (User/Instanz-Limits) an **Mutations-Endpunkten** enforcen, **nicht** auf jedem AI-Call.
10. **Root-Mandant:** systemische Subscription ohne Stripe-Abrechnung; unbegrenzte Seats/Instanzen; Usage-Billing kann **PREPAY_USER** mit Bootstrap-Guthaben bleiben.

View file

@ -0,0 +1,94 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Workflow-Engine
## Überblick
Die Workflow-Engine im Gateway orchestriert KI-gestützte Aufgabenpläne und die Ausführung einzelner **Aktionen** über eine gemeinsame **Method/Action-Bibliothek**. Sie verbindet die Schichten *Workflow**Methods**Services**Interfaces**Connectors*; Workflows importieren bewusst **nicht** direkt Interfaces, Connectors oder `aicore` (Zugriff über Services).
**Einsatzorte (Konsumenten der Action Library):**
- **Workspace (Dynamic Mode):** `WorkflowProcessor` / `modeDynamic` → Planung (Stage 1/2) → `ActionExecutor`
- **Automation v1:** `WorkflowProcessor` / `modeAutomation``ActionExecutor`
- **Automation2:** Graph-Engine mappt Nodes (`_method` / `_action`) auf dieselbe Library
- **Workspace-Agent:** `ActionToolAdapter` exponiert `dynamicMode=True`-Aktionen als Tools → `ActionExecutor`
**Ausführungsmodell:** Pro Workflow-Instanz sequentielle Ausführung (kein paralleles Multi-Task-Modell auf einer Instanz). Ausführungszähler (`currentRound`, `currentTask`, `currentAction`) liegen am **`ChatWorkflow`** (Single Source of Truth).
---
## WorkflowManager
Zentrale Steuerung in `gateway/modules/workflows/workflowManager.py` (grosse Datei; Einstieg für Start/Stopp und Hauptloop).
**Öffentliche / zentrale Verantwortlichkeiten (Konzept):**
| Bereich | Inhalt |
|--------|--------|
| Lebenszyklus | Start eines Workflow-Laufs, Verarbeitungsschleife, Beendigung |
| Planung | Aufgaben- und Aktionsplanung (modusabhängig; KI-Planning über Services) |
| Ausführung | Abarbeitung von Tasks/Actions in definierter Reihenfolge |
| Zustand | Anbindung an persistierten `ChatWorkflow` / Chat-DB über Service- und Interface-Schicht |
**Workflow-Zustände (konzeptionell):** `running`, `stopped`, `completed`, `failed`.
**Modi (Dokumentation):** Klassische Beschreibung nennt u.a. **React** (iterativ, begrenzte Schritte) und **Actionplan** (Plan upfront, ein Pfad). Die erweiterte Planungsarchitektur (`ai_plan_architecture.md`) beschreibt zusätzlich **dynamischen Modus** mit zweistufiger Aktionsplanung (Stage 1: Aktionswahl + Ressourcen; optional Stage 2: Parametergenerierung).
---
## Methoden
Methoden sind Python-Klassen unter `gateway/modules/workflows/methods/`; der **Methodenname** (`self.name`) ist der Registry-Schlüssel (z.B. `ai`, `context`). Aktionen sind über `WorkflowActionDefinition` registriert; viele tragen `actionId` im Muster `<method>.<action>` und `dynamicMode=True` für den Agent/Graph.
| Method (`self.name`) | Actions (Registry-Keys) |
|---------------------|-------------------------|
| `context` | `getDocumentIndex`, `extractContent`, `neutralizeData`, `triggerPreprocessingServer` |
| `ai` | `process`, `webResearch`, `summarizeDocument`, `translateDocument`, `convertDocument`, `generateDocument`, `generateCode` |
| `outlook` | `readEmails`, `searchEmails`, `composeAndDraftEmailWithContext`, `sendDraftEmail` |
| `sharepoint` | `findDocumentPath`, `readDocuments`, `uploadDocument`, `listDocuments`, `analyzeFolderUsage`, `findSiteByUrl`, `downloadFileByPath`, `copyFile`, `uploadFile` |
| `clickup` | `listTasks`, `searchTasks`, `getTask`, `createTask`, `updateTask`, `uploadAttachment` |
| `jira` | `connectJira`, `exportTicketsAsJson`, `importTicketsFromJson`, `mergeTicketData`, `parseCsvContent`, `parseExcelContent`, `createCsvContent`, `createExcelContent` |
| `trustee` | `extractFromFiles`, `processDocuments`, `syncToAccounting` |
| `chatbot` | `queryDatabase` |
| `file` | `create` |
*Hinweis:* Ältere Kontext-Dokumente nennen für `context` u.a. `saveContent` / `transformContent`; der aktuelle Gateway-Stand listet die obigen Aktionen (Stand Abgleich Code / Review 2026-04-05).
---
## Aktionen
- **Registrierung:** Jede Aktion ist eine `WorkflowActionDefinition` mit Metadaten, Parametern (`WorkflowActionParameter`, u.a. `FrontendType`) und `execute`-Callable.
- **Ausführung:** `ActionExecutor` löst `methodName` + `actionName` auf, validiert Parameter (Action Registry / Pydantic je nach Implementierung) und liefert ein **`ActionResult`** (Erfolg, Dokumente, Fehler).
- **Dokumente:** Ergebnisse werden typischerweise als strukturierte **`ActionDocument`** / Extraktionsartefakte (`ContentExtracted` / `ContentPart`) weitergereicht.
- **Extraktion vs. KI:** Zielarchitektur (siehe `ai_plan_architecture.md`): **reine Extraktion** (`context.extractContent` bzw. dokumentbezogene Pipeline) ist von **KI-Aufrufen** (`serviceAi`) zu trennen; KI-Methoden arbeiten bevorzugt mit bereits extrahierten `ContentPart`-Strukturen.
- **Planung:** Stage 1 liefert u.a. `action` (`method.action`), Zieltext, optional `documentList` / `connectionReference`; Stage 2 ergänzt bei Bedarf das Parameter-JSON ohne die Stage-1-Ressourcen zu überschreiben.
---
## Schlüssel-Dateien
| Pfad (unter `gateway/modules/`) | Rolle |
|--------------------------------|--------|
| `workflows/workflowManager.py` | Workflow-Orchestrierung, Einstieg |
| `workflows/processing/` | Processor, Modi (`modeReact`, `modeActionplan`, `modeDynamic`, …), `ActionExecutor` |
| `workflows/methods/methodBase.py` | Basis für Methoden, Aktions-Validierung |
| `workflows/methods/method*/` | Konkrete Methoden und Aktionen |
| `datamodels/datamodelChat.py` | `ChatWorkflow`, `TaskContext`, Task-/Plan-Modelle |
| `datamodels/datamodelWorkflowActions.py` | Aktionsdefinitionen |
| `services/serviceWorkflow/` | Fortschritt, Logs, Nachrichten/Dokumente am Workflow |
| `services/serviceAi/` | Planning- und Content-KI (kein direkter Workflow-Import aus Methods zurück) |
| `interfaces/interfaceDbChat*` | Persistenz Workflow/Nachrichten/Dokumente |
---
## Regeln / Invarianten
1. **Schichten-Imports:** Workflows importieren nur `datamodels`, `services`, interne `workflows/*`. Methods importieren `datamodels`, `services`, `workflows.methods.*`**keine** direkten Interface-/Connector-/aicore-Imports in Methods.
2. **Zustand am Workflow:** Rund-/Task-/Action-Indices und Kontext gehören zum **`ChatWorkflow`** / `TaskContext`, nicht als lose Parameter durch alle Ebenen.
3. **Typisierung:** Bevorzugt Pydantic-Modelle für Planungs- und Aktionskontext (`ActionDefinition`, `TaskResult`, …); JSON aus KI-Calls über zentrale Parse-/Repair-Hilfen.
4. **Sequenz:** Ein Workflow läuft in einer Instanz sequentiell ab; parallele Ausführung ist kein Designziel der beschriebenen Engine.
5. **Neutralisierung:** Sensible Daten an **KI-Modelle** laufen über das zentrale Gate in `serviceAi` (`mainServiceAi.py`); die Workflow-Aktion `context.neutralizeData` ist eine **explizite** Neutralisierung extrahierter Inhalte und ersetzt nicht das globale KI-Gate (siehe Compliance-Doku).
6. **Gemeinsame Library:** Dieselben Actions werden von Chat-Workflow, Automation v1/v2 und Agent-Tools genutzt — Änderungen an `actionId` / Parametern wirken quer über alle Konsumenten.

View file

@ -0,0 +1,85 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Navigation API
## Überblick
Die Navigation-API ist die **Single Source of Truth** für die Navigationsstruktur: Das **Gateway** entscheidet, welche Einträge ein Benutzer sieht; das **UI** rendert nur die gelieferte Struktur — **keine** parallele Berechtigungslogik im Frontend für die Navigation. Die API liefert **keine** Darstellungsassets (Icons, CSS); stattdessen **UI-Komponenten-Codes** (`uiComponent`), die im Client (z. B. `PAGE_REGISTRY`) auf Komponenten gemappt werden. Einträge ohne Berechtigung erscheinen **nicht** im Baum (kein `hasAccess: false`). Unbekannte `uiComponent`-Codes sollen im UI **sichtbar als Fehler** gemeldet werden, damit Gateway/UI-Drift auffällt.
**Ziel-Endpoint (Konzept):** `GET /api/navigation` mit Antwort u. a. `language`, `blocks[]`.
**Ist-Stand (Audit):** Statische Navigation u. a. über `GET /api/system/navigation` mit `sections` — Migration auf kombinierten Endpoint und `blocks`-Schema ist im Konzept dokumentiert.
**Personalisierung:** Sortierung über numerisches `order`; User-Overrides in Settings (`navOrder`), Merge im Gateway: `EffektiveOrder = User-Override ?? Default ?? 50`. Update-Konzept: `PUT /api/user/settings/navOrder`.
Aktuelle UI-Bezüge im Kontext: `MandateNavigation`, Hook `useNavigation` (`frontend_nyla`).
## Block-Struktur
Die Antwort besteht aus einer geordneten Liste von **Blocks**:
- **`type`:** `static` oder `dynamic`
- **`id`:** z. B. `system`, `workflows`, `basedata`, `admin`, `features`
- **`title`:** Anzeige-Gruppentitel
- **`order`:** Reihenfolge der Blöcke
**Static Block:** enthält `items[]` mit Navigationsknoten auf System-/Admin-/Basisdaten-Seiten.
**Dynamic Block:** enthält `mandates[]` → je Mandat `features[]``instances[]``views[]`. Der dynamische Block fehlt, wenn der User keine zugängliche Feature-Instanz hat.
**Item-Felder (Static / Views):**
| Feld | Bedeutung |
|------|-----------|
| `uiComponent` | Eindeutiger Code für das UI-Mapping |
| `uiLabel` | Text in der gewählten Sprache |
| `uiPath` | URL-Pfad |
| `order` | Sortierung innerhalb der Ebene |
| `objectKey` | Vollqualifizierter RBAC-Bezug (UI-Kontext), z. B. `ui.system.home` |
## Static Blocks (System, Basedata, Admin)
Typische **static** Blöcke im Konzept:
- **`system`:** mandatsübergreifende Systemseiten (z. B. Home, Einstellungen) — `page.system.*`, ObjectKeys `ui.system.*`.
- **`workflows`:** Workflow-bezogene Systemseiten (z. B. Playground, Chat-Liste) — ebenfalls `page.system.*` / `ui.system.*` im Beispiel.
- **`basedata`:** Stammdaten (z. B. Prompts, Dateien) — weiterhin `page.system.*` mit Pfaden unter `/basedata/...`.
- **`admin`:** Administration — `page.admin.*`, ObjectKeys `ui.admin.*` (Benutzer, Mandanten, …).
Die exakte Liste und Default-`order` stammen aus der Gateway-Konfiguration (`NAVIGATION_SECTIONS` in `mainSystem.py` laut Analyse — Felder teilweise noch `label`/`path`/`icon`; Zielmapping: `uiLabel`/`uiPath`, ohne `icon` in der API).
## Dynamic Block (Features)
- **`id`:** typischerweise `features`
- Hierarchie: **Mandat****Feature-Typ** (`uiComponent` z. B. `feature.trustee`) → **Instanz****Views** (`page.feature.<code>.<view>`)
- Pfade enthalten Mandats- und Instanz-IDs (siehe Konzeptbeispiele)
- Sortierung auf allen Ebenen über jeweiliges `order` (Mandat, Feature, Instanz, View)
## RBAC-Integration
- **`objectKey`** in Navigationsitems entspricht dem **`item`**-String im **UI-Kontext** der Access Rules (vollqualifiziert), z. B. `ui.feature.trustee.dashboard`.
- Navigation-Endpoint wendet **Permission-Filter** an, bevor die Response gebaut wird — nur erlaubte Knoten sind enthalten.
- Konventionen (Kontext UI): `ui.system.<name>`, `ui.admin.<name>`, `ui.feature.<code>.<view>`. Für DATA/RESOURCE siehe übergreifendes RBAC-Dokument (`data.*`, `resource.*`).
- **Inkonsistenz-Hinweis (Audit):** Template-Rollen dürfen keine Kurz-`item`-Namen (`dashboard`) nutzen, wenn `objectKey` vollqualifiziert ist — `item` und Navigation müssen übereinstimmen.
## Schlüssel-Dateien
| Schicht | Pfad / Artefakt |
|---------|------------------|
| Statische Sektionen (Gateway) | `mainSystem.py``NAVIGATION_SECTIONS` |
| Navigation-Route | `routeSystem.py` — Endpoint-Evolution `/api/system/navigation``/api/navigation` |
| Feature-Views / Template-Rollen | z. B. `mainTrustee.py`, `mainRealEstate.py``UI_OBJECTS`, `TEMPLATE_ROLES` |
| Admin-Feature-Permission (Ist teils feature-spezifisch) | `routeAdminFeatures.py` — z. B. `_deriveViewPermissions` |
| Frontend: Navigation | `MandateNavigation.tsx`, `useNavigation` |
| Frontend: Registry (Ziel) | `frontend_nyla/src/config/pageRegistry.ts``PAGE_REGISTRY`, `FEATURE_REGISTRY` |
| Legacy-Duplikate (Audit) | `mandate.ts``FEATURE_REGISTRY` / View-Definitionen parallel zum Backend |
## Regeln / Invarianten
- **Backend autoritativ:** Keine eigenständige Zusammenstellung der Navigationsstruktur im UI aus mehreren Quellen ohne Gateway-Abgleich (Zielzustand: ein Endpoint, ein Baum).
- **Nur sichtbare Knoten:** Keine negativen Sichtbarkeitsflags in der Response.
- **Sortierung:** ausschließlich vom Gateway; das UI sortiert empfangene Listen nicht erneut.
- **`uiComponent`-Konventionen:** `page.system.<page>`, `page.admin.<page>`, `page.feature.<feature>.<view>`, Feature-Gruppe `feature.<code>`.
- **Drift sichtbar machen:** Unbekannte Codes im UI als Fehler anzeigen, nicht still ignorieren.
- Vollständiges API-Konzept und Migrationsphasen: `wiki/concepts/Navigation-API-Konzept.md`.

View file

@ -0,0 +1,81 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# Neutralisierungs-System
## Überblick
Neutralisierung ersetzt mandantensensible Inhalte durch stabile Platzhalter, bevor Text an externe KI-Modelle geht oder dauerhaft im RAG landet. Rohdaten aus Tools werden nicht separat „nachgefiltert“: der Schutz liegt am **Content-Einstieg** (Indexierung, Extraktion, zentrales AI-Gate) und an vererbten Flags auf `FileItem` / Session / Feature-Konfiguration.
## Architektur: Einzige zentrale Stelle
**Für jeden AI-Modell-Call** gilt: Prompt, RAG-Kontext und Chat-Nachrichten werden **ausschließlich** in `mainServiceAi.py` geprüft und neutralisiert (`_shouldNeutralize`, `_neutralizeRequest`). Kein anderes Modul entscheidet parallel „stattdessen“ für dieselbe Modell-Schnittstelle.
Orthogonal dazu (kein Ersatz des Gates, sondern Data-at-rest bzw. Workflow):
- **RAG:** `mainServiceKnowledge.indexFile()` neutralisiert Chunks bei `FileItem.neutralize=True`.
- **Agent:** DataSource- und FeatureDataSource-Flags setzen bzw. vererben Neutralisierungspflicht; Sub-Agent-Calls können `requireNeutralization=True` tragen.
- **Workflows:** Aktion `neutralizeData` neutralisiert explizit extrahierte ContentParts (prüft u. a. `NeutralizationConfig.enabled`, nicht das Session-Flag).
## Neutralisierungs-Trigger (Prioritätsreihenfolge)
**Am AI-Gate (`_shouldNeutralize`)** (Auswertung in der dokumentierten Reihenfolge):
1. **Pro Request:** `AiCallRequest.requireNeutralization` — expliziter Override auf dem Call.
2. **Chat-/Session-Level:** `ServiceCenterContext.requireNeutralization` (z. B. Workspace, Automation).
3. **Mandanten-/Feature-Konfiguration:** `NeutralizationConfig.enabled` (DataNeutraliser / Feature-Instanz).
**Quellen gesamt (OR-Logik):** Ist irgendwo Neutralisierung erforderlich (Feature-Instanz, Workflow/Session, konkretes Objekt mit `FileItem.neutralize` / `DataSource.neutralize` / `FeatureDataSource.neutralize`), wird entsprechend verarbeitet. Dokumentierte Produktregel: **Kein `False` von einer Quelle hebt ein `True` einer anderen auf.**
## Was neutralisiert wird
Im zentralen AI-Gate (`_neutralizeRequest`):
- `request.prompt`
- `request.context` (RAG-Kontext)
- `request.messages` (OpenAI-artige Nachrichten)
**Engine** (`NeutralizationService`): `processText`, `processFile`, `processBinaryBytes` (synchron/asynchron); Rückübersetzung über `resolveText` / Mappings. Modell-Familien u. a. `NEUTRALIZATION_TEXT` / `NEUTRALIZATION_IMAGE` (Private-LLM-Plugin; externe Provider ohne diese Ratings werden für Neutralisierung nicht gewählt).
**Nicht erneut neutralisieren:** Bereits neutral indexierte RAG-Chunks; Web-Suchergebnisse ohne Mandantendaten (laut Spezifikation).
**Bekannter Ist-Stand Medien:** Bild-Binary wird in der Engine derzeit weitgehend durchgereicht bzw. übersprungen — dedizierter Bild-Neutralisierungspfad ist in der Fachdoku als Lücke / Soll beschrieben, nicht als abgeschlossene Implementierung ausgewiesen.
## Failsafe-Kette
1. **Toggle `FileItem.neutralize`:** Index und Chunks werden synchron gelöscht; Re-Index im Hintergrund verhindert Leaks bei Fehlern in der Nachindexierung.
2. **Indexierung:** `indexFile()` neutralisiert Text-Chunks bei `FileItem.neutralize=True` → Data-at-rest abgesichert.
3. **DataSource-Download:** `neutralize`-Flag wird auf erzeugte `FileItem`s vererbt.
4. **FeatureDataSource:** `_queryFeatureInstance()` setzt bei `neutralize=True` u. a. `requireNeutralization=True` für Sub-Agent-AI-Calls.
5. **AI-Call:** Bei erzwungener Neutralisierung (`requireNeutralization=True`) schlägt fehlgeschlagene Neutralisierung hart fehl (`RuntimeError` / Blockierung bzw. Entfernen betroffener Message-Teile — kein Durchleiten im Rohzustand).
6. **`_rehydrateResponse()`:** Als Hilfsmethode vorhanden; automatische Rückübersetzung der Modellantwort ist nicht mehr der Standardpfad.
**Engine-Failsafe (Spezifikation):** Neutralisierung verlangt, Engine nicht verfügbar → nicht weiterverarbeiten; Teilfehler → Teil entfernen, nicht roh weitergeben; fehlendes internes Medienmodell → Medien-Part entfernen.
## NeutralizationPanel (Frontend)
`frontend_nyla/src/pages/views/workspace/NeutralizationPanel.tsx` — Übersicht zu Dateien mit `neutralize`-Flag, Status und Platzhalter-Mappings. Datenbasis u. a. `GET /api/workspace/{instanceId}/files``{ files: [...] }`.
## Schlüssel-Dateien
| Bereich | Pfad |
|--------|------|
| **Zentrales AI-Gate** | `serviceCenter/services/serviceAi/mainServiceAi.py` |
| **Neutralisierungs-Engine** | `features/neutralization/serviceNeutralization/mainServiceNeutralization.py` (+ `subProcess*.py`) |
| **Feature-Config / DB** | `features/neutralization/datamodelFeatureNeutralizer.py`, `interfaceFeatureNeutralizer.py` |
| **RAG-Index** | `serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` |
| **Agent / Quellen** | `serviceCenter/services/serviceAgent/mainServiceAgent.py` (`_resolveDataSource`, `_downloadFromDataSource`, `_queryFeatureInstance`) |
| **Datei-Toggle / Index** | `routes/routeDataFiles.py``PATCH /{fileId}/neutralize` |
| **Workflow-Aktion** | `workflows/methods/methodContext/actions/neutralizeData.py` |
| **Kontext** | `serviceCenter/context.py``requireNeutralization` |
| **Flags (Modelle)** | `datamodels/datamodelFiles.py` (`FileItem.neutralize`), `datamodelDataSource.py`, `datamodelFeatureDataSource.py` |
| **AI-Operationen / Enums** | `datamodels/datamodelAi.py`, `aicore/aicorePluginPrivateLlm.py` |
## Regeln / Invarianten
- **Ein Gate pro Modell-Call:** Sämtlicher Text in Richtung externes LLM für diesen Call läuft über `mainServiceAi` — keine parallele „zweite“ Neutralisierungstelle für dieselbe Schnittstelle.
- **Hard-Mode:** `requireNeutralization=True` und Neutralisierung scheitert → Call blockieren bzw. Inhalt nicht im Klartext an das Modell geben.
- **Kein stilles Weiterreichen** sensibler Inhalte bei Pflicht zur Neutralisierung.
- **Platzhalter:** Mapping `[typ.uuid]` in der DB; `resolveText` für kontrollierte Rückübersetzung.
- Detaillierte Compliance- und Prozessbeschreibung: `wiki/compliance/Neutralisierung.md`.

View file

@ -0,0 +1,69 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-03-29) -->
# RBAC-System
## Überblick
Das Role-Based Access Control bündelt Berechtigungen in **Access Rules** pro Rollenlabel und **Kontext** (DATA, UI, RESOURCE). Auswertung erfolgt zentral über `interfaceRbac.py`; Zielbild laut Architekturdokumentation: möglichst **filternd in der Datenbank** statt voller Tabellen-Scans in Python. Nutzer können **mehrere Rollenlabels** gleichzeitig tragen; die effektive Berechtigung entsteht aus **Öffnungslogik (Union)** über alle Rollen.
## Zwei getrennte Rollensysteme
| | **Mandantenrollen** | **Feature-Instanz-Rollen** |
|--|---------------------|----------------------------|
| **Labels (Beispiele)** | `admin`, `user`, `viewer` | `workspace-admin`, `workspace-user`, `workspace-viewer`, feature-spezifisch |
| **Scope** | `mandateId` | `mandateId` + `featureCode` + `featureInstanceId` |
| **Zuordnung** | `UserMandateRole` | `FeatureAccessRole` |
**Invariante:** Mandantenrollen und Feature-Instanz-Rollen **nicht vermischen** — kein Zuweisen eines Mandanten-Labels zu `FeatureAccessRole` oder umgekehrt.
Zusätzlich (Systemebene, laut RBAC-Dokument): globale Rollen wie **SysAdmin** / **SystemUser** für mandantenübergreifende Sonderfälle; Mandantenrollen **Admin** / **User** / **Viewer** für Zugriff innerhalb eines Mandats.
## Access Rules (DATA / UI / RESOURCE)
### Kontexte
- **DATA:** Tabellen und Felder; CRUD über `read`, `create`, `update`, `delete` mit Access Levels `a` (all), `m` (my), `g` (group / Mandat), `n` (none); zusätzlich `view`.
- **UI:** Sichtbarkeit/Aktivierung von Oberflächenelementen; relevant ist **`view`** (boolean). Item-Format: kaskadierender String (z. B. `playground.voice.settings`).
- **RESOURCE:** Systemressourcen (KI-Modelle, Aktionen, …); ebenfalls primär **`view`**. Item-Format: kaskadierend (z. B. `ai.model.anthropic`).
### Spezifität (pro Rolle)
Innerhalb **einer** Rolle gewinnt die **spezifischste** passende Regel (längster passender Präfix/exakter `item`) gegenüber generischen Regeln (`item = null`).
### Mehrere Rollen
Über Rollen hinweg: **Union** — wenn eine Rolle nach interner Auflösung `view: true` liefert, gilt das Element als sichtbar/erlaubt (OR über Rollen). Für **DATA** werden die **freizügigsten** Stufen über Rollen kombiniert.
### DATA: Öffnungsrechte (CUD vs. Read)
- Ohne Leserecht (`read = n`) keine CUD.
- Mit `read = m` sind CUD höchstens `m` oder `n`.
- Mit `read = g` sind CUD höchstens `g`, `m` oder `n`.
- Mit `read = a` sind alle Stufen für CUD zulässig.
### Systemfelder (DATA)
Felder `id` und Namen mit führendem `_` sind für Anwendungs-CUD geschützt; Connector erzwingt das unabhängig von Access Rules.
### Frontend-Optionen für Rollen
`frontend_options` an Feldern kann statische Listen oder String-Referenzen (z. B. `"user.role"`) nutzen; dynamische Optionen über `/api/options/{optionsName}`. Typ-Hilfen: `gateway/modules/shared/frontendOptionsTypes.py`.
## Schlüssel-Dateien
| Rolle | Pfad |
|-------|------|
| RBAC-Auswertung / DB-Schicht | `gateway/modules/interfaces/interfaceRbac.py` |
| AccessRule- und Permission-Modelle | `gateway/modules/datamodels/` (u. a. RBAC-bezogene Modelle) |
| Nutzer / Rollenlabels | User-Modell mit `roleLabels` (Multiselect, Union) |
| Konzept & Feldsemantik | `wiki/appdoc/doc_security_role_based_access.md` |
## Regeln / Invarianten
- Mandanten- vs. Feature-Rollen **strikt trennen** (keine Kreuz-Zuweisung der Label-Typen).
- **Spezifisch vor generisch** innerhalb einer Rolle; **Union** über Rollen.
- UI/RESOURCE: Effektiv sichtbar nur, wenn nach Regelauflösung **`view: true`** (kein `hasAccess: false` in Navigationskonzept — nicht berechtigte UI-Einträge werden gar nicht geliefert).
- DATA: Validierung der Regeln so, dass CUD nicht über dem jeweiligen Read-Level liegen.
- Performance-Ziel: DATA-Zugriffe mit RBAC-Filter in SQL, nicht erst vollständige Tabellen in Python filtern.

View file

@ -0,0 +1,66 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: private-llm (codebase review 2026-04-05) -->
# Private LLM -- Architektur
## Überblick
Eigenständiger Service für die Verarbeitung sensitiver Daten mit lokalen AI-Modellen (Ollama). Läuft auf einem dedizierten GPU-Server (Infomaniak Swiss Cloud) und wird vom Gateway als Provider-Plugin (`aicorePluginPrivateLlm.py`) angesprochen. Kein Datenabfluss an externe Cloud-APIs.
## Technologie-Stack
| Layer | Technologie |
|-------|------------|
| Framework | FastAPI (Python) |
| AI Runtime | Ollama (lokale Vision/Text-Modelle) |
| PDF-Support | PyMuPDF (fitz) |
| Hosting | Infomaniak Swiss Cloud (GPU) |
| Deployment | GitHub Actions → `main` Branch |
## Modelle
| Externer Name | Internes Ollama-Modell | Typ |
|--------------|----------------------|-----|
| `poweron-text-general` | `qwen2.5:7b` | Text |
| `poweron-vision-general` | `qwen2.5vl:7b` | Vision |
| `poweron-vision-deep` | `granite3.2-vision` | Vision |
## API-Routen
| Modul | Zweck |
|-------|-------|
| `routeApi.py` | Analyse-API: Bild-/PDF-Analyse mit Prompt, Modellauswahl |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-Completion-API (für Cursor-Integration) |
| `routeWeb.py` | Web-UI für manuelle Tests |
## Integration mit Gateway
Der Gateway nutzt das Private LLM über `aicorePluginPrivateLlm.py` als Provider für:
- **Neutralisierung:** Text-Analyse mit `poweron-text-general`
- **Sensitive Datenverarbeitung:** Vision-Analyse von Dokumenten (Rechnungen, Belege, Handschrift)
- **Keine Billing-Kosten** für mandanteninterne LLM-Calls (eigene Infrastruktur)
## Sicherheit
- API-Key-Authentifizierung (`X-API-Key` Header)
- Separater Cursor-API-Key für OpenAI-kompatible Endpoints (Bearer Token)
- Rate-Limiting per API-Key (Token Bucket, konfigurierbar)
- Konfiguration über `config.ini` + Environment-Variablen (Secrets nie im Code)
## Schlüssel-Dateien
| Datei | Rolle |
|-------|-------|
| `app.py` | FastAPI-Einstieg, Router-Mount |
| `config.py` | Konfiguration, Model-Mapping, Auth, Rate-Limiting, Request/Response-Modelle |
| `routeApi.py` | Analyse-Endpunkte (Bild, PDF) |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-API |
| `routeWeb.py` | Test-UI |
## Regeln / Invarianten
- Alle Daten werden **lokal** verarbeitet -- kein Weiterleiten an externe APIs
- Model-Mapping ist die einzige Stelle für Namensauflösung (`MODEL_MAPPING` in `config.py`)
- API-Keys werden aus `config.ini` oder Environment gelesen, nie hardcoded
- PDF-Verarbeitung rendert Seiten als Bilder für Vision-Modelle (max 5 Seiten)

56
b-reference/product.md Normal file
View file

@ -0,0 +1,56 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
# PowerOn Portal -- Komponentenübersicht
## Produkt
PowerOn Portal ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung.
## Komponenten
| Komponente | Repository | Technologie | Beschreibung |
|-----------|-----------|-------------|-------------|
| Frontend Nyla | frontend_nyla | React/TypeScript, Vite | Zentrales UI für alle Features |
| Gateway | gateway | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | private-llm | Python | Internes LLM für Neutralisierung + sensitive Daten |
| Teams Bot | service-teams-browser-bot | Node.js/.NET | Bot für Teams-Meeting-Teilnahme |
| Wiki | wiki | Markdown | Dokumentation (dieses Repo) |
## 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` |
## 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 |
## 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`
## Cross-Cutting Concerns
- Neutralisierung: Gateway ↔ Private LLM (→ platform/neutralization.md)
- RBAC: Gateway ↔ Frontend (→ platform/rbac.md)
- Navigation: Gateway → Frontend (→ platform/navigation.md)

View file

@ -0,0 +1,64 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: service-teams-browser-bot (documentation review 2026-02-18) -->
# Teams Meeting Bot -- Architektur
## Überblick
AI-gesteuerter Meeting-Bot für Microsoft Teams. Tritt Meetings als regulärer Teilnehmer bei (Browser-Automation via Playwright/Chromium), erfasst Live-Transkripte, reagiert per Sprache (TTS) und/oder Chat. Kein Teams-Graph-SDK nötig -- funktioniert mandantenübergreifend ohne Admin-Approval.
## System-Architektur
```
┌────────────┐ SSE ┌──────────────┐ WebSocket ┌─────────────┐
│ Frontend │◄──────────────│ Gateway │◄───────────────│ Bot Service │
│ (Nyla UI) │ │ (AI, TTS, │ HTTP (join/ │ (Playwright │
│ │ │ Sessions) │ leave) │ Chromium) │
└────────────┘ └──────────────┘ └─────────────┘
```
| Verbindung | Protokoll | Zweck |
|------------|----------|-------|
| Gateway ↔ Bot | WebSocket | Echtzeit: Transkripte, Chat, Audio, Status |
| Gateway → Bot | HTTP | Session-Steuerung (join, leave, status) |
| Frontend ← Gateway | SSE | Live-Transkript-Stream für UI |
## Kernfähigkeiten
- **Live Transcription:** Erfasst Untertitel mit Sprecher-Zuordnung, streamt via SSE
- **AI-Analyse:** Transkript-Segmente werden durch AI-Modell (GPT-4o-mini / Claude) analysiert
- **Voice Response:** TTS-Audio wird über den Mikrofon-Kanal ins Meeting gespielt
- **Chat Response:** Bot kann Chat-Nachrichten ins Meeting schreiben
- **Multi-Session:** Mehrere Bot-Instanzen parallel in verschiedenen Meetings
## Use Cases
| UC | Beschreibung |
|----|-------------|
| AI Meeting Assistant | Bot nimmt teil, hört zu, antwortet auf Ansprache ("Hey Nyla, ...") |
| Live Transcription | Echtzeit-Transkript-Stream für Teilnehmer ausserhalb des Meetings |
| Meeting Summary | AI-generierte Zusammenfassung nach Meeting-Ende |
| Multi-Bot | Mehrere parallele Sessions in verschiedenen Meetings |
## Integration mit Gateway
Der Gateway (Feature `teamsbot`) verwaltet Sessions und stellt die AI-Pipeline bereit:
- Session-Lifecycle: erstellen, starten, stoppen
- WebSocket-Verbindung pro Session
- AI-Analyse der Transkript-Segmente via `serviceAi`
- TTS-Generierung für Voice-Responses
## Schlüssel-Dateien
| Datei / Bereich | Rolle |
|-----------------|-------|
| `gateway/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul |
| `service-teams-browser-bot/` | Eigenständiger Bot-Service (separates Repository) |
## Regeln / Invarianten
- Bot tritt als **regulärer Web-Teilnehmer** bei (Browser-Automation), nicht via Graph Communications SDK
- Jede Session läuft in einer **eigenen Browser-Instanz** (Isolation)
- Authentifizierter Join (mit Microsoft-Account) oder Anonymous Guest -- je nach Konfiguration
- Gateway ist die **einzige** Schnittstelle für AI-Aufrufe und TTS -- der Bot-Service selbst hat keine AI-Logik

View file

@ -0,0 +1,85 @@
# PR: CodeEditor Feature - Phase 1 (MVP)
## Summary
Neues Feature "CodeEditor" -- Cursor-artiger AI-gestuetzter Text-Editor als eigenstaendiges Feature im Gateway mit Frontend-Integration in Nyla UI. Komplett unabhaengig vom bestehenden Workflow-System (Option B).
- Eigenstaendiger Verarbeitungspfad in `features/codeeditor/` ohne Eingriff in `workflowManager.py`
- AI-Aufrufe direkt ueber `interfaceAiObjects.callWithTextContext()` mit voller Model Selection, Failover und Billing
- SSE-Streaming via bestehender `EventManager`-Infrastruktur aus dem Chatbot-Feature
- Frontend: Drei-Panel-Layout (FileList, Chat, DiffPreview) mit Accept/Reject fuer Datei-Aenderungen
- Phase 1 = Single-Shot Mode (1 AI Call pro Prompt). Phase 2 (Agent Loop mit Tool Calling) ist geplant.
## Neue Dateien
### Backend (Gateway)
| Datei | Beschreibung |
|---|---|
| `gateway/modules/features/codeeditor/__init__.py` | Package init |
| `gateway/modules/features/codeeditor/datamodelCodeeditor.py` | Pydantic Models: FileContext, ResponseSegment, FileEditProposal, FileVersion, MIME-Type Validierung |
| `gateway/modules/features/codeeditor/mainCodeeditor.py` | Feature-Registration: RBAC UI/Resource Objects, Template Roles (Plug&Play) |
| `gateway/modules/features/codeeditor/fileContextManager.py` | Text-Dateien aus DB laden, MIME-Type filtern |
| `gateway/modules/features/codeeditor/promptAssembly.py` | System Prompt Builder mit Datei-Kontext und Format-Instruktionen |
| `gateway/modules/features/codeeditor/responseParser.py` | AI-Antwort in typisierte Segmente parsen (text, code_block, file_edit) |
| `gateway/modules/features/codeeditor/codeEditorProcessor.py` | Orchestrator: Files laden -> Prompt bauen -> AI call -> Parse -> SSE emit |
| `gateway/modules/features/codeeditor/routeFeatureCodeeditor.py` | 8 FastAPI Endpoints inkl. SSE Stream |
### Frontend (Nyla UI)
| Datei | Beschreibung |
|---|---|
| `frontend_nyla/src/pages/views/codeeditor/CodeEditorPage.tsx` | Drei-Panel-Layout mit resizable Panels |
| `frontend_nyla/src/pages/views/codeeditor/FileListPanel.tsx` | Datei-Auswahl mit Checkboxen |
| `frontend_nyla/src/pages/views/codeeditor/DiffPreviewPanel.tsx` | Diff-Anzeige mit Accept/Reject |
| `frontend_nyla/src/pages/views/codeeditor/useCodeEditor.ts` | SSE Hook mit Auth/CSRF, File-Selection, Edit-State |
| `frontend_nyla/src/pages/views/codeeditor/CodeEditor.module.css` | Styling |
| `frontend_nyla/src/pages/views/codeeditor/index.ts` | Export |
## Geaenderte Dateien
| Datei | Aenderung |
|---|---|
| `gateway/modules/datamodels/datamodelChat.py` | `WORKFLOW_CODEEDITOR = "CodeEditor"` zu `WorkflowModeEnum` hinzugefuegt |
| `gateway/modules/routes/routeSystem.py` | `codeeditor` in `_getFeatureUiObjects()` fuer Navigation API |
| `gateway/modules/system/mainSystem.py` | Store-Resource `resource.store.codeeditor` |
| `gateway/modules/interfaces/interfaceBootstrap.py` | `resource.store.codeeditor` in `storeResources` |
| `frontend_nyla/src/pages/FeatureView.tsx` | Import + `codeeditor` in `VIEW_COMPONENTS` Registry |
| `frontend_nyla/src/config/pageRegistry.tsx` | `feature.codeeditor` Icon (FaFileAlt) |
| `frontend_nyla/src/types/mandate.ts` | `codeeditor` in `FEATURE_REGISTRY` mit Views |
| `frontend_nyla/src/pages/Store.tsx` | Icon + Beschreibung fuer Feature Store |
| `frontend_nyla/src/App.tsx` | Route `editor` fuer CodeEditorPage |
## API Endpoints
| Endpoint | Methode | Beschreibung |
|---|---|---|
| `/api/codeeditor/{instanceId}/start/stream` | POST | Workflow starten + SSE-Stream |
| `/api/codeeditor/{instanceId}/{workflowId}/stop` | POST | Workflow stoppen |
| `/api/codeeditor/{instanceId}/{workflowId}/chatData` | GET | Polling-Fallback |
| `/api/codeeditor/{instanceId}/workflows` | GET | Workflows auflisten |
| `/api/codeeditor/{instanceId}/files` | GET | Text-Dateien auflisten |
| `/api/codeeditor/{instanceId}/files/{fileId}/content` | GET | Datei-Inhalt laden |
| `/api/codeeditor/{instanceId}/{workflowId}/apply` | POST | Aenderung akzeptieren |
## Architektur-Entscheide
- **Option B**: Eigenstaendiger Pfad, kein Eingriff in WorkflowManager/WorkflowProcessor
- **AI-Zugriff**: Direkt ueber `interfaceAiObjects.callWithTextContext()` -- nutzt bestehende Model Selection, Failover, Provider-Filtering, Billing
- **SSE**: Segment-weise Emission (nicht token-weise), da aicore aktuell kein Token-Streaming hat
- **Feature-Discovery**: Plug&Play via `mainCodeeditor.py` + `routeFeatureCodeeditor.py` (automatisch entdeckt durch `registry.py`)
## Test Plan
- [ ] Gateway startet ohne Fehler mit neuem Feature
- [ ] Feature erscheint im Feature Store und kann aktiviert werden
- [ ] Navigation zeigt CodeEditor-Instanz mit Icon und Views (Editor, Workflows)
- [ ] Editor-View laedt: FileList links, Chat mitte, DiffPreview rechts
- [ ] Panel-Divider sind verschiebbar
- [ ] Text-Dateien werden in FileList angezeigt (nur text-basierte MIME-Types)
- [ ] Chat-Prompt mit ausgewaehlten Dateien sendet SSE-Request
- [ ] AI-Antwort wird als Chat-Nachrichten gerendert
- [ ] file_edit Vorschlaege erscheinen im DiffPreview Panel
- [ ] Accept/Reject Buttons funktionieren (Accept ueberschreibt Datei in DB)
- [ ] Follow-Up Prompts nutzen bestehenden Workflow (kein neuer Workflow pro Message)
- [ ] Keine Auswirkungen auf bestehende Features (Chatplayground, Automation, Chatbot, Teamsbot)

View file

@ -0,0 +1,263 @@
---
name: Cursor-Style Chat Feature MVP
overview: Integration eines Cursor-artigen File-Editing-Chat-Features als neues Feature "codeeditor" im Gateway und der Nyla UI. Nutzt aicore-Modelle direkt, Chat-Datenmodelle vom Chatplayground, SSE-Streaming vom Chatbot-Feature. Nur Text-Dokumente (Markdown, JSON, YAML, Code). Dateien werden hochgeladen (kein SharePoint), spaeter mit virtuellen Folder-Tags strukturiert. Apply erzeugt neue lokale Dokument-Versionen.
todos:
- id: extend-workflow-mode
content: WorkflowModeEnum um WORKFLOW_CODEEDITOR erweitern in datamodelChat.py + FileContext/FileEditProposal Models
status: pending
- id: backend-feature-scaffold
content: "Feature-Scaffold: mainCodeeditor.py (Registrierung) + routeFeatureCodeeditor.py (Endpoints, Vorlage: chatplayground)"
status: pending
- id: file-context-manager
content: "fileContextManager.py: Hochgeladene Text-Dateien laden, Workspace-Snapshot erstellen (kein SharePoint)"
status: pending
- id: prompt-assembly
content: "promptAssembly.py: Cursor-artiger System Prompt Builder mit Datei-Kontext und Format-Instruktionen"
status: pending
- id: response-parser
content: "responseParser.py: AI-Antwort in Document-Segmente parsen (text, code_block, file_edit, etc.)"
status: pending
- id: frontend-feature-register
content: "FeatureView.tsx: codeeditor Views registrieren, CodeEditorPage + FileBrowserPanel + DiffPreviewPanel erstellen"
status: pending
- id: frontend-hooks
content: "useCodeEditor.ts Hook: Erweitert Playground-Pattern um File-Selection und Edit-Management"
status: pending
isProject: false
---
# MVP: Cursor-Style File-Editing Chat Feature ("CodeEditor")
## Professionelle Einschaetzung
### Kernfrage: aicore-Modelle direkt oder ueber Chat-Komponente?
**Empfehlung: Die bestehenden aicore-Modelle direkt nutzen** (nicht ueber eine externe Cursor-Chat-Komponente).
Begruendung:
- Die aicore-Infrastruktur (`aicoreModelRegistry`, `aicoreModelSelector`, Plugin-System) ist bereits produktionsreif mit Failover, Billing, RBAC und Multi-Provider-Support
- Eine externe Cursor-Komponente wuerde eine Abhaengigkeit schaffen, die schwer zu kontrollieren ist
- Der Mehrwert liegt nicht im LLM-Aufruf (den beherrscht aicore), sondern in der **Prompt-Orchestrierung** (System Prompt + Context + Tool Definitions) und dem **Response Parsing** (Antwort in Dokument-Segmente zerlegen)
- Der neue "Cursor-Style" Layer wird **auf aicore aufgebaut**, nicht neben oder statt aicore
### Was vom Chatplayground uebernommen werden kann
Sehr viel -- die Grundarchitektur ist ideal:
- **ChatWorkflow** Datenmodell: 1:1 wiederverwendbar (neuer `workflowMode: "CodeEditor"`)
- **ChatMessage** + **ChatDocument**: Vollstaendig wiederverwendbar fuer Chat-Verlauf und Datei-Referenzen
- **Polling-Mechanismus** (`getUnifiedChatData` mit `afterTimestamp`): Sofort nutzbar
- **SSE-Infrastruktur** (aus Chatbot-Feature): Kann fuer Echtzeit-Streaming aktiviert werden
- **PlaygroundPage UI-Pattern**: Resizable Two-Column Layout, Messages-Komponente, File-Upload, Input-Footer
- **Route-Pattern** (`routeFeatureChatplayground.py`): Als Vorlage fuer neue Feature-Route
- **Feature-Registrierung**: `VIEW_COMPONENTS` Registry in `FeatureView.tsx`, Backend `mainChatplayground.py`
### Was NEU gebaut werden muss
1. **File-Context-Manager** (Backend): Hochgeladene Text-Dateien als "Workspace" laden und als Kontext bereitstellen (kein SharePoint, spaeter virtuelle Folder-Tags)
2. **Prompt Assembly Service** (Backend): System Prompt mit File-Kontext und Cursor-artigen Instruktionen zusammenbauen
3. **Response Document Parser** (Backend): AI-Antwort in typisierte Dokument-Segmente zerlegen (text, code_block, file_edit, etc.)
4. **Diff-Preview UI** (Frontend): Text-Aenderungen als Diff anzeigen mit Accept/Reject
5. **File-List Panel** (Frontend): Hochgeladene Dateien auflisten und als Kontext auswaehlen (spaeter: virtuelle Folder-Tags)
6. **SSE-Integration** (Backend+Frontend): Echtzeit-Streaming ueber bestehende EventManager-Infrastruktur
---
## Architektur
```mermaid
flowchart TB
subgraph ui [Nyla UI - Frontend]
CodeEditorPage["CodeEditorPage\n(neue View)"]
FileList["FileListPanel\n(hochgeladene Dateien)"]
ChatPanel["ChatPanel\n(Messages + SSE)"]
DiffPreview["DiffPreviewPanel\n(Text-Diffs)"]
CodeEditorPage --> FileList
CodeEditorPage --> ChatPanel
CodeEditorPage --> DiffPreview
end
subgraph gw [Gateway - Backend]
Route["routeFeatureCodeeditor.py\n(FastAPI Endpoints)"]
SSE["SSE Stream Endpoint\n(EventManager)"]
FileCtx["fileContextManager.py\n(Text-Dateien laden)"]
PromptAsm["promptAssembly.py\n(System Prompt Builder)"]
RespParse["responseParser.py\n(Document Segmentation)"]
Route --> FileCtx
Route --> PromptAsm
PromptAsm --> AiService["serviceAi\n(bestehend)"]
AiService --> AiCore["aicore\n(ModelRegistry + Plugins)"]
RespParse --> Route
RespParse --> SSE
end
subgraph data [Datenspeicher]
DB["Gateway DB\n(interfaceDbComponent)\nHochgeladene Dateien"]
end
ChatPanel -->|"POST /api/codeeditor/.../start"| Route
ChatPanel -->|"GET .../stream (SSE)"| SSE
FileList -->|"GET .../files"| Route
DiffPreview -->|"POST .../apply"| Route
FileCtx --> DB
```
---
## MVP Scope: Konkrete Implementierung
### Backend: Gateway
**1. Neues Feature `codeeditor`**
- Datei: `gateway/modules/features/codeeditor/mainCodeeditor.py`
- Registrierung analog zu `mainChatplayground.py` (RBAC, Feature-Config)
**2. Routes**
- Datei: `gateway/modules/features/codeeditor/routeFeatureCodeeditor.py`
- Kopie von `routeFeatureChatplayground.py` als Basis, erweitert um:
| Endpoint | Methode | Beschreibung |
| -------------------------------------- | ------- | ---------------------------------------------------------- |
| `/{instanceId}/start` | POST | Workflow starten (nutzt `chatStart` mit mode `CodeEditor`) |
| `/{instanceId}/{workflowId}/stop` | POST | Workflow stoppen |
| `/{instanceId}/{workflowId}/stream` | GET | SSE-Stream fuer Echtzeit-Updates (Messages, Logs, Edits) |
| `/{instanceId}/{workflowId}/chatData` | GET | Fallback-Polling fuer Chat-Daten |
| `/{instanceId}/workflows` | GET | Workflows auflisten |
| `/{instanceId}/files` | GET | Hochgeladene Text-Dateien auflisten |
| `/{instanceId}/files/{fileId}/content` | GET | Text-Datei-Inhalt laden |
| `/{instanceId}/{workflowId}/apply` | POST | Aenderung als neue Dokument-Version speichern |
**3. WorkflowMode Erweiterung**
- Datei: `gateway/modules/datamodels/datamodelChat.py`
- Neuer Enum-Wert: `WORKFLOW_CODEEDITOR = "CodeEditor"` in `WorkflowModeEnum`
**4. File Context Manager**
- Datei: `gateway/modules/features/codeeditor/fileContextManager.py`
- Laedt hochgeladene Text-Dateien aus Gateway DB (`interfaceDbComponent`)
- Unterstuetzte Formate: `.md`, `.txt`, `.json`, `.yaml`, `.yml`, `.xml`, `.csv`, `.py`, `.js`, `.ts`, `.html`, `.css`, `.sql`
- Baut einen "Workspace-Snapshot": Dateiliste + Inhalte der vom User ausgewaehlten Dateien
- Validiert MIME-Types (nur text-basierte Dateien akzeptieren)
- Spaeter erweiterbar: virtuelle Folder-Tags pro Datei fuer Strukturierung
**5. Prompt Assembly**
- Datei: `gateway/modules/features/codeeditor/promptAssembly.py`
- Baut System Prompt nach Cursor-Muster (dokumentiert in `wiki/cursor-doc/doc_cursor_ai_agent_architecture.md`)
- Injiziert: Datei-Kontexte, Benutzer-Instruktionen, Antwort-Format-Vorgaben
- Nutzt `aiService.callAiContent()` oder `interfaceAiObjects.callWithTextContext()` als LLM-Aufruf
**6. Response Document Parser**
- Datei: `gateway/modules/features/codeeditor/responseParser.py`
- Parst AI-Antwort in typisierte Segmente: `text`, `code_block`, `code_reference`, `file_edit`
- Speichert Segmente als erweiterte `ChatMessage` Eintraege (mit `actionMethod: "codeeditor"`)
- Spezifikation: `wiki/cursor-doc/doc_cursor_response_json_structure.md`
### Frontend: Nyla UI
**7. Feature-Registrierung**
- Datei: `frontend_nyla/src/pages/FeatureView.tsx`
- Neuer Eintrag in `VIEW_COMPONENTS`:
```typescript
codeeditor: {
editor: CodeEditorPage,
workflows: WorkflowsPage, // wiederverwendet
}
```
**8. CodeEditorPage**
- Datei: `frontend_nyla/src/pages/views/codeeditor/CodeEditorPage.tsx`
- Drei-Panel-Layout (File-Browser links, Chat mitte, Diff-Preview rechts)
- Nutzt bestehende `Messages` Komponente, `useResizablePanels`, `usePlayground`-Pattern
**9. File List Panel**
- Datei: `frontend_nyla/src/components/CodeEditor/FileListPanel.tsx`
- Flache Liste der hochgeladenen Text-Dateien mit Checkbox-Auswahl
- Upload-Button fuer neue Dateien (Drag & Drop wiederverwendet aus Playground)
- Ausgewaehlte Dateien werden als Kontext an den Chat gesendet (analog `listFileId`)
- Spaeter erweiterbar: virtuelle Folder-Tags als Gruppierung
**10. Diff Preview Panel**
- Datei: `frontend_nyla/src/components/CodeEditor/DiffPreviewPanel.tsx`
- Zeigt `file_edit` Segmente aus der AI-Antwort als Text-Diff an
- Accept/Reject Buttons pro Aenderung
- Accept erzeugt neue Dokument-Version (POST `/{instanceId}/{workflowId}/apply`)
- MVP: einfacher Side-by-Side Text-Diff (kein vollstaendiger Code-Editor noetig)
**11. Hooks**
- Datei: `frontend_nyla/src/hooks/useCodeEditor.ts`
- Erweitert `useDashboardInputForm` Pattern um:
- `selectedFiles: string[]` (ausgewaehlte Kontext-Dateien)
- `pendingEdits: FileEdit[]` (vorgeschlagene Aenderungen)
- `applyEdit(editId)` / `rejectEdit(editId)` Aktionen
### Datenmodell-Erweiterungen
**12. Neue Pydantic Models** (in bestehendem `datamodelChat.py` oder eigenem File)
```python
class FileContext(BaseModel):
fileId: str
fileName: str
content: Optional[str] = None
mimeType: str
tags: List[str] = Field(default_factory=list) # virtuelle Folder-Tags (spaeter)
class FileEditProposal(BaseModel):
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
fileId: str # Referenz auf bestehende Datei
fileName: str
operation: str # "edit" | "create"
oldContent: Optional[str] = None
newContent: str
diffSummary: Optional[str] = None # Kurzbeschreibung der Aenderung
status: str = "pending" # "pending" | "accepted" | "rejected"
class FileVersion(BaseModel):
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
sourceFileId: str # Original-Datei
editProposalId: str # Referenz auf akzeptiertes FileEditProposal
newFileId: str # Neue Datei-Version in DB
createdAt: float = Field(default_factory=getUtcTimestamp)
```
---
## Entschiedene Design-Entscheide
1. **Datenquelle**: Hochgeladene Dateien im System (kein SharePoint). Spaeter: virtuelle Folder-Tags pro Datei fuer Strukturierung
2. **Dateitypen**: Nur Text-basierte Dokumente (Markdown, JSON, YAML, Code, etc.)
3. **Apply-Mechanismus**: Erzeugt neue lokale Dokument-Version in der DB (keine externe Synchronisation)
4. **Streaming**: SSE ueber bestehende `EventManager`-Infrastruktur aus dem Chatbot-Feature
---
## SSE-Integration (Details)
Nutzt die bestehende Infrastruktur aus `gateway/modules/features/chatbot/streaming/events.py`:
- **EventManager** Singleton: `get_event_manager()` - verwaltet async Queues pro Workflow
- **Event-Emission**: In `interfaceDbChat.createMessage()` und `createLog()` bereits eingebaut
- **Neuer SSE-Endpoint**: `GET /api/codeeditor/{instanceId}/{workflowId}/stream`
- **Event-Typen fuer CodeEditor**:
- `chatdata` (bestehend): Messages, Logs, Stats
- `file_edit` (neu): FileEditProposal Events fuer Echtzeit-Diff-Updates
- `file_version` (neu): Neue Datei-Version erstellt (nach Apply)
- **Frontend**: `useCodeEditor` Hook oeffnet `EventSource` statt Polling
- **Fallback**: `chatData` Polling-Endpoint bleibt als Fallback verfuegbar

View file

@ -0,0 +1,361 @@
# Refactoring Concept: Add WEB_SEARCH_MEDIA Operation Type
## Executive Summary
**Refactoring Goal**: Add image search capability by introducing `WEB_SEARCH_MEDIA` operation type and Google Custom Search connector.
**Current State**:
- ✅ `WEB_SEARCH_DATA` already exists (replaces former `WEB_SEARCH`)
- ✅ Tavily connector handles `WEB_SEARCH_DATA` for web page/content search
- ✅ `AiCallPromptWebSearchData` model exists
**Target State**:
- Add `WEB_SEARCH_MEDIA` operation type for image/media search
- Create Google Custom Search connector for `WEB_SEARCH_MEDIA`
- Create `AiCallPromptWebSearchMedia` model
- Add `ai.searchImages` action using `WEB_SEARCH_MEDIA`
**Estimated Complexity**: Medium (1-2 days development)
**Integration Impact**: Low - additive changes, no breaking changes
---
## 1. Current Architecture
### 1.1 Operation Types
**Current Operation Types** (`gateway/modules/datamodels/datamodelAi.py`):
```python
class OperationTypeEnum(str, Enum):
# ... existing operations ...
# Web Operations
WEB_SEARCH_DATA = "webSearchData" # Web page search (Tavily) ✅ EXISTS
WEB_CRAWL = "webCrawl" # Web crawl for a given URL
```
**Target Operation Types**:
```python
class OperationTypeEnum(str, Enum):
# ... existing operations ...
# Web Operations
WEB_SEARCH_DATA = "webSearchData" # Web page search (Tavily) ✅ EXISTS
WEB_SEARCH_MEDIA = "webSearchMedia" # Image/media search (Google) ⬅️ NEW
WEB_CRAWL = "webCrawl" # Web crawl for a given URL
```
### 1.2 Model Capabilities
**Tavily Connector** (`gateway/modules/aicore/aicorePluginTavily.py`):
- ✅ Registered for `WEB_SEARCH_DATA` (rating: 9)
- ✅ Registered for `WEB_CRAWL` (rating: 10)
- ❌ Does NOT support image search - designed for web/text content only
**Model Selection**:
- Dynamic model selection routes based on `OperationTypeEnum` in `AiCallOptions`
- Models register capabilities via `operationTypes` with ratings (1-10)
- System automatically selects best model for each operation type
---
## 2. Refactoring Plan
### 2.1 Add WEB_SEARCH_MEDIA Operation Type
**File**: `gateway/modules/datamodels/datamodelAi.py`
**Changes**:
```python
class OperationTypeEnum(str, Enum):
# ... existing operations ...
# Web Operations
WEB_SEARCH_DATA = "webSearchData" # Web page search (Tavily)
WEB_SEARCH_MEDIA = "webSearchMedia" # Image/media search (Google) ⬅️ ADD
WEB_CRAWL = "webCrawl" # Web crawl for a given URL
```
### 2.2 Create AiCallPromptWebSearchMedia Model
**File**: `gateway/modules/datamodels/datamodelAi.py`
**Add after `AiCallPromptWebSearchData`**:
```python
class AiCallPromptWebSearchMedia(BaseModel):
"""Structured prompt format for WEB_SEARCH_MEDIA operation - returns list of image URLs."""
instruction: str = Field(description="Search instruction/query for finding relevant images")
maxResults: Optional[int] = Field(default=10, description="Maximum number of images to return (default: 10)")
imageType: Optional[str] = Field(default=None, description="Image type filter: 'photo', 'clipart', 'lineart', 'animated'")
size: Optional[str] = Field(default=None, description="Image size filter: 'small', 'medium', 'large', 'xlarge'")
color: Optional[str] = Field(default=None, description="Color filter: 'color', 'grayscale', 'transparent'")
country: Optional[str] = Field(default=None, description="Two-digit country code (lowercase, e.g., ch, us, de, fr)")
language: Optional[str] = Field(default=None, description="Language code (lowercase, e.g., de, en, fr)")
```
### 2.3 Create Google Custom Search Connector
**New File**: `gateway/modules/aicore/aicorePluginGoogle.py`
**Structure** (similar to `aicorePluginTavily.py`):
```python
class AiGoogle(BaseConnectorAi):
"""Google Custom Search connector for image search."""
def getModels(self) -> List[AiModel]:
"""Get Google Custom Search model."""
return [
AiModel(
name="google-custom-search",
displayName="Google Custom Search",
connectorType="google",
apiUrl="https://www.googleapis.com/customsearch/v1",
# ... model configuration ...
operationTypes=createOperationTypeRatings(
(OperationTypeEnum.WEB_SEARCH_MEDIA, 9)
),
functionCall=self._routeWebOperation,
# ...
)
]
async def _routeWebOperation(self, modelCall: AiModelCall) -> "AiModelResponse":
"""Route web operation based on operation type."""
operationType = modelCall.options.operationType
if operationType == OperationTypeEnum.WEB_SEARCH_MEDIA:
return await self.webSearchMedia(modelCall)
else:
return AiModelResponse(
content="",
success=False,
error=f"Unsupported operation type: {operationType}"
)
async def webSearchMedia(self, modelCall: AiModelCall) -> "AiModelResponse":
"""WEB_SEARCH_MEDIA operation - returns list of image URLs using Google Custom Search."""
# Parse AiCallPromptWebSearchMedia from messages
# Call Google Custom Search API with searchType=image
# Return JSON array of image URLs (same format as Tavily for consistency)
```
**Key Implementation Points**:
- Use Google Custom Search API with `searchType=image`
- Return image URLs in JSON array format (consistent with Tavily)
- Support filters: imageType, size, color, country, language
- Handle API errors and rate limiting
### 2.4 Update Service AI Handler
**File**: `gateway/modules/services/serviceAi/mainServiceAi.py`
**Update `_handleWebOperations()` method**:
```python
async def _handleWebOperations(
self,
prompt: str,
options: AiCallOptions,
opType: OperationTypeEnum,
aiOperationId: str
) -> AiResponse:
"""Handle WEB_SEARCH_DATA, WEB_SEARCH_MEDIA, and WEB_CRAWL operation types."""
# Existing logic handles WEB_SEARCH_DATA and WEB_CRAWL
# Add support for WEB_SEARCH_MEDIA
if opType == OperationTypeEnum.WEB_SEARCH_DATA or opType == OperationTypeEnum.WEB_SEARCH_MEDIA or opType == OperationTypeEnum.WEB_CRAWL:
# ... existing implementation ...
```
### 2.5 Add searchImages Action
**New File**: `gateway/modules/workflows/methods/methodAi/actions/searchImages.py`
**Implementation**:
```python
async def searchImages(self, parameters: Dict[str, Any]) -> ActionResult:
"""Search for images on the web using a prompt and return them as documents."""
prompt = parameters.get("prompt")
if not prompt:
return ActionResult.isFailure(error="Search prompt is required")
maxResults = parameters.get("maxResults", 5)
imageType = parameters.get("imageType")
size = parameters.get("size")
color = parameters.get("color")
# Build AiCallPromptWebSearchMedia
searchPromptModel = AiCallPromptWebSearchMedia(
instruction=prompt,
maxResults=maxResults,
imageType=imageType,
size=size,
color=color
)
# Call AI with WEB_SEARCH_MEDIA operation
searchOptions = AiCallOptions(
operationType=OperationTypeEnum.WEB_SEARCH_MEDIA,
resultFormat="json"
)
# System will automatically route to Google connector
searchResponse = await self.services.ai.callAiContent(
prompt=searchPromptModel.model_dump_json(exclude_none=True, indent=2),
options=searchOptions,
outputFormat="json"
)
# Parse response to extract image URLs
# Download images in parallel
# Create ActionDocument for each image
# Return ActionResult with list of documents
```
**Update**: `gateway/modules/workflows/methods/methodAi/methodAi.py`
**Add action definition**:
```python
"searchImages": WorkflowActionDefinition(
actionId="ai.searchImages",
description="Search for images on the web using a prompt and return them as documents",
dynamicMode=True,
parameters={
"prompt": WorkflowActionParameter(...),
"maxResults": WorkflowActionParameter(...),
"imageType": WorkflowActionParameter(...),
"size": WorkflowActionParameter(...)
},
execute=searchImages.__get__(self, self.__class__)
)
```
---
## 3. Implementation Steps
### Phase 1: Add WEB_SEARCH_MEDIA Operation Type (30 min)
1. ✅ Add `WEB_SEARCH_MEDIA = "webSearchMedia"` to `OperationTypeEnum`
2. ✅ Create `AiCallPromptWebSearchMedia` model
3. ✅ Update imports/exports
### Phase 2: Create Google Connector (4-6 hours)
1. ✅ Create `aicorePluginGoogle.py` file
2. ✅ Implement `AiGoogle` connector class
3. ✅ Implement `webSearchMedia()` method
4. ✅ Register connector in connector discovery
5. ✅ Test Google API integration
6. ✅ Handle errors and rate limiting
### Phase 3: Update Service Handlers (1-2 hours)
1. ✅ Update `serviceAi/mainServiceAi.py` to handle `WEB_SEARCH_MEDIA`
2. ✅ Ensure routing works correctly
3. ✅ Test model selection routes to Google connector
### Phase 4: Add searchImages Action (3-4 hours)
1. ✅ Create `actions/searchImages.py`
2. ✅ Implement image search logic
3. ✅ Implement parallel image download
4. ✅ Add action definition to `methodAi.py`
5. ✅ Add to `actions/__init__.py`
6. ✅ Write unit tests
### Phase 5: Testing & Integration (2-3 hours)
1. ✅ Test Google connector with real API
2. ✅ Test searchImages action end-to-end
3. ✅ Verify dynamic model selection
4. ✅ Test error handling
5. ✅ Integration testing
**Total Estimated Time**: 1-2 days
---
## 4. Configuration Requirements
### 4.1 Environment Variables
**Required**:
- `GOOGLE_SEARCH_API_KEY` - Google Custom Search API key
- `GOOGLE_SEARCH_ENGINE_ID` - Custom Search Engine ID
- Note: Must enable "Image Search" in Google Custom Search Engine settings
### 4.2 Google Custom Search Setup
1. Create Google Custom Search Engine at https://programmablesearchengine.google.com/
2. Enable "Image Search" in settings
3. Get API key from Google Cloud Console
4. Configure environment variables
---
## 5. Files to Create/Modify
### New Files
- `gateway/modules/aicore/aicorePluginGoogle.py` - Google connector
- `gateway/modules/workflows/methods/methodAi/actions/searchImages.py` - Image search action
### Modified Files
- `gateway/modules/datamodels/datamodelAi.py` - Add `WEB_SEARCH_MEDIA` and `AiCallPromptWebSearchMedia`
- `gateway/modules/services/serviceAi/mainServiceAi.py` - Handle `WEB_SEARCH_MEDIA`
- `gateway/modules/workflows/methods/methodAi/methodAi.py` - Add `searchImages` action
- `gateway/modules/workflows/methods/methodAi/actions/__init__.py` - Export `searchImages`
- Connector discovery module (if exists) - Register Google connector
---
## 6. Testing Requirements
### Unit Tests
- Google connector `webSearchMedia()` method
- `searchImages` action with various parameters
- Error handling (API errors, rate limits, invalid responses)
- Image download and validation
### Integration Tests
- End-to-end image search workflow
- Dynamic model selection routes to Google connector
- Multiple image downloads in parallel
- Verify ActionDocuments are created correctly
---
## 7. Risks & Mitigation
| Risk | Impact | Probability | Mitigation |
|------|--------|-------------|------------|
| Google API setup complexity | Medium | Medium | Provide clear setup instructions, validate API keys at startup |
| Dynamic model selection routing | Medium | Low | Thoroughly test operation type routing |
| API rate limiting (Google) | Low | Medium | Implement retry logic with exponential backoff |
| Missing connector registration | Medium | Low | Ensure connector is registered in discovery system |
---
## 8. Dependencies
- **Google Custom Search API** - REQUIRED
- **Google API Client Library** - May need `google-api-python-client` package
- **HTTP Client** - For image downloads (existing)
- **Base64 Encoding** - Python standard library (no dependency)
---
## 9. Success Criteria
`WEB_SEARCH_MEDIA` operation type exists
✅ Google connector is registered and functional
`searchImages` action works end-to-end
✅ Dynamic model selection routes `WEB_SEARCH_MEDIA` to Google connector
✅ Images are downloaded and returned as ActionDocuments
✅ All tests pass
---
**Document Version**: 2.0
**Last Updated**: 2026-01-01
**Status**: Refactoring Concept - Ready for Implementation

File diff suppressed because it is too large Load diff

66
c-work/_TEMPLATE.md Normal file
View file

@ -0,0 +1,66 @@
<!-- status: plan | build | validate | done -->
<!-- started: YYYY-MM-DD -->
<!-- component: gateway | frontend-nyla | private-llm | teams-bot | platform -->
# <Feature/Refactor Titel>
## Beschreibung und Kontext
Was ist das Thema? Warum jetzt? Was ist der Business-Treiber?
Welche Abhängigkeiten bestehen? Was ist das Risiko wenn wir es NICHT machen?
## Fokus und kritische Details
- Worauf muss besonders geachtet werden?
- Welche Stellen im Code sind fragil / komplex?
- Bekannte Fallstricke oder Edge Cases
## Ziel und Nicht-Ziele
- Ziel: ...
- Explizit NICHT: ...
## Betroffene Module
- Gateway: ...
- Frontend: ...
- DB-Migration: ja/nein
- Andere Komponenten: ...
## Entscheidungen
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
## Umsetzungs-Checkliste
- [ ] API-Endpunkte
- [ ] DB-Schema / Migration
- [ ] Frontend-Komponenten
- [ ] RBAC / Permissions
- [ ] Neutralisierung betroffen?
- [ ] Navigation / Routing
- [ ] Billing-Impact?
## Akzeptanzkriterien
| # | Kriterium (Given-When-Then) | Prio |
|---|---------------------------|------|
| 1 | Given ... When ... Then ... | must |
## Testplan
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | ja | gateway/tests/... | pending |
## Links
- PR: ...
- Issue: ...
## Abschluss
- [ ] b-reference/ aktualisiert (welche Seite?)
- [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -0,0 +1,20 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
# Coding-Konventionen
## Naming
- Alle internen Funktionen beginnen mit `_` Prefix
- camelCase für Variablen und Funktionsnamen (kein snake_case)
## Frontend-Regeln
- Keine Browser-Dialoge (alert/confirm/prompt) -- stattdessen `useConfirm()` und `usePrompt()` Hooks
- CSS Modules für Komponenten-Styles
## Backend-Regeln
- 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`

View file

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

25
d-guides/dev-setup.md Normal file
View file

@ -0,0 +1,25 @@
<!-- status: draft -->
<!-- lastReviewed: 2026-04-05 -->
# Dev-Setup
## Voraussetzungen
- Python (Anaconda/Miniconda)
- Node.js
- PostgreSQL mit pgvector
## Gateway starten
```bash
conda activate <env>
cd gateway/
uvicorn app:app --host 0.0.0.0 --port 8000
```
## Frontend Nyla starten
```bash
cd frontend_nyla/
npx vite --port 8080 --mode dev
```

View file

@ -0,0 +1,26 @@
<!-- status: draft -->
<!-- lastReviewed: 2026-04-05 -->
# Testing-Strategie
## Testpyramide
- **Unit Tests:** pytest (Gateway), vitest (Frontend)
- **Integration Tests:** API-Tests gegen laufenden Gateway
- **E2E Tests:** (zu definieren)
## Akzeptanzkriterien-Format
Given-When-Then Sätze in Arbeits-Dokumenten (`c-work/_TEMPLATE.md`)
## Testplan-Tabelle
Jedes Arbeits-Dokument enthält eine Testplan-Tabelle:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
## Test-Pfade im Repo
- Gateway: `gateway/tests/`
- Frontend: `frontend_nyla/src/**/*.test.ts`

Some files were not shown because too many files have changed in this diff Show more