docs: complete wiki restructuring - new folder hierarchy, canonical reference pages, archive old docs
Made-with: Cursor
87
README.md
Normal 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
|
|
@ -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 |
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
|
@ -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>
|
||||
75
b-reference/frontend-nyla/architecture.md
Normal 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.
|
||||
237
b-reference/gateway/ai-agent.md
Normal 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, 1–100) |
|
||||
| `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.
|
||||
106
b-reference/gateway/architecture.md
Normal 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.
|
||||
97
b-reference/gateway/automation.md
Normal 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.
|
||||
186
b-reference/gateway/billing.md
Normal 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** enforce’n, **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.
|
||||
94
b-reference/gateway/workflow.md
Normal 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.
|
||||
85
b-reference/platform/navigation.md
Normal 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`.
|
||||
81
b-reference/platform/neutralization.md
Normal 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`.
|
||||
69
b-reference/platform/rbac.md
Normal 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.
|
||||
66
b-reference/private-llm/architecture.md
Normal 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
|
|
@ -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)
|
||||
64
b-reference/teams-bot/architecture.md
Normal 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
|
||||
85
c-work/1-plan/2026-03-codeeditor-phase1.md
Normal 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)
|
||||
263
c-work/1-plan/2026-03-cursor-style-chat.md
Normal 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
|
||||
|
||||
361
c-work/1-plan/2026-03-web-image-search.md
Normal 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
|
||||
1219
c-work/1-plan/2026-03-workflow-editor.md
Normal file
66
c-work/_TEMPLATE.md
Normal 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
|
||||
20
d-guides/coding-conventions.md
Normal 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`
|
||||
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
25
d-guides/dev-setup.md
Normal 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
|
||||
```
|
||||
26
d-guides/testing-strategy.md
Normal 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`
|
||||