DOcu updated
23
TOPICS.md
|
|
@ -1,4 +1,4 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
|
||||
# Themen-Index für AI-Kontext
|
||||
|
|
@ -32,15 +32,32 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
|
|||
| 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 |
|
||||
| RBAC | b-reference/platform/rbac.md | 4-Stufen-Modell, Template-Rollen, Resolution, Datenmodell |
|
||||
| Datenbank-Architektur | b-reference/platform/database-architecture.md | Interface-Pattern, Connector, Auto-Init, DB-Liste |
|
||||
| Navigation | b-reference/platform/navigation.md | Menü-Struktur, Admin-Seiten, API |
|
||||
|
||||
## Aktive Arbeiten (c-work)
|
||||
|
||||
| Thema | Datei | Wann laden |
|
||||
|-------|-------|------------|
|
||||
| Automation Unification | c-work/1-plan/2026-04-automation-unification.md | Refactoring v1/v2/Workspace |
|
||||
| Web Image Search | c-work/1-plan/2026-03-web-image-search.md | WEB_SEARCH_MEDIA Feature |
|
||||
|
||||
## 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 |
|
||||
| Secrets-Verschluesselung | d-guides/encrypt-env-secrets.md | Env-Dateien verschluesseln |
|
||||
| Google OAuth | d-guides/google-oauth-setup.md | OAuth Auth/Data Apps einrichten |
|
||||
| Security-Migration | d-guides/security-migration-guide.md | JWT Cookie Migration |
|
||||
| Doc-Sync Cursor-Rule | d-guides/doc-sync.mdc | Cursor-Regel installieren, Doku-Workflow |
|
||||
|
||||
## Compliance & Sicherheit
|
||||
|
||||
| Thema | Datei | Wann laden |
|
||||
|-------|-------|------------|
|
||||
| Sicherheitsuebersicht | e-compliance/security-overview.md | Kunden/Audit: DSGVO, RBAC, Verschluesselung |
|
||||
| Neutralisierung Detail | e-compliance/neutralisierung-detail.md | Technische Neutralisierungs-Flows |
|
||||
|
|
|
|||
|
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 |
|
|
@ -1,4 +1,4 @@
|
|||
# Markteinschaetzung: Langdock (Berlin) vs. PowerON
|
||||
# Markteinschaetzung: Langdock (Berlin) vs. PowerOn
|
||||
|
||||
**Dokument:** Markt- und Wettbewerbsanalyse mit strategischer Empfehlung
|
||||
**Stand:** 23. Maerz 2026
|
||||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
**Langdock** ist eine horizontale Enterprise-KI-Adoptionsplattform (Chat, Workflows, Agents, Integrationen, API) mit Fokus auf sichere, modellagnostische KI fuer das gesamte Unternehmen. Sitz Berlin, tausende Kunden, schnelles Wachstum.
|
||||
|
||||
**PowerON** positioniert sich auf poweron.swiss als *"The Swiss Pocket Knife of AI for SMEs"* -- eine universelle KI-Plattform fuer Schweizer KMU mit DSGVO-Compliance und Schweizer Hosting. Im Code steckt deutlich mehr: eine mandantenfaehige SaaS-Plattform mit RBAC, Feature-Instanzen, Billing/Subscription, vertikalen Fachmodulen (Treuhand, Immobilien, CommCoach) und einem einzigartigen **Daten-Neutralisierungs-Feature**.
|
||||
**PowerOn** positioniert sich auf poweron.swiss als *"The Swiss Pocket Knife of AI for SMEs"* -- eine universelle KI-Plattform fuer Schweizer KMU mit DSGVO-Compliance und Schweizer Hosting. Im Code steckt deutlich mehr: eine mandantenfaehige SaaS-Plattform mit RBAC, Feature-Instanzen, Billing/Subscription, vertikalen Fachmodulen (Treuhand, Immobilien, CommCoach) und einem einzigartigen **Daten-Neutralisierungs-Feature**.
|
||||
|
||||
**Kernbefund:** Die oeffentliche Positionierung von PowerON ueberschneidet sich staerker mit Langdock als noetig. Das Produkt hat genuegend einzigartige Tiefe, um sich klar abzugrenzen -- die Botschaft muss geschaerft werden.
|
||||
**Kernbefund:** Die oeffentliche Positionierung von PowerOn ueberschneidet sich staerker mit Langdock als noetig. Das Produkt hat genuegend einzigartige Tiefe, um sich klar abzugrenzen -- die Botschaft muss geschaerft werden.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
---
|
||||
|
||||
## 3. PowerON -- Oeffentliche Positionierung (poweron.swiss)
|
||||
## 3. PowerOn -- Oeffentliche Positionierung (poweron.swiss)
|
||||
|
||||
### 3.1 Claim und Zielgruppe
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ Im Code existiert dafuer ein eigenes Feature-Modul (`neutralization`) mit Playgr
|
|||
|
||||
---
|
||||
|
||||
## 4. PowerON -- Realitaet im Code (ueber die Homepage hinaus)
|
||||
## 4. PowerOn -- Realitaet im Code (ueber die Homepage hinaus)
|
||||
|
||||
Die Codebase zeigt erheblich mehr Tiefe als die Website kommuniziert:
|
||||
|
||||
|
|
@ -115,13 +115,13 @@ Die Codebase zeigt erheblich mehr Tiefe als die Website kommuniziert:
|
|||
|
||||
### 4.3 Gap: Homepage vs. Code
|
||||
|
||||
Die Website zeigt PowerON als **generische KI-Plattform**. Der Code offenbart eine **spezialisierte SaaS mit Branchen-Features, Abrechnungslogik und tiefer Mandantenfaehigkeit** -- davon erfaehrt der Besucher von poweron.swiss aktuell nichts.
|
||||
Die Website zeigt PowerOn als **generische KI-Plattform**. Der Code offenbart eine **spezialisierte SaaS mit Branchen-Features, Abrechnungslogik und tiefer Mandantenfaehigkeit** -- davon erfaehrt der Besucher von poweron.swiss aktuell nichts.
|
||||
|
||||
---
|
||||
|
||||
## 5. Ueberschneidungen PowerON vs. Langdock
|
||||
## 5. Ueberschneidungen PowerOn vs. Langdock
|
||||
|
||||
| Thema | Langdock | PowerON |
|
||||
| Thema | Langdock | PowerOn |
|
||||
|-------------------------|-----------------------------------|-----------------------------------------------|
|
||||
| Firmenweite KI-Nutzung | Kerngeschaeft | Workspace, Chatbot, Teamsbot |
|
||||
| Chat & Konversationen | Chat-Produkt | Chatbot + Workspace-Editor |
|
||||
|
|
@ -131,13 +131,13 @@ Die Website zeigt PowerON als **generische KI-Plattform**. Der Code offenbart ei
|
|||
| Integrationen | Viele Standard-Integrationen | M365, Google, Jira, ClickUp, SharePoint, DB |
|
||||
| Governance / Security | EU-Hosting, DSGVO | Schweizer Hosting, DSGVO, RBAC, Neutralisierung|
|
||||
|
||||
**Die generische KI-Schicht ueberschneidet sich stark.** Wer nur "ChatGPT im Unternehmen" sucht, sieht PowerON und Langdock in der gleichen Kategorie -- wobei Langdock dort durch Marktgroesse und Bekanntheit dominiert.
|
||||
**Die generische KI-Schicht ueberschneidet sich stark.** Wer nur "ChatGPT im Unternehmen" sucht, sieht PowerOn und Langdock in der gleichen Kategorie -- wobei Langdock dort durch Marktgroesse und Bekanntheit dominiert.
|
||||
|
||||
---
|
||||
|
||||
## 6. Klare Unterschiede (PowerON-Vorteile)
|
||||
## 6. Klare Unterschiede (PowerOn-Vorteile)
|
||||
|
||||
| Dimension | PowerON | Langdock |
|
||||
| Dimension | PowerOn | Langdock |
|
||||
|----------------------------|----------------------------------------------|---------------------------------|
|
||||
| **Daten-Neutralisierung** | 5-Stufen-Prozess, eigenes Feature | Nicht vorhanden |
|
||||
| **Schweizer Hosting** | 100% Schweiz, lokale Datensouveraenitaet | EU (nicht CH-spezifisch) |
|
||||
|
|
@ -151,13 +151,13 @@ Die Website zeigt PowerON als **generische KI-Plattform**. Der Code offenbart ei
|
|||
|
||||
### 7.1 Kernproblem der aktuellen Positionierung
|
||||
|
||||
Die Homepage positioniert PowerON als **generische KI-Plattform** -- genau dort, wo Langdock (und Microsoft Copilot, und Google Gemini for Workspace, und dutzende weitere) bereits mit massiv mehr Ressourcen, Brand und Kundenstamm unterwegs sind.
|
||||
Die Homepage positioniert PowerOn als **generische KI-Plattform** -- genau dort, wo Langdock (und Microsoft Copilot, und Google Gemini for Workspace, und dutzende weitere) bereits mit massiv mehr Ressourcen, Brand und Kundenstamm unterwegs sind.
|
||||
|
||||
Ein Drei-Personen-Team kann dieses Rennen nicht auf der generischen Ebene gewinnen. Jede Stunde, die in "wir sind auch ein KI-Chat mit Workflows" investiert wird, ist eine Stunde, in der Langdock mit tausenden Kunden und Millionen-Revenue den gleichen Pitch perfektioniert.
|
||||
|
||||
### 7.2 Empfohlene Richtung: Vertikale KI-SaaS mit Neutralisierungs-Moat
|
||||
|
||||
**PowerON sollte sich als vertikale, mandantenfaehige KI-SaaS positionieren -- nicht als generische KI-Plattform.**
|
||||
**PowerOn sollte sich als vertikale, mandantenfaehige KI-SaaS positionieren -- nicht als generische KI-Plattform.**
|
||||
|
||||
Die empfohlene Positionierung stuetzt sich auf drei Saeulen:
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ Die empfohlene Positionierung stuetzt sich auf drei Saeulen:
|
|||
|
||||
Die Daten-Neutralisierung ist das Feature, das kein Wettbewerber in dieser Form hat. Statt es als eines von fuenf technischen Features aufzulisten, sollte es das **zentrale Verkaufsargument** werden:
|
||||
|
||||
- *"PowerON ist die einzige KI-Plattform, bei der LLMs niemals Ihre sensiblen Daten sehen -- garantiert durch einen 5-Stufen-Neutralisierungsprozess."*
|
||||
- *"PowerOn ist die einzige KI-Plattform, bei der LLMs niemals Ihre sensiblen Daten sehen -- garantiert durch einen 5-Stufen-Neutralisierungsprozess."*
|
||||
- Besonders relevant fuer: Treuhand, Kanzleien, Gesundheitswesen, Finanzdienstleister, oeffentliche Verwaltung.
|
||||
- Alle anderen Features (Chat, Automation, Workspace) werden **unter dem Neutralisierungs-Dach** vermarktet, nicht daneben.
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ Die Daten-Neutralisierung ist das Feature, das kein Wettbewerber in dieser Form
|
|||
|
||||
Der Code enthaelt bereits Treuhand, Immobilien und CommCoach. Diese Module gehoeren sichtbar auf die Website und in den Pitch:
|
||||
|
||||
- Dedizierte Landing Pages pro Branche: "PowerON fuer Treuhandbueros", "PowerON fuer Immobilienverwaltungen".
|
||||
- Dedizierte Landing Pages pro Branche: "PowerOn fuer Treuhandbueros", "PowerOn fuer Immobilienverwaltungen".
|
||||
- Jede Branchenseite zeigt den konkreten Workflow: Dokument rein, Neutralisierung, KI-Verarbeitung, Ergebnis zurueck -- mit branchenspezifischem Vokabular.
|
||||
- Der Feature-Store und das Mandantenmodell sind dabei die **technische Grundlage**, nicht der Marketing-Lead.
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ Der Code enthaelt bereits Treuhand, Immobilien und CommCoach. Diese Module gehoe
|
|||
### 7.4 Wovon ich abrate
|
||||
|
||||
1. **Breites Integrations-Rennen:** Langdock hat Dutzende Integrationen; dieses Rennen zu gewinnen ist mit kleinem Team unrealistisch. Besser: die vorhandenen Integrationen (M365, SharePoint, Google) **tief und zuverlaessig** halten und pro Branche gezielt erweitern (z. B. ABACUS/Bexio fuer Treuhand).
|
||||
2. **"KI-Chat fuer alle":** Das ist Langdocks Kernmarkt. PowerON gewinnt nicht, indem es den gleichen Pitch macht, sondern indem es den Pitch **spezifischer** macht.
|
||||
2. **"KI-Chat fuer alle":** Das ist Langdocks Kernmarkt. PowerOn gewinnt nicht, indem es den gleichen Pitch macht, sondern indem es den Pitch **spezifischer** macht.
|
||||
3. **Feature-Breite vor Feature-Tiefe:** Lieber drei Branchen exzellent bedienen als zehn Features halb fertig zeigen (vgl. `features.feature5.title`-Platzhalter auf der Homepage).
|
||||
|
||||
### 7.5 Mittelfristiger Zielzustand (6-12 Monate)
|
||||
|
|
@ -212,13 +212,13 @@ Der Code enthaelt bereits Treuhand, Immobilien und CommCoach. Diese Module gehoe
|
|||
|
||||
## 8. Zusammenfassung in einem Satz
|
||||
|
||||
> PowerON sollte aufhoeren, Langdocks Spiel zu spielen ("generische KI fuer alle"), und stattdessen das eigene Spiel spielen: **sichere, neutralisierte KI fuer regulierte Schweizer Branchen** -- ein Markt, den Langdock strukturell nicht adressiert.
|
||||
> PowerOn sollte aufhoeren, Langdocks Spiel zu spielen ("generische KI fuer alle"), und stattdessen das eigene Spiel spielen: **sichere, neutralisierte KI fuer regulierte Schweizer Branchen** -- ein Markt, den Langdock strukturell nicht adressiert.
|
||||
|
||||
---
|
||||
|
||||
## 9. Quellen und Methodik
|
||||
|
||||
- **PowerON:** Homepage poweron.swiss (Stand Maerz 2026) sowie Codeanalyse gateway und frontend_nyla.
|
||||
- **PowerOn:** Homepage poweron.swiss (Stand Maerz 2026) sowie Codeanalyse gateway und frontend_nyla.
|
||||
- **Langdock:** Oeffentliche Website langdock.com und Produktunterseiten, Presseartikel (Stand Maerz 2026).
|
||||
- Keine vertraulichen Materialien verwendet. Fuer verbindliche Pricing- und SLA-Vergleiche ist Herstellerkontakt noetig.
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
1) **🔒 Neutralizer (Datenschutz-First)**
|
||||
- **Automatische Anonymisierung** sensibler Daten vor der KI-Verarbeitung
|
||||
- **DSGVO-konform**, transparente Regeln – du bestimmst, was neutralisiert wird
|
||||
- **Validierungs-Roadmap**: Level 1 Datenschutz jetzt; Level 2 kontextueller IP-Schutz folgt mit externem Validat/Cert (ETH/HSG/Partner)
|
||||
- **Validierungs-Roadmap**: Level 1 Datenschutz jetzt; Level 2 kontextueller IP-Schutz folgt mit externem Validator/Zertifizierung (ETH/HSG/Partner)
|
||||
|
||||
2) **♾️ Unlimitierte Verarbeitung**
|
||||
- **Keine Token-Limits** – Dokumente jeder Grösse verarbeiten
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ PowerOn ist eine **Multi-Agent-KI-Plattform für Enterprise-Workflows** mit inte
|
|||
### 2.2 Alleinstellungsmerkmale (USP)
|
||||
|
||||
#### **1. Integrierter Datenschutz-Neutralisierer**
|
||||
- **Einzigartig**: Erste Plattform mit eingebautem Datenschutz-Schutz
|
||||
- **Einzigartig**: Erste Plattform mit eingebautem Datenschutz-Neutralisierer
|
||||
- **Vorteil**: Unternehmen können KI nutzen ohne Datenschutzrisiken
|
||||
- **Differenzierung**: Kein Konkurrent bietet diese Funktionalität
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ PowerOn ist eine **Multi-Agent-KI-Plattform für Enterprise-Workflows** mit inte
|
|||
- **3 Workflow-Modi**:
|
||||
- **Learning-Mode**: Iterative Plan-Act-Observe-Refine-Schleife
|
||||
- **Actionplan-Mode**: Batch-Planung mit sequenzieller Ausführung
|
||||
- **Automation-Mode**: Automatisierte vordefinierte Workflosw
|
||||
- **Automation-Mode**: Automatisierte vordefinierte Workflows
|
||||
- **Adaptive Learning Engine**: Lernt aus Validierungsergebnissen und passt Prompts an
|
||||
- **Intelligente Task-Planung**: Automatische Aufschlüsselung komplexer Anfragen in ausführbare Schritte
|
||||
- **Echtzeit-Validierung**: Kontinuierliche Qualitätskontrolle und automatische Verbesserungen
|
||||
|
|
@ -701,7 +701,7 @@ Wir sind aktuell im Monat 10 des Projekts und haben noch 2 Monate bis zur Seed-R
|
|||
#### **KI-Services**
|
||||
- **OpenAI**: GPT-4, DALL-E, Whisper
|
||||
- **Anthropic**: Claude, Constitutional AI
|
||||
- **Google**: PaLM, Bard, Vertex AI
|
||||
- **Google**: Gemini, Vertex AI
|
||||
- **Azure**: Cognitive Services, OpenAI Service
|
||||
|
||||
---
|
||||
|
|
|
|||
71
a-strategy/product-vision.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
|
||||
# PowerOn PORTA -- Produktvision
|
||||
|
||||
## Was ist PowerOn PORTA?
|
||||
|
||||
PowerOn PORTA ist eine **Multi-Agent-KI-Plattform für Enterprise-Workflows** mit integriertem Datenschutz-Neutralisierer. Die Plattform ermöglicht Unternehmen, KI-Transformation zu beschleunigen, ohne Datenschutzrisiken einzugehen.
|
||||
|
||||
**PORTA** = **P**owerful **O**rchestration & **R**eal-**T**ime **A**utomation
|
||||
|
||||
## Value Proposition
|
||||
|
||||
| Problem | PowerOn-Lösung |
|
||||
|---------|---------------|
|
||||
| 80% der Unternehmen können ChatGPT/Copilot nicht nutzen wegen Datenschutz | Integrierter Datenschutz-Neutralisierer: sensible Daten verlassen nie das Unternehmen |
|
||||
| Token-Limits bei grossen Dokumenten | Unlimitierte Verarbeitung durch intelligente Chunking-Strategien |
|
||||
| Isolierte KI-Services arbeiten nicht zusammen | Einheitliche Plattform mit nahtloser Integration aller Services |
|
||||
| Komplexe, unvorhersehbare Pricing-Modelle | Transparentes Pauschalpricing pro Monat/Jahr |
|
||||
| End-to-End-Workflows sind Expertensache | Schrittweise Integration, beginnend mit einfachen Use Cases |
|
||||
|
||||
## Zielkunden
|
||||
|
||||
- **Primär:** Mittelständische Unternehmen (100-2'000 MA) in datenschutz-sensitiven Branchen
|
||||
- **Branchen:** Finanzdienstleistungen, Treuhand, Immobilien, Professional Services, Healthcare
|
||||
- **Geografie:** DACH (initial), EU + US (Expansion)
|
||||
|
||||
## Alleinstellungsmerkmale (USPs)
|
||||
|
||||
1. **Datenschutz-Neutralisierer:** Einzige Plattform mit integrierter Echtzeit-Neutralisierung, die sensible Daten vor dem Verlassen des Unternehmens anonymisiert und nach Verarbeitung reanonymisiert.
|
||||
|
||||
2. **Multi-Agent-Orchestrierung:** Spezialisierte KI-Agenten pro Aufgabe (Chat, Workflow, Voice, RAG, Automation), koordiniert durch eine zentrale Engine mit 40+ Tools.
|
||||
|
||||
3. **Modellunabhängigkeit:** Integration mit Anthropic, OpenAI, Mistral, Perplexity, Tavily, Private LLM -- kein Vendor Lock-in, immer das beste Modell pro Aufgabe.
|
||||
|
||||
4. **Feature-Store-Architektur:** Mandanten aktivieren Features modular (Workspace, Automation, CommCoach, Trustee etc.) -- skaliert von Einzelanwendung bis Full-Suite.
|
||||
|
||||
5. **Voice-First:** Integrierte STT/TTS in den meisten Sprachen, nahtlos im Workflow nutzbar.
|
||||
|
||||
## Technologie-Stack (Kurzübersicht)
|
||||
|
||||
| Komponente | Technologie |
|
||||
|-----------|-------------|
|
||||
| Frontend Nyla | React/TypeScript, Vite |
|
||||
| Gateway | FastAPI, Python, PostgreSQL, pgvector |
|
||||
| Private LLM | Python, Ollama |
|
||||
| Teams Bot | TypeScript/Node.js |
|
||||
|
||||
Detaillierte Architektur: → `b-reference/product.md`
|
||||
|
||||
## Umsatzmodell
|
||||
|
||||
- **SaaS-Abonnement:** Pauschal pro Monat/Jahr, Features modular zubuchbar
|
||||
- **Ziel-Bruttomarge:** 75-85% nach Skalierung
|
||||
- **Preismodell:** Nicht nutzungsbasiert pro Token, sondern unlimitiert innerhalb des Abonnements
|
||||
|
||||
## Strategische Phasen
|
||||
|
||||
| Phase | Zeitraum | Fokus |
|
||||
|-------|---------|-------|
|
||||
| Launch | 2025-2026 | Core-Plattform, 3-5 Referenzkunden, DACH |
|
||||
| Growth | 2026-2027 | Feature-Expansion, branchenspezifische Templates, Partner |
|
||||
| Scale | 2027+ | Internationalisierung, Agenten-Marktplatz, Branchenlösungen |
|
||||
|
||||
## Verweise
|
||||
|
||||
- Strategie & PMF: → `a-strategy/product-strategy.md`
|
||||
- Roadmap: → `a-strategy/roadmap.md`
|
||||
- Marktanalyse: → `a-strategy/market/`
|
||||
- Investor-Zusammenfassung: → `a-strategy/investor/investor-summary.md`
|
||||
- Komponentenübersicht: → `b-reference/product.md`
|
||||
|
|
@ -17,7 +17,7 @@ Dieses Dokument beschreibt die vorhandenen Features der PowerOn-Plattform, das a
|
|||
|
||||
PowerOn ist eine **Multi-Mandanten-Plattform**:
|
||||
|
||||
- **Mandatenmodell:** Jede Organisation/Kunde wird als Mandant abgebildet.
|
||||
- **Mandantenmodell:** Jede Organisation/Kunde wird als Mandant abgebildet.
|
||||
- **Datenisolation:** Daten eines Mandanten sind strikt von anderen Mandanten getrennt.
|
||||
- **Zugehörigkeitsprüfung:** Bei jedem Zugriff wird geprüft, ob der Nutzer dem Mandanten angehört (via `UserMandate`).
|
||||
- **Request-Kontext:** `mandateId` und `featureInstanceId` werden über Header (`X-Mandate-Id`, `X-Feature-Instance-Id`) übergeben.
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@
|
|||
|
||||
# Automation
|
||||
|
||||
## Überblick
|
||||
## Ueberblick
|
||||
|
||||
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).
|
||||
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 fuer 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.
|
||||
- Keine Migration von Altdaten fuer Automation v1 (nicht produktiv); v1 bleibt bis zur Abloesung.
|
||||
- **Vier Saeulen:** AI Service (Agent, Streaming, Neutralisierung, Failover), Graphical Editor (Flow + kuenftig 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 ueber Zielmodell und Uebernahme bewaehrter v1-Scheduler-Patterns in Richtung v2.
|
||||
|
||||
---
|
||||
|
||||
## Business Spec (Zusammenfassung)
|
||||
|
||||
**Ist-Systeme:**
|
||||
## Ist-Systeme (Gateway, Stand 2026-04-05)
|
||||
|
||||
| System | Kurzbeschreibung |
|
||||
|--------|------------------|
|
||||
|
|
@ -26,41 +24,9 @@ PowerOn hat **mehrere Automatisierungs-Spuren**, die sich die **gleiche Unified
|
|||
| **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`.
|
||||
**Gemeinsame technische Basis:** Alle genannten Pfade fuehren ueber **`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
|
||||
### Automation v1 vs v2 (Ist-Vergleich)
|
||||
|
||||
| Aspekt | Automation v1 | Automation2 (v2) |
|
||||
|--------|----------------|------------------|
|
||||
|
|
@ -68,20 +34,74 @@ PowerOn hat **mehrere Automatisierungs-Spuren**, die sich die **gleiche Unified
|
|||
| DB / Schema | `poweron_automation` | `poweron_automation2` |
|
||||
| Scheduler | Inkrementell, Callback `automation.changed`, `eventId` auf `AutomationDefinition` | 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 |
|
||||
| Staerken | Bewaehrtes 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.
|
||||
**Konsolidierungsrichtung (Spec):** v1-Scheduler-Muster (inkrementell, Job-Handle, Reload+`active`-Check vor Run, capped Logs, `sysCreatedBy` fuer Kontext) in die v2-Welt uebernehmen; einheitliches **Workflow/Version/Run**-Konzept langfristig ueber beide Welten.
|
||||
|
||||
---
|
||||
|
||||
## Schlüssel-Dateien
|
||||
## Datenmodell
|
||||
|
||||
### Ist: Konkrete Modelle (Gateway, Stand 2026-04-05)
|
||||
|
||||
| Modell | Datei | DB | Beschreibung |
|
||||
|--------|-------|-----|-------------|
|
||||
| `AutomationDefinition` | `features/automation/datamodelFeatureAutomation.py` | `poweron_automation` | v1 Template mit `schedule`, `placeholders`, `eventId` |
|
||||
| `ChatWorkflow` | `datamodels/datamodelChat.py` | `poweron_chat` | v1 Execution-Artefakt (Status, Tasks, Messages) |
|
||||
| `Automation2Workflow` | `features/automation2/datamodelFeatureAutomation2.py` | `poweron_automation2` | v2 Graph mit `active`, inline `graph`, `invocations` |
|
||||
| `Automation2WorkflowRun` | gleiche Datei | `poweron_automation2` | v2 Run: Status `running`/`paused`/`completed`/`failed`, `nodeOutputs`, `context` |
|
||||
| `Automation2HumanTask` | gleiche Datei | `poweron_automation2` | Human-Task: Status `pending`/`completed`/`rejected` |
|
||||
|
||||
**Hinweis:** Es gibt **keine** `WorkflowVersion`-Tabelle -- v2 speichert den Graph direkt in `Automation2Workflow`. Tracing ist `nodeOutputs` im Run, nicht ein separates `RunStepLog`-Entity.
|
||||
|
||||
### Ziel: Vereinheitlichtes Workflow-Modell (Spec -- nicht implementiert)
|
||||
|
||||
| Entitaet | Zweck | Heute approximiert durch |
|
||||
|----------|-------|--------------------------|
|
||||
| **Workflow** | Metadaten, Mandant/Instanz, `active`, `eventId`, Zeiger auf aktuelle Version | `Automation2Workflow` (ohne Versioning) |
|
||||
| **WorkflowVersion** | Immutabler Snapshot: `graph`, `invocations`, Status draft/published/archived | *nicht vorhanden* (Graph inline in Workflow) |
|
||||
| **WorkflowRun** | Ausfuehrung mit Status, Trigger, `nodeOutputs`, Kostenfelder | `Automation2WorkflowRun` (ohne Kostenfelder, Statusmenge abweichend) |
|
||||
| **RunStepLog** | Pro Node: Input, Output, Dauer, Fehler, Token | *nicht vorhanden* (approximiert durch `nodeOutputs`) |
|
||||
| **HumanTask** | Menschliche Aufgabe bei Pause; Status pending/completed/cancelled/expired | `Automation2HumanTask` (Status: `pending`/`completed`/`rejected`, kein `expired`) |
|
||||
|
||||
**Invarianten (Zielmodell):** Pro Workflow hoechstens **eine** `PUBLISHED` Version; Scheduler bindet an die veroeffentlichte Version.
|
||||
|
||||
### Toolbox-Datenmodell (Ziel -- nicht im Gateway implementiert)
|
||||
|
||||
`ToolboxDefinition` (id, label i18n, `tools[]`, optional `requiresConnection`), `ToolboxRegistry`, erweiterte `AgentConfig` mit `initialToolboxes` / `availableToolboxes`.
|
||||
|
||||
> Kein Match im Gateway-Code fuer `requestToolbox`, `ToolboxDefinition` oder `availableToolboxes` (Stand 2026-04-05).
|
||||
|
||||
### Gateway-Schichten
|
||||
|
||||
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 ueber `registry.py` / `ServiceHub`.
|
||||
|
||||
---
|
||||
|
||||
## Ziel-Konzepte (Business Spec, nicht implementiert)
|
||||
|
||||
**Toolbox-Konzept:** 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 -- nicht im Code):** `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.
|
||||
|
||||
---
|
||||
|
||||
## Schluessel-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`) |
|
||||
| Automation v1 Runtime | `workflows/automation/` (`mainWorkflow.py`, `subAutomationSchedule.py`) |
|
||||
| Automation2 Feature | `features/automation2/` |
|
||||
| Automation2 Runtime | `workflows/automation2/` (`executionEngine.py`, `subAutomation2Schedule.py`) |
|
||||
| Agent <-> Actions | `serviceCenter/services/serviceAgent/` (Tool-Registrierung, `ActionToolAdapter`) |
|
||||
| Feature-Discovery | `system/registry.py`, `serviceHub/__init__.py` |
|
||||
| RBAC | `interfaces/interfaceRbac.py`, `security/`, Rollen/AccessRules in Datamodels |
|
||||
|
||||
|
|
@ -89,9 +109,9 @@ PowerOn hat **mehrere Automatisierungs-Spuren**, die sich die **gleiche Unified
|
|||
|
||||
## 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.
|
||||
1. **Eine Action Library:** Aenderungen an Methods/Actions betreffen Workspace, Automation v1, Automation2 und Agent-Tools gleichzeitig -- Kompatibilitaet und `actionId`-Stabilitaet beachten.
|
||||
2. **RBAC strikt trennen:** Mandantenrollen vs Feature-Instanz-Rollen nicht mischen; Permissions ueber AccessRules und Prioritaetsregeln.
|
||||
3. **Scheduler vs Editor:** Ausfuehrung und Zeitplanung gehoeren zur **Scheduler-Saeule**; der Graph ist **Version**-gebunden (Draft vs Published).
|
||||
4. **Tool-Skalierung:** Flache Tool-Listen skalieren nicht; Toolbox + `requestToolbox` + connection-basierte Verfuegbarkeit sind das vorgesehene Gegenmittel (Ziel, nicht implementiert).
|
||||
5. **Zielmodell vs Ist:** `Workflow` / `WorkflowVersion` / `WorkflowRun` in der Spec sind **Zielarchitektur**. Ist-Modelle siehe oben (`Automation2Workflow`, `Automation2WorkflowRun` etc.). Abgleich 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.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
<!-- verifiedAgainst: gateway (codebase audit 2026-04-05) -->
|
||||
|
||||
|
|
@ -24,27 +24,20 @@ Ohne gültige, zahlungswirksame Subscription (soweit implementiert) sollen **nur
|
|||
- **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`)
|
||||
### Abrechnungsmodell
|
||||
|
||||
| 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.
|
||||
Im Gateway gibt es aktuell **kein `billingModel`-Feld** auf `BillingSettings`. Das operative Modell ist faktisch **PREPAY_MANDATE** (gemeinsames Mandantenkonto). Konzeptionell waren weitere Modelle (`PREPAY_USER`, `UNLIMITED`, `CREDIT_POSTPAY`) vorgesehen — diese sind im Code nicht implementiert.
|
||||
|
||||
### Kernentitäten
|
||||
|
||||
- **`BillingAccount`:** Guthaben (`balance` CHF), optional `userId` bei `PREPAY_USER`, `accountType` MANDATE | USER, `warningThreshold`, `enabled`.
|
||||
- **`BillingAccount`:** Guthaben (`balance` CHF), `mandateId`, optional `userId`, `warningThreshold`, `enabled`. Kein explizites `accountType`-Feld im Code — Mandant vs. User wird über Vorhandensein von `userId` unterschieden.
|
||||
- **`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).
|
||||
- **`BillingSettings`:** `warningThresholdPercent`, `notifyEmails`, `notifyOnWarning`, `stripeCustomerId` (Organisation = Mandant). Zusätzlich: `autoRechargeEnabled`, `rechargeAmountCHF`, `rechargeThresholdCHF` (Auto-Recharge) sowie Storage-Felder (`storageLimitGB`, `STORAGE_PRICE_PER_GB_CHF`).
|
||||
- **`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.
|
||||
- Verrechnung in **CHF**; zentraler Aufschlag via `calculatePriceWithMarkup()` in `mainServiceBilling.py` mit `BILLING_MARKUP_PERCENT = 400` (Multiplikator ×5 auf Provider-Kosten). **Achtung:** Code-Kommentare referenzieren inkonsistent „Faktor 2.0" und „50 %", die Konstante ist aktuell 400 %.
|
||||
|
||||
### Provider-Steuerung (RBAC)
|
||||
|
||||
|
|
@ -112,7 +105,9 @@ Referenz **Gateway-Audit** zu Prepaid-Beispielen: Trial **5 CHF**, Standard **10
|
|||
| **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).
|
||||
**AI-Gate (Code-Stand 2026-04-05):** Im Code ist `PAST_DUE` Teil der operativen Statusmenge (`OPERATIVE_STATUSES = ACTIVE, TRIALING, PAST_DUE`). `_checkSubscription` in `mainServiceBilling.py` gibt fuer alle drei Status `None` (erlaubt) zurueck. AI-Calls werden bei `PAST_DUE` **nicht blockiert**. Nur `EXPIRED`, `PENDING`, `SCHEDULED` und fehlende Subscription blockieren AI.
|
||||
|
||||
> Konzept vs. Code: Eine strengere Produktregel (PAST_DUE blockiert AI) war konzeptionell vorgesehen, ist aber aktuell nicht implementiert.
|
||||
|
||||
### Erlaubte Statusübergänge (Kernmenge)
|
||||
|
||||
|
|
@ -176,7 +171,7 @@ Typische Trigger: Stripe-Webhooks (`checkout.session.completed`, `invoice.paymen
|
|||
|
||||
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.
|
||||
3. **Pro Mandant** hoechstens eine operative Subscription; `ACTIVE`, `TRIALING` und `PAST_DUE` gelten als **operativ** (AI erlaubt). Nur `EXPIRED`, `PENDING`, `SCHEDULED` und fehlende Subscription blockieren AI.
|
||||
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`.
|
||||
|
|
|
|||
271
b-reference/platform/database-architecture.md
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
<!-- verifiedAgainst: gateway (codebase audit 2026-04-05) -->
|
||||
|
||||
# Datenbank-Architektur
|
||||
|
||||
## Ueberblick
|
||||
|
||||
PowerOn verwendet **PostgreSQL** mit einer klaren Trennung: jedes Modul (App, Chat, Billing, Knowledge, Features) hat eine eigene physische Datenbank (`poweron_*`). Datenbank-Zugriffe laufen ueber **Interfaces** (`interfaceDb*.py`), die auf dem zentralen **DatabaseConnector** (`connectorDbPostgre.py`) aufbauen. Datenbanken und Tabellen werden **automatisch** beim ersten Zugriff erzeugt -- kein manuelles Schema-Management noetig.
|
||||
|
||||
---
|
||||
|
||||
## Architektur-Stack
|
||||
|
||||
```
|
||||
Route / Service
|
||||
|
|
||||
v
|
||||
Interface (interfaceDb*.py)
|
||||
|-- XxxObjects Klasse
|
||||
|-- getInterface() Factory (cached)
|
||||
|-- setUserContext() -> RBAC-Anbindung
|
||||
|
|
||||
v
|
||||
DatabaseConnector (connectorDbPostgre.py)
|
||||
|-- Auto-Create Database
|
||||
|-- Auto-Create/Extend Tables (aus Pydantic-Modellen)
|
||||
|-- CRUD-Operationen (getRecordset, recordCreate, recordUpdate, recordDelete)
|
||||
|
|
||||
v
|
||||
PostgreSQL (+ pgvector Extension)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Datenbanken
|
||||
|
||||
### Inventar
|
||||
|
||||
| Datenbank | Modul / Zweck | Interface |
|
||||
|-----------|---------------|-----------|
|
||||
| `poweron_app` | Kernapplikation: UAM, Mandanten, Rollen, RBAC-Regeln, Navigation, Config | `interfaceDbApp.py` |
|
||||
| `poweron_chat` | Chat-Verlaeufe, Messages, Attachments | `interfaceDbChat.py` |
|
||||
| `poweron_management` | System-Management, Logs | `interfaceDbManagement.py` |
|
||||
| `poweron_knowledge` | RAG Knowledge-Store (mit pgvector) | `interfaceDbKnowledge.py` |
|
||||
| `poweron_billing` | Billing Accounts, Transactions, Usage | `interfaceDbBilling.py` |
|
||||
| `poweron_billing` | Subscriptions (gleiche DB wie Billing) | `interfaceDbSubscription.py` |
|
||||
| `poweron_workspace` | AI Workspace Feature-Daten | Feature-Interface |
|
||||
| `poweron_automation` | Automation v1 Workflows, Runs | Feature-Interface |
|
||||
| `poweron_automation2` | Automation v2 (Graph-Editor) Workflows, Runs | Feature-Interface |
|
||||
| `poweron_chatbot` | Chatbot Feature-Daten | Feature-Interface |
|
||||
| `poweron_trustee` | Trustee Feature-Daten | Feature-Interface |
|
||||
| `poweron_commcoach` | CommCoach Feature-Daten | Feature-Interface |
|
||||
| `poweron_neutralization` | Neutralisierungs-Daten | Feature-Interface |
|
||||
| `poweron_realestate` | RealEstate Feature-Daten | Feature-Interface |
|
||||
| `poweron_teamsbot` | Teams-Bot Feature-Daten | Feature-Interface |
|
||||
| `poweron_test` | Test-Datenbank | Nur in Tests |
|
||||
|
||||
### Namenskonvention
|
||||
|
||||
Feature-Datenbanken folgen dem Pattern `poweron_{featureCode.lower()}`. Der Datenbankname wird hart-codiert in der `_initializeDatabase()` Methode des jeweiligen Interfaces.
|
||||
|
||||
### Konfiguration
|
||||
|
||||
Verbindungsparameter kommen aus `APP_CONFIG` (config.ini / Environment):
|
||||
|
||||
| Key | Beschreibung |
|
||||
|-----|-------------|
|
||||
| `DB_HOST` | PostgreSQL Host |
|
||||
| `DB_PORT` | PostgreSQL Port |
|
||||
| `DB_USER` | Datenbank-Benutzer |
|
||||
| `DB_PASSWORD_SECRET` | Passwort (ggf. verschluesselt) |
|
||||
| `DB_DATABASE` | Default-DB-Name (Standard: `poweron_app`) |
|
||||
|
||||
---
|
||||
|
||||
## Interface-Pattern
|
||||
|
||||
Jedes Interface folgt einem einheitlichen Aufbau:
|
||||
|
||||
### XxxObjects Klasse
|
||||
|
||||
```python
|
||||
class AppObjects:
|
||||
db: DatabaseConnector # Connector zur eigenen DB
|
||||
rbac: RbacClass # RBAC-Integration
|
||||
currentUser: dict # Aktueller Benutzer
|
||||
mandateId: str # Aktueller Mandant
|
||||
featureInstanceId: str # (nur bei Feature-Interfaces)
|
||||
```
|
||||
|
||||
### _initializeDatabase()
|
||||
|
||||
Setzt den Datenbanknamen und erstellt den Connector:
|
||||
|
||||
```python
|
||||
def _initializeDatabase(self):
|
||||
dbDatabase = "poweron_app" # hart-codiert pro Interface
|
||||
self.db = DatabaseConnector(
|
||||
host=APP_CONFIG.get("DB_HOST"),
|
||||
database=dbDatabase,
|
||||
user=APP_CONFIG.get("DB_USER"),
|
||||
password=APP_CONFIG.get("DB_PASSWORD_SECRET"),
|
||||
port=APP_CONFIG.get("DB_PORT")
|
||||
)
|
||||
```
|
||||
|
||||
### setUserContext()
|
||||
|
||||
Bindet Benutzer und RBAC an die Instanz:
|
||||
|
||||
```python
|
||||
def setUserContext(self, currentUser, mandateId):
|
||||
self.currentUser = currentUser
|
||||
self.userId = currentUser["id"]
|
||||
self.mandateId = mandateId
|
||||
self.rbac = RbacClass(self.db, dbApp=dbApp)
|
||||
self.db.updateContext(self.userId)
|
||||
```
|
||||
|
||||
**RBAC-Besonderheit:** `poweron_app` ist Sonderfall (`dbApp=self.db`), weil RBAC-Regeln selbst in `poweron_app` liegen. Alle anderen Interfaces nutzen `getRootDbAppConnector()` um Rules aus der App-DB zu lesen:
|
||||
|
||||
```python
|
||||
dbApp = getRootDbAppConnector()
|
||||
self.rbac = RbacClass(self.db, dbApp=dbApp)
|
||||
```
|
||||
|
||||
### getInterface() Factory
|
||||
|
||||
Cached pro Kontext:
|
||||
|
||||
| Interface | Cache-Key | Ergebnis |
|
||||
|-----------|-----------|----------|
|
||||
| App | `{mandateId}_{userId}` | `AppObjects` |
|
||||
| Chat | `{mandateId}_{featureInstanceId}_{userId}` | `ChatObjects` |
|
||||
| Billing | `{userId}_{mandateId}` | `BillingObjects` |
|
||||
| Knowledge | `"default"` (Singleton) | `KnowledgeObjects` |
|
||||
|
||||
---
|
||||
|
||||
## DatabaseConnector
|
||||
|
||||
### Auto-Initialisierung
|
||||
|
||||
Beim Erstellen eines `DatabaseConnector` (`initDbSystem()`):
|
||||
|
||||
```
|
||||
1. _create_database_if_not_exists()
|
||||
-> Verbindet sich zu DB "postgres"
|
||||
-> Prueft pg_database auf Existenz
|
||||
-> CREATE DATABASE "{name}" falls fehlend
|
||||
|
||||
2. _create_tables()
|
||||
-> Erstellt nur die _system Registry-Tabelle
|
||||
-> Applikations-Tabellen werden lazy durch Interfaces erzeugt
|
||||
|
||||
3. _connect()
|
||||
-> psycopg2-Verbindung zur Ziel-DB
|
||||
|
||||
4. _initializeSystemTable()
|
||||
-> _ensureTableExists(SystemTable)
|
||||
```
|
||||
|
||||
### Lazy Table Creation
|
||||
|
||||
Tabellen werden **bei erstem Zugriff** automatisch aus Pydantic-Modellen erzeugt (`_ensureTableExists(model_class)`):
|
||||
|
||||
- **Tabellenname** = Python-Klassenname des Pydantic-Modells (z.B. `Role`, `AccessRule`, `UserMandate`)
|
||||
- **Spalten** werden aus Modellfeldern abgeleitet
|
||||
- **JSONB** fuer komplexe Typen (dict, list, Pydantic-Submodelle)
|
||||
- **vector** fuer pgvector-Felder (Knowledge-Store)
|
||||
- **Additive Migration**: Wenn die Tabelle existiert, werden fehlende Spalten automatisch hinzugefuegt. Bestehende Spalten werden **nicht** geaendert oder entfernt.
|
||||
|
||||
### Connector-Caching
|
||||
|
||||
```python
|
||||
_get_cached_connector(host, database, port)
|
||||
```
|
||||
|
||||
Wiederverwendet einen `DatabaseConnector` pro Datenbank-Identitaet (`host:database:port`). Genutzt von App, Management, Knowledge. Chat und Billing instanziieren direkt (kein Cache).
|
||||
|
||||
### userId Context
|
||||
|
||||
`userId` wird ueber eine `contextvar` am Connector gesetzt (`updateContext(userId)`). Damit werden System-Felder (`_createdBy`, `_updatedBy`) automatisch befuellt.
|
||||
|
||||
---
|
||||
|
||||
## RBAC-Integration in DB-Abfragen
|
||||
|
||||
Die RBAC-Schicht greift direkt in Datenbank-Abfragen ein:
|
||||
|
||||
### Kern-Funktionen in interfaceRbac.py
|
||||
|
||||
| Funktion | Zweck |
|
||||
|----------|-------|
|
||||
| `getRecordsetWithRBAC()` | Listet Datensaetze mit RBAC-Filter in SQL WHERE |
|
||||
| `buildRbacWhereClause()` | Uebersetzt Access Levels in SQL-Bedingungen |
|
||||
| `buildDataObjectKey()` | Baut Keys wie `data.uam.UserInDB` fuer Rule-Lookup |
|
||||
| `TABLE_NAMESPACE` | Mapping von Modellnamen zu logischen Namespaces |
|
||||
|
||||
### Namespace-Mapping
|
||||
|
||||
`TABLE_NAMESPACE` ordnet Pydantic-Modellnamen logischen Bereichen zu:
|
||||
|
||||
| Namespace | Modelle (Beispiele) |
|
||||
|-----------|-------------------|
|
||||
| `uam` | UserInDB, UserMandate, Role, AccessRule |
|
||||
| `chat` | ChatHistory, ChatMessage |
|
||||
| `files` | FileRecord, FileFolder |
|
||||
| `feature.trustee` | TrusteePosition, TrusteeDocument |
|
||||
| `feature.workspace` | Workspace-spezifische Modelle |
|
||||
|
||||
### SQL-Filter nach Access Level
|
||||
|
||||
| Level | SQL WHERE |
|
||||
|-------|-----------|
|
||||
| `a` (ALL) | Kein Filter |
|
||||
| `m` (MANDATE) | `mandateId = :mandateId` |
|
||||
| `o` (OWN) | `_createdBy = :userId` |
|
||||
| `n` (NONE) | `1=0` (kein Ergebnis) |
|
||||
|
||||
---
|
||||
|
||||
## System-Felder
|
||||
|
||||
Jedes `PowerOnModel` erbt automatisch System-Felder:
|
||||
|
||||
| Feld | Beschreibung | Schutz |
|
||||
|------|-------------|--------|
|
||||
| `id` | UUID, auto-generiert | Immutable |
|
||||
| `_createdBy` | userId des Erstellers | Immutable |
|
||||
| `_createdAt` | Zeitstempel Erstellung | Immutable |
|
||||
| `_updatedBy` | userId der letzten Aenderung | Auto-gesetzt |
|
||||
| `_updatedAt` | Zeitstempel letzte Aenderung | Auto-gesetzt |
|
||||
|
||||
Felder mit fuehrendem `_` sind fuer Anwendungs-CUD geschuetzt -- der Connector erzwingt das unabhaengig von Access Rules.
|
||||
|
||||
---
|
||||
|
||||
## Feature-DB-Registrierung
|
||||
|
||||
Features registrieren sich **nicht** in einer zentralen DB-Liste. Stattdessen:
|
||||
|
||||
1. `registry.py` → `registerAllFeaturesInCatalog()` laedt Feature-Main-Module
|
||||
2. Jedes Feature-Main definiert seinen `FEATURE_CODE` und `dbDatabase`
|
||||
3. Der Datenbank-Name wird in `_initializeDatabase()` des Feature-Interfaces gesetzt
|
||||
4. Der `DatabaseConnector` erzeugt die DB automatisch beim ersten Zugriff
|
||||
|
||||
### Admin-Sicht
|
||||
|
||||
`routeSecurityAdmin.py` bietet eine API, die alle `poweron_%`-Datenbanken aus PostgreSQL auflistet -- fuer Systemadministration und Diagnostik.
|
||||
|
||||
---
|
||||
|
||||
## Schluessel-Dateien
|
||||
|
||||
| Thema | Pfad |
|
||||
|-------|------|
|
||||
| PostgreSQL Connector | `gateway/modules/connectors/connectorDbPostgre.py` |
|
||||
| App-DB Interface | `gateway/modules/interfaces/interfaceDbApp.py` |
|
||||
| Chat-DB Interface | `gateway/modules/interfaces/interfaceDbChat.py` |
|
||||
| Management-DB Interface | `gateway/modules/interfaces/interfaceDbManagement.py` |
|
||||
| Knowledge-DB Interface | `gateway/modules/interfaces/interfaceDbKnowledge.py` |
|
||||
| Billing-DB Interface | `gateway/modules/interfaces/interfaceDbBilling.py` |
|
||||
| Subscription Interface | `gateway/modules/interfaces/interfaceDbSubscription.py` |
|
||||
| RBAC in DB-Schicht | `gateway/modules/interfaces/interfaceRbac.py` |
|
||||
| Feature-Interface (Template) | `gateway/modules/interfaces/interfaceFeatures.py` |
|
||||
| Bootstrap / DB-Seed | `gateway/modules/interfaces/interfaceBootstrap.py` |
|
||||
| DB-Migration Script | `gateway/scripts/script_db_export_migration.py` |
|
||||
| Admin DB-Listing | `gateway/modules/routes/routeSecurityAdmin.py` |
|
||||
| Datenmodelle (Pydantic) | `gateway/modules/datamodels/` |
|
||||
|
|
@ -168,7 +168,7 @@ This diagram shows the complete microservices structure, organized into Core Ser
|
|||
graph TB
|
||||
subgraph "Core Services"
|
||||
CHAT[self.services.chat<br/>Chat & Conversation]
|
||||
WF_SVC[self.services.workflow<br/>Workflow State]
|
||||
WF_SVC[self.services.workflow<br/>Runtime Workflow State<br/>not a registered service]
|
||||
UTILS[self.services.utils<br/>Utilities]
|
||||
end
|
||||
|
||||
|
|
@ -185,6 +185,14 @@ graph TB
|
|||
TICKET[self.services.ticket<br/>Jira, ClickUp, etc.]
|
||||
end
|
||||
|
||||
subgraph "Additional Services not shown"
|
||||
AGENT[self.services.agent]
|
||||
KNOWLEDGE[self.services.knowledge]
|
||||
MESSAGING[self.services.messaging]
|
||||
BILLING[self.services.billing]
|
||||
SUBSCRIPTION[self.services.subscription]
|
||||
end
|
||||
|
||||
subgraph "Security"
|
||||
SEC_SVC[self.services.security<br/>Auth, Authorization<br/>Token Management]
|
||||
end
|
||||
|
|
@ -415,7 +423,7 @@ graph TB
|
|||
|
||||
subgraph "Integration Points"
|
||||
WF_DIR[gateway/modules/workflows/methods/]
|
||||
SVC_DIR[gateway/modules/services/]
|
||||
SVC_DIR[gateway/modules/serviceCenter/services/]
|
||||
CONN_DIR[gateway/modules/connectors/]
|
||||
ROUTE_DIR[gateway/modules/routes/]
|
||||
FEAT_DIR[gateway/modules/features/]
|
||||
|
|
@ -481,4 +489,4 @@ graph TB
|
|||
|
||||
---
|
||||
|
||||
*Last updated: 2025*
|
||||
*Last updated: 2026-04-05 (audit: service paths, missing services, date corrected)*
|
||||
|
|
|
|||
|
|
@ -4,66 +4,334 @@
|
|||
|
||||
# RBAC-System
|
||||
|
||||
## Überblick
|
||||
## Ueberblick
|
||||
|
||||
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.
|
||||
Das Role-Based Access Control baut auf vier Stufen auf: **System**, **Mandant**, **Feature** und **Feature-Instanz**. Berechtigungen werden in **Access Rules** pro Rollenlabel und Kontext (DATA, UI, RESOURCE) gebunden. Auswertung erfolgt zentral ueber `interfaceRbac.py`; Zielbild: moeglichst **filternd in SQL** statt vollstaendiger Tabellen-Scans in Python. Nutzer koennen mehrere Rollenlabels gleichzeitig tragen; die effektive Berechtigung entsteht aus **Oeffnungslogik (Union)** ueber 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` |
|
||||
## 4-Stufen-Hierarchie
|
||||
|
||||
**Invariante:** Mandantenrollen und Feature-Instanz-Rollen **nicht vermischen** — kein Zuweisen eines Mandanten-Labels zu `FeatureAccessRole` oder umgekehrt.
|
||||
```
|
||||
System (PowerOn Platform)
|
||||
|
|
||||
+-- System Template Rollen (isSystemRole=true, mandateId=null, featureCode=null)
|
||||
| Labels: "admin", "user", "viewer"
|
||||
| -> kopiert bei Mandant-Erstellung via copySystemRolesToMandate()
|
||||
|
|
||||
+-- Feature Template Rollen (isSystemRole=false, mandateId=null, featureCode=X)
|
||||
| Labels: "workspace-admin", "workspace-user", "workspace-viewer",
|
||||
| "graphicalEditor-admin", "graphicalEditor-user", ...
|
||||
| -> kopiert bei Feature-Instanz-Erstellung via _copyTemplateRoles()
|
||||
|
|
||||
+-- Mandant (Tenant)
|
||||
+-- Mandate-Rollen (Instanzen der System Templates)
|
||||
| mandateId=X, featureInstanceId=null, featureCode=null
|
||||
| "admin", "user", "viewer"
|
||||
| Zuordnung: UserMandateRole <- UserMandate <- User
|
||||
|
|
||||
+-- Feature-Instanz A (z.B. "AI Workspace Produktion")
|
||||
| +-- Feature-Instanz-Rollen (Instanzen der Feature Templates)
|
||||
| | mandateId=X, featureInstanceId=Y, featureCode="workspace"
|
||||
| | "workspace-admin", "workspace-user", "workspace-viewer"
|
||||
| | Zuordnung: FeatureAccessRole <- FeatureAccess <- User
|
||||
| +-- Daten (Workflows, Files, Chats, ...)
|
||||
|
|
||||
+-- Feature-Instanz B (z.B. "Graphical Editor Dev")
|
||||
+-- Feature-Instanz-Rollen
|
||||
+-- Daten (Workflows, Runs, Tasks, ...)
|
||||
```
|
||||
|
||||
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.
|
||||
### Sonderfaelle
|
||||
|
||||
## Access Rules (DATA / UI / RESOURCE)
|
||||
- **SysAdmin**: Eine globale Rolle auf Root-Mandant-Ebene. Wird in `_initSysAdminRole()` beim Bootstrap angelegt -- keine Template-Kopie.
|
||||
- **SystemUser / EventUser**: Technische System-Accounts, nicht an echte Benutzer gebunden.
|
||||
|
||||
### 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`).
|
||||
## Zwei getrennte Template-Rollen-Systeme
|
||||
|
||||
### Spezifität (pro Rolle)
|
||||
Templates sind **Blaupausen**. Sie definieren welche Rollen und Berechtigungen ein neuer Mandant oder eine neue Feature-Instanz erhaelt. Die beiden Template-Systeme sind **vollstaendig getrennt** -- kein Kreuz-Zuweisen.
|
||||
|
||||
Innerhalb **einer** Rolle gewinnt die **spezifischste** passende Regel (längster passender Präfix/exakter `item`) gegenüber generischen Regeln (`item = null`).
|
||||
### System Template Rollen (fuer Mandanten)
|
||||
|
||||
### Mehrere Rollen
|
||||
| Feld | Wert |
|
||||
|------|------|
|
||||
| `isSystemRole` | `true` |
|
||||
| `mandateId` | `null` |
|
||||
| `featureInstanceId` | `null` |
|
||||
| `featureCode` | `null` |
|
||||
| `roleLabel` | `"admin"`, `"user"`, `"viewer"` |
|
||||
| Definiert in | `interfaceBootstrap.py` → `initRoles()` (Zeilen ~473-540) |
|
||||
| Kopier-Mechanismus | `copySystemRolesToMandate()` in `interfaceBootstrap.py` |
|
||||
| Ausgeloest bei | Mandant-Erstellung (`createMandate()`, `_provisionMandateForUser()`) |
|
||||
| Bootstrap-Sync | `_ensureAllMandatesHaveSystemRoles()` beim Startup |
|
||||
|
||||
Ü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.
|
||||
### Feature Template Rollen (fuer Feature-Instanzen)
|
||||
|
||||
### DATA: Öffnungsrechte (CUD vs. Read)
|
||||
| Feld | Wert |
|
||||
|------|------|
|
||||
| `isSystemRole` | `false` |
|
||||
| `mandateId` | `null` |
|
||||
| `featureInstanceId` | `null` |
|
||||
| `featureCode` | z.B. `"workspace"`, `"automation2"`, `"trustee"` |
|
||||
| `roleLabel` | z.B. `"workspace-admin"`, `"workspace-user"` |
|
||||
| Definiert in | `TEMPLATE_ROLES` in jedem Feature-Main (z.B. `mainWorkspace.py` Zeilen ~83-135) |
|
||||
| Sync in DB | `_syncTemplateRolesToDb()` bei `registerFeature()` |
|
||||
| Kopier-Mechanismus | `_copyTemplateRoles()` in `interfaceFeatures.py` (Zeilen ~209-304) |
|
||||
| Ausgeloest bei | Feature-Instanz-Erstellung (`createFeatureInstance(copyTemplateRoles=True)`) |
|
||||
|
||||
- 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.
|
||||
### TEMPLATE_ROLES Format (Beispiel Workspace)
|
||||
|
||||
### Systemfelder (DATA)
|
||||
```python
|
||||
TEMPLATE_ROLES = [
|
||||
{
|
||||
"roleLabel": "workspace-admin",
|
||||
"description": {"en": "Workspace Administrator", "de": "Workspace-Administrator"},
|
||||
"accessRules": [
|
||||
{"context": "UI", "item": "ui.feature.workspace", "view": True},
|
||||
{"context": "RESOURCE", "item": "resource.feature.workspace", "view": True},
|
||||
{"context": "DATA", "item": None, "read": "a", "create": "a", "update": "a", "delete": "a", "view": True}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roleLabel": "workspace-user",
|
||||
"description": {"en": "Workspace User", "de": "Workspace-Benutzer"},
|
||||
"accessRules": [
|
||||
{"context": "UI", "item": "ui.feature.workspace", "view": True},
|
||||
{"context": "RESOURCE", "item": "resource.feature.workspace", "view": True},
|
||||
{"context": "DATA", "item": None, "read": "m", "create": "m", "update": "m", "delete": "m", "view": True}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Felder `id` und Namen mit führendem `_` sind für Anwendungs-CUD geschützt; Connector erzwingt das unabhängig von Access Rules.
|
||||
### Kopier-Invariante
|
||||
|
||||
### Frontend-Optionen für Rollen
|
||||
Templates werden **nur bei Erstellung** kopiert. Spaetere Aenderungen an Templates werden **nicht** automatisch an bestehende Mandanten oder Feature-Instanzen propagiert. Fuer nachtraeglichen Sync existiert `syncRolesFromTemplate()` in `interfaceFeatures.py` -- aber dies muss explizit aufgerufen werden.
|
||||
|
||||
`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/frontendTypes.py`.
|
||||
---
|
||||
|
||||
## Schlüssel-Dateien
|
||||
## Datenmodell
|
||||
|
||||
| Rolle | Pfad |
|
||||
### Role
|
||||
|
||||
```python
|
||||
class Role(PowerOnModel):
|
||||
id: str # UUID, auto-generiert
|
||||
mandateId: Optional[str] # null = Global/Template
|
||||
featureInstanceId: Optional[str] # null = nicht Instanz-spezifisch
|
||||
featureCode: Optional[str] # z.B. "workspace", "graphicalEditor"
|
||||
roleLabel: str # z.B. "workspace-admin"
|
||||
description: TextMultilingual # {"en": "...", "de": "..."}
|
||||
isSystemRole: bool # true nur fuer System Template Rollen
|
||||
```
|
||||
|
||||
**Immutable nach Erstellung:** `mandateId`, `featureInstanceId`, `featureCode` (erzwungen in `datamodelRbac.py`).
|
||||
|
||||
### AccessRule
|
||||
|
||||
```python
|
||||
class AccessRule(PowerOnModel):
|
||||
id: str
|
||||
roleId: str # FK -> Role
|
||||
context: AccessRuleContext # DATA | UI | RESOURCE
|
||||
item: Optional[str] # null = generic, oder spezifischer Key
|
||||
view: bool
|
||||
read: Optional[AccessLevel] # nur bei DATA relevant
|
||||
create: Optional[AccessLevel]
|
||||
update: Optional[AccessLevel]
|
||||
delete: Optional[AccessLevel]
|
||||
```
|
||||
|
||||
### AccessLevel
|
||||
|
||||
```python
|
||||
class AccessLevel(str, Enum):
|
||||
NONE = "n" # Kein Zugriff
|
||||
OWN = "o" # Nur eigene Datensaetze (userId-Match)
|
||||
MANDATE = "m" # Alle im gleichen Mandanten
|
||||
ALL = "a" # Alle (mandantenuebergreifend, nur SysAdmin)
|
||||
```
|
||||
|
||||
### Membership-Modelle
|
||||
|
||||
```python
|
||||
class UserMandate(PowerOnModel):
|
||||
userId: str
|
||||
mandateId: str
|
||||
enabled: bool
|
||||
|
||||
class UserMandateRole(PowerOnModel):
|
||||
userMandateId: str # FK -> UserMandate
|
||||
roleId: str # FK -> Role (Mandate-Rolle)
|
||||
|
||||
class FeatureAccess(PowerOnModel):
|
||||
userId: str
|
||||
featureInstanceId: str
|
||||
enabled: bool
|
||||
|
||||
class FeatureAccessRole(PowerOnModel):
|
||||
featureAccessId: str # FK -> FeatureAccess
|
||||
roleId: str # FK -> Role (Feature-Instanz-Rolle)
|
||||
```
|
||||
|
||||
### ER-Diagramm (Vereinfacht)
|
||||
|
||||
```
|
||||
User
|
||||
|
|
||||
+-- UserMandate (1:N)
|
||||
| |
|
||||
| +-- UserMandateRole (1:N) ---> Role (mandateId=X)
|
||||
| |
|
||||
| +-- AccessRule (1:N)
|
||||
|
|
||||
+-- FeatureAccess (1:N)
|
||||
|
|
||||
+-- FeatureAccessRole (1:N) ---> Role (featureInstanceId=Y)
|
||||
|
|
||||
+-- AccessRule (1:N)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Access-Rule-Kontexte
|
||||
|
||||
### DATA
|
||||
|
||||
Steuert CRUD-Berechtigungen auf Datenbank-Ebene.
|
||||
|
||||
- **Item-Format**: Auto-generiert aus Tabellenname + Namespace (z.B. `data.uam.UserInDB`, `data.feature.trustee.TrusteePosition`)
|
||||
- **Prueft**: `read`, `create`, `update`, `delete` als Access Levels
|
||||
- **`view`**: Boolean, steuert Grundsichtbarkeit
|
||||
- **Mapping**: `TABLE_NAMESPACE` in `interfaceRbac.py` ordnet Modellnamen logischen Namespaces zu
|
||||
- **`buildDataObjectKey()`**: Baut Keys wie `data.{namespace}.{ModelName}` oder `data.feature.{featureCode}.{ModelName}`
|
||||
|
||||
### UI
|
||||
|
||||
Steuert Sichtbarkeit und Aktivierung von Oberflaechenelementen.
|
||||
|
||||
- **Item-Format**: Kaskadierende Strings (z.B. `playground.voice.settings`, `ui.feature.workspace.editor`)
|
||||
- **Prueft**: Nur `view` (Boolean)
|
||||
- **Verwendung**: Navigation, Seitenleiste, Buttons, Tabs
|
||||
|
||||
### RESOURCE
|
||||
|
||||
Steuert Zugriff auf Systemressourcen.
|
||||
|
||||
- **Item-Format**: Kaskadierende Strings (z.B. `ai.model.anthropic`, `resource.feature.workspace.execute`)
|
||||
- **Prueft**: Primaer `view` (Boolean)
|
||||
- **Verwendung**: KI-Modelle, Aktionen, Features
|
||||
|
||||
---
|
||||
|
||||
## Resolution-Algorithmus
|
||||
|
||||
### Priority-System
|
||||
|
||||
| Rollen-Typ | Scope | Priority |
|
||||
|------------|-------|----------|
|
||||
| **Global/Template** | `mandateId=null, featureInstanceId=null` | 1 (niedrigste) |
|
||||
| **Mandate-Rolle** | `mandateId=X, featureInstanceId=null` | 2 |
|
||||
| **Feature-Instanz-Rolle** | `mandateId=X, featureInstanceId=Y` | 3 (hoechste) |
|
||||
|
||||
### Resolution-Ablauf
|
||||
|
||||
1. **Rollen laden**: Mandate-Rollen via `UserMandate` → `UserMandateRole`; Feature-Rollen via `FeatureAccess` → `FeatureAccessRole` (`getRulesForUserBulk()` in `rbac.py`)
|
||||
2. **AccessRules laden** fuer alle gefundenen Rollen
|
||||
3. **Gruppierung** nach Priority-Stufe
|
||||
4. **Hoechste Prioritaet gewinnt** bei DATA-Permissions
|
||||
5. **View wird OR-verknuepft** ueber alle Rollen der hoechsten Prioritaetsstufe
|
||||
6. **Item-Spezifitaet** innerhalb einer Stufe: exact > prefix > generic (laengster passender Praefix gewinnt)
|
||||
|
||||
### DATA: Oeffnungsrechte (CUD vs. Read)
|
||||
|
||||
| Read-Level | Maximales CUD |
|
||||
|------------|---------------|
|
||||
| `n` (NONE) | Kein CUD moeglich |
|
||||
| `o` (OWN) | CUD hoechstens `o` oder `n` |
|
||||
| `m` (MANDATE) | CUD hoechstens `m`, `o` oder `n` |
|
||||
| `a` (ALL) | Alle Stufen fuer CUD zulaessig |
|
||||
|
||||
### Mehrere Rollen (Union-Logik)
|
||||
|
||||
Ueber Rollen hinweg gilt **Union** (OR): wenn eine Rolle nach interner Aufloesung `view: true` liefert, gilt das Element als sichtbar/erlaubt. Fuer DATA werden die **freizuegigsten** Stufen ueber Rollen kombiniert.
|
||||
|
||||
### SQL-Integration
|
||||
|
||||
`buildRbacWhereClause()` in `interfaceRbac.py` uebersetzt die aufgeloesten Access Levels in SQL-WHERE-Bedingungen:
|
||||
- `a`: Kein Filter
|
||||
- `m`: `WHERE mandateId = :mandateId`
|
||||
- `o`: `WHERE _createdBy = :userId`
|
||||
- `n`: `WHERE 1=0` (kein Zugriff)
|
||||
|
||||
RBAC-gefilterte Abfragen laufen ueber `getRecordsetWithRBAC()`.
|
||||
|
||||
---
|
||||
|
||||
## Bootstrap-Ablauf
|
||||
|
||||
Beim Gateway-Start (`initBootstrap()` in `interfaceBootstrap.py`):
|
||||
|
||||
```
|
||||
1. initRootMandate() -- Root-Mandant sicherstellen
|
||||
2. _deduplicateRoles() -- Duplikate bereinigen, isSystemRole-Flags fixen
|
||||
3. initRoles() -- System Template Rollen (admin/user/viewer) anlegen
|
||||
4. initRbacRules() -- Default AccessRules auf Template-Rollen
|
||||
5. _ensureAllMandatesHaveSystemRoles()
|
||||
-- copySystemRolesToMandate() fuer jeden Mandanten
|
||||
6. _initSysAdminRole() -- SysAdmin-Rolle auf Root-Mandant
|
||||
7. _ensureUiContextRules() -- UI-Kontext-Regeln pruefen
|
||||
8. Admin/Event-User sichern
|
||||
9. assignInitialUserMemberships()
|
||||
-- UserMandate + UserMandateRole fuer Admin/SysAdmin
|
||||
```
|
||||
|
||||
Danach bei Feature-Registrierung (`registerAllFeaturesInCatalog()` → `registerFeature()`):
|
||||
|
||||
```
|
||||
10. _syncTemplateRolesToDb() -- Feature Template Rollen upserten
|
||||
-- AccessRules fuer Templates synchronisieren
|
||||
```
|
||||
|
||||
Bei Laufzeit:
|
||||
|
||||
```
|
||||
- createMandate() -- copySystemRolesToMandate() fuer neuen Mandanten
|
||||
- createFeatureInstance() -- _copyTemplateRoles() fuer neue Feature-Instanz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Systemfelder (DATA)
|
||||
|
||||
Felder `id` und Namen mit fuehrendem `_` (z.B. `_createdBy`, `_createdAt`) sind fuer Anwendungs-CUD geschuetzt. Der Connector erzwingt das unabhaengig von Access Rules.
|
||||
|
||||
## Frontend-Optionen fuer Rollen
|
||||
|
||||
`frontend_options` an Feldern kann statische Listen oder String-Referenzen (z.B. `"user.role"`) nutzen. Dynamische Optionen ueber `/api/options/{optionsName}`. Typ-Hilfen: `gateway/modules/shared/frontendTypes.py`.
|
||||
|
||||
---
|
||||
|
||||
## Schluessel-Dateien
|
||||
|
||||
| Thema | 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/z-archive/appdoc/doc_security_role_based_access.md` |
|
||||
| RBAC-Auswertung, SQL-Integration | `gateway/modules/interfaces/interfaceRbac.py` |
|
||||
| AccessRule/Permission-Modelle | `gateway/modules/datamodels/datamodelRbac.py` |
|
||||
| Membership-Modelle | `gateway/modules/datamodels/datamodelMembership.py` |
|
||||
| Bootstrap (System Templates, Copy) | `gateway/modules/interfaces/interfaceBootstrap.py` |
|
||||
| Feature-Template-Copy | `gateway/modules/interfaces/interfaceFeatures.py` |
|
||||
| Feature-Registrierung | `gateway/modules/system/registry.py` |
|
||||
| RBAC-Rule-Resolution | `gateway/modules/security/rbac.py` |
|
||||
| TEMPLATE_ROLES (Beispiel) | `gateway/modules/features/workspace/mainWorkspace.py` |
|
||||
|
||||
## 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.
|
||||
- Mandanten-Rollen und Feature-Instanz-Rollen **strikt trennen** (keine Kreuz-Zuweisung der Label-Typen)
|
||||
- Templates werden nur bei Erstellung kopiert -- keine automatische Propagierung
|
||||
- **Spezifisch vor generisch** innerhalb einer Rolle; **Union** ueber Rollen
|
||||
- UI/RESOURCE: Sichtbar nur wenn `view: true`; nicht berechtigte UI-Eintraege werden gar nicht geliefert
|
||||
- DATA: CUD darf nicht ueber dem jeweiligen Read-Level liegen
|
||||
- Performance-Ziel: DATA-Zugriffe mit RBAC-Filter in SQL
|
||||
|
|
|
|||
|
|
@ -1,361 +1,83 @@
|
|||
# Refactoring Concept: Add WEB_SEARCH_MEDIA Operation Type
|
||||
<!-- status: plan -->
|
||||
<!-- started: 2026-03-01 -->
|
||||
<!-- component: gateway -->
|
||||
|
||||
## Executive Summary
|
||||
# Web Image Search -- WEB_SEARCH_MEDIA Operation Type
|
||||
|
||||
**Refactoring Goal**: Add image search capability by introducing `WEB_SEARCH_MEDIA` operation type and Google Custom Search connector.
|
||||
## Beschreibung und Kontext
|
||||
|
||||
**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
|
||||
PowerOn unterstützt Web-Suche über den Tavily-Connector (`WEB_SEARCH_DATA`). Es fehlt eine dedizierte Bildersuche. Ziel ist ein neuer OperationType `WEB_SEARCH_MEDIA` mit Google Custom Search Connector, damit der AI Agent Bilder suchen und als ActionDocuments zurückgeben kann.
|
||||
|
||||
**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`
|
||||
**Business-Treiber:** Mandanten benötigen Bildmaterial (z.B. für Immobilien-Exposés, Marketing-Content) direkt im AI Workspace.
|
||||
|
||||
**Estimated Complexity**: Medium (1-2 days development)
|
||||
**Risiko bei Nicht-Umsetzung:** Manuelle Bildersuche ausserhalb der Plattform, kein automatisierter Image-Workflow.
|
||||
|
||||
**Integration Impact**: Low - additive changes, no breaking changes
|
||||
## Fokus und kritische Details
|
||||
|
||||
---
|
||||
- Google Custom Search API erfordert API Key + Search Engine ID mit aktivierter Image Search
|
||||
- Model-Selection muss `WEB_SEARCH_MEDIA` korrekt zum Google-Connector routen
|
||||
- Rückgabeformat: JSON-Array mit Image-URLs, konsistent mit Tavily-Format
|
||||
- Rate Limiting der Google API (100 queries/Tag im Free Tier)
|
||||
|
||||
## 1. Current Architecture
|
||||
## Ziel und Nicht-Ziele
|
||||
|
||||
### 1.1 Operation Types
|
||||
- **Ziel:** `WEB_SEARCH_MEDIA` OperationType in `OperationTypeEnum`
|
||||
- **Ziel:** Google Custom Search Connector (`aicorePluginGoogle.py`)
|
||||
- **Ziel:** `AiCallPromptWebSearchMedia` Pydantic Model
|
||||
- **Ziel:** `ai.searchImages` Action in `methodAi`
|
||||
- **Explizit NICHT:** Video-Suche, Tavily-Erweiterung, SharePoint-Integration
|
||||
|
||||
**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
|
||||
```
|
||||
## Betroffene Module
|
||||
|
||||
**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
|
||||
```
|
||||
- Gateway: `modules/datamodels/datamodelAi.py`, `modules/aicore/aicorePluginGoogle.py` (NEU), `modules/services/serviceAi/mainServiceAi.py`, `modules/workflows/methods/methodAi/`
|
||||
- Frontend: keine (Agent nutzt Action intern)
|
||||
- DB-Migration: nein
|
||||
- Andere: Google Cloud Console Setup (API Key)
|
||||
|
||||
### 1.2 Model Capabilities
|
||||
## Entscheidungen
|
||||
|
||||
**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
|
||||
| Datum | Entscheidung | Begründung |
|
||||
|-------|-------------|------------|
|
||||
| 2026-03-01 | Google Custom Search statt Tavily | Tavily unterstützt keine Bildersuche |
|
||||
| 2026-03-01 | Eigener Connector statt Tavily-Erweiterung | Saubere Trennung, unabhängige Skalierung |
|
||||
|
||||
**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
|
||||
## Umsetzungs-Checkliste
|
||||
|
||||
---
|
||||
- [ ] `WEB_SEARCH_MEDIA` in `OperationTypeEnum` hinzufügen
|
||||
- [ ] `AiCallPromptWebSearchMedia` Model erstellen
|
||||
- [ ] `aicorePluginGoogle.py` Connector implementieren
|
||||
- [ ] Connector in Discovery registrieren
|
||||
- [ ] `mainServiceAi.py` für `WEB_SEARCH_MEDIA` erweitern
|
||||
- [ ] `searchImages` Action erstellen
|
||||
- [ ] Action in `methodAi.py` registrieren
|
||||
- [ ] RBAC / Permissions: nicht betroffen (nutzt bestehende AI-Berechtigung)
|
||||
- [ ] Neutralisierung betroffen? nein
|
||||
- [ ] Navigation / Routing: nicht betroffen
|
||||
- [ ] Billing-Impact? prüfen (API-Kosten pro Query)
|
||||
|
||||
## 2. Refactoring Plan
|
||||
## Akzeptanzkriterien
|
||||
|
||||
### 2.1 Add WEB_SEARCH_MEDIA Operation Type
|
||||
| # | Kriterium (Given-When-Then) | Prio |
|
||||
|---|---------------------------|------|
|
||||
| 1 | Given ein AI Agent mit `searchImages` Tool, When der User "Suche Bilder von Zürich" eingibt, Then gibt der Agent eine Liste von Bild-URLs zurück | must |
|
||||
| 2 | Given kein Google API Key konfiguriert, When `WEB_SEARCH_MEDIA` aufgerufen wird, Then wird ein klarer Fehler zurückgegeben | must |
|
||||
| 3 | Given `maxResults=5` und `imageType=photo`, When die Suche ausgeführt wird, Then werden max. 5 Fotos zurückgegeben | should |
|
||||
|
||||
**File**: `gateway/modules/datamodels/datamodelAi.py`
|
||||
## Testplan
|
||||
|
||||
**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
|
||||
```
|
||||
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|
||||
|----|----|-----|--------------|-----------|--------|
|
||||
| T1 | 1 | integration | ja | gateway/tests/test_google_connector.py | pending |
|
||||
| T2 | 2 | unit | ja | gateway/tests/test_google_connector.py | pending |
|
||||
| T3 | 3 | api | ja | gateway/tests/test_search_images_action.py | pending |
|
||||
|
||||
### 2.2 Create AiCallPromptWebSearchMedia Model
|
||||
## Links
|
||||
|
||||
**File**: `gateway/modules/datamodels/datamodelAi.py`
|
||||
- Google Custom Search API: https://developers.google.com/custom-search/v1/overview
|
||||
- Bestehender Tavily Connector: `gateway/modules/aicore/aicorePluginTavily.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)")
|
||||
```
|
||||
## Abschluss
|
||||
|
||||
### 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
|
||||
- [ ] b-reference/gateway/ai-agent.md aktualisiert (neuer OperationType)
|
||||
- [ ] TOPICS.md aktualisiert (falls neues Thema)
|
||||
- [ ] Dieses Dokument → z-archive/ verschoben
|
||||
|
|
|
|||
1067
c-work/1-plan/2026-04-automation-unification.md
Normal file
|
|
@ -5,16 +5,61 @@
|
|||
|
||||
## Naming
|
||||
|
||||
- Alle internen Funktionen beginnen mit `_` Prefix
|
||||
- camelCase für Variablen und Funktionsnamen (kein snake_case)
|
||||
- Alle internen Funktionen beginnen mit `_` Prefix (nicht exportierbar)
|
||||
- **camelCase** fuer Variablen und Funktionsnamen (kein snake_case)
|
||||
- **PascalCase** fuer Klassen und Pydantic-Models
|
||||
- Dateien: `camelCase` fuer Module (z.B. `mainServiceAi.py`, `routeBilling.py`)
|
||||
|
||||
## Frontend-Regeln
|
||||
|
||||
- Keine Browser-Dialoge (alert/confirm/prompt) -- stattdessen `useConfirm()` und `usePrompt()` Hooks
|
||||
- CSS Modules für Komponenten-Styles
|
||||
|
||||
## Backend-Regeln
|
||||
## Frontend (React/TypeScript)
|
||||
|
||||
- Keine Browser-Dialoge (`alert`, `confirm`, `prompt`) -- stattdessen `useConfirm()` / `usePrompt()` Hooks
|
||||
- CSS Modules fuer Styling
|
||||
- Hooks-Pattern fuer State und API-Zugriffe (`useApiRequest`, `useBilling`, etc.)
|
||||
- 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`
|
||||
|
||||
## Backend (FastAPI/Python)
|
||||
|
||||
- **Pydantic-Models** als einzige Quelle fuer UI-Feld-Definitionen
|
||||
- **`PowerOnModel`** als Basis mit System-Audit-Feldern (`sysCreatedAt`, `sysCreatedBy`, `sysModifiedAt`, `sysModifiedBy`)
|
||||
- Fehler propagieren -- Exceptions explizit werfen, nicht schlucken
|
||||
- Config ueber `APP_CONFIG` (aus `modules/shared/configuration.py`)
|
||||
|
||||
## Projektstruktur Gateway
|
||||
|
||||
```
|
||||
gateway/
|
||||
app.py # FastAPI-App, Middleware, Startup
|
||||
config.ini # Statische Konfiguration
|
||||
modules/
|
||||
auth/ # JWT, OAuth, CSRF, Authentication
|
||||
datamodels/ # Pydantic-Models (zentrale Quelle)
|
||||
features/ # Feature-Module (workspace, automation, ...)
|
||||
<name>/
|
||||
main<Name>.py # FEATURE_CODE, Registrierung
|
||||
routeFeature<Name>.py # HTTP-Endpunkte
|
||||
interfaceFeature<Name>.py # DB-Interface
|
||||
datamodelFeature<Name>.py # Feature-spezifische Models
|
||||
interfaces/ # DB-Interfaces (CRUD, Queries)
|
||||
routes/ # Core-Routes (billing, admin, GDPR, ...)
|
||||
security/ # RBAC-Engine
|
||||
serviceCenter/
|
||||
core/ # serviceSecurity, serviceUtils, serviceStreaming
|
||||
services/ # serviceAi, serviceChat, serviceAgent, ...
|
||||
registry.py # Service-Registrierung und Dependencies
|
||||
shared/ # configuration.py, Utilities
|
||||
system/ # registry.py (Feature-Discovery)
|
||||
workflows/
|
||||
methods/ # Unified Action Library
|
||||
processing/ # WorkflowProcessor, Modes
|
||||
automation/ # v1 Runtime
|
||||
automation2/ # v2 Engine
|
||||
connectors/ # Externe Systeme (DB, SharePoint, Jira, ...)
|
||||
aicore/ # AI-Provider-Plugins, Model-Selector
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Keine impliziten Type-Conversions in API-Responses
|
||||
- Keine DB-Queries in Route-Handlern (immer ueber Interfaces)
|
||||
- Kein direkter `os.environ`-Zugriff -- immer `APP_CONFIG`
|
||||
- Keine hartkodierten Secrets -- verschluesselt in Env-Dateien
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
|
@ -1,25 +1,85 @@
|
|||
<!-- status: draft -->
|
||||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
|
||||
# Dev-Setup
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Python (Anaconda/Miniconda)
|
||||
- Node.js
|
||||
- PostgreSQL mit pgvector
|
||||
- **Python 3.11** (CI-Standard; Minimum 3.10)
|
||||
- **Node.js** (aktuelles LTS empfohlen)
|
||||
- **PostgreSQL** mit **pgvector**-Extension
|
||||
- **Conda** oder **venv** fuer Python-Umgebung
|
||||
|
||||
## Gateway starten
|
||||
|
||||
```bash
|
||||
conda activate <env>
|
||||
cd gateway/
|
||||
# Python-Umgebung aktivieren (Conda oder venv)
|
||||
conda activate <env>
|
||||
# oder: python -m venv .venv && .\.venv\Scripts\Activate.ps1
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Config vorbereiten:
|
||||
# 1. config.ini muss im gateway/ Verzeichnis liegen (statische Settings)
|
||||
# 2. .env Datei aus env_dev.env kopieren/symlinken:
|
||||
# copy env_dev.env .env
|
||||
# 3. APP_KEY_SYSVAR in config.ini zeigt auf Master-Key (OS-Variable oder Dateipfad)
|
||||
|
||||
uvicorn app:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### Konfigurationsdateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|-------|-------|
|
||||
| `gateway/config.ini` | Statische Settings (Auth-Defaults, Upload-Limits, Operator-Text) |
|
||||
| `gateway/.env` | Runtime-Env (DB, API-Keys, Secrets) -- wird aus `env_dev.env` kopiert |
|
||||
| `gateway/env_dev.env` | Dev-Umgebung Template (verschluesselte Secrets mit `DEV_ENC:` Prefix) |
|
||||
| `gateway/env_int.env` | Integration-Umgebung |
|
||||
| `gateway/env_prod.env` | Produktion |
|
||||
|
||||
### Wichtige Env-Variablen (Auszug)
|
||||
|
||||
| Variable | Beschreibung |
|
||||
|----------|-------------|
|
||||
| `DB_HOST`, `DB_USER`, `DB_PASSWORD_SECRET` | PostgreSQL-Verbindung |
|
||||
| `APP_KEY_SYSVAR` | Master-Key fuer Secrets-Entschluesselung |
|
||||
| `APP_API_URL` | API-URL (bestimmt Cookie-Secure-Flag) |
|
||||
| `APP_ALLOWED_ORIGINS` | CORS Origins (inkl. `http://localhost:5176`) |
|
||||
| `Service_GOOGLE_AUTH_*` | Google OAuth Auth-App |
|
||||
| `Service_GOOGLE_DATA_*` | Google OAuth Data-App |
|
||||
|
||||
## Frontend Nyla starten
|
||||
|
||||
```bash
|
||||
cd frontend_nyla/
|
||||
npx vite --port 8080 --mode dev
|
||||
npm install
|
||||
npm run dev
|
||||
# oder: npx vite --port 5176 --mode dev
|
||||
```
|
||||
|
||||
Frontend laeuft auf **http://localhost:5176** und erwartet Gateway auf **http://localhost:8000**.
|
||||
|
||||
### Frontend-Konfiguration
|
||||
|
||||
| Datei | Zweck |
|
||||
|-------|-------|
|
||||
| `frontend_nyla/config/.env.dev` | Dev-Mode Env (VITE_API_BASE_URL etc.) |
|
||||
| `frontend_nyla/config/.env.int` | Integration |
|
||||
| `frontend_nyla/config/.env.prod` | Produktion |
|
||||
|
||||
## Secrets-Verwaltung
|
||||
|
||||
Env-Dateien enthalten verschluesselte Werte (`DEV_ENC:`, `INT_ENC:`, `PROD_ENC:`).
|
||||
Zur Entschluesselung wird der Master-Key ueber `APP_KEY_SYSVAR` geladen.
|
||||
|
||||
Details: -> `d-guides/encrypt-env-secrets.md`
|
||||
|
||||
## Weiterführende Guides
|
||||
|
||||
- Secrets verschluesseln: `d-guides/encrypt-env-secrets.md`
|
||||
- Google OAuth einrichten: `d-guides/google-oauth-setup.md`
|
||||
- Cookie/JWT-Migration: `d-guides/security-migration-guide.md`
|
||||
- Coding-Konventionen: `d-guides/coding-conventions.md`
|
||||
- Testing: `d-guides/testing-strategy.md`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
### Admin-Leitfaden: *_SECRET-Werte in Env-Dateien verschlüsseln
|
||||
|
||||
Diese Anleitung beschreibt, wie das PowerOn-Gateway-Tool `tool_security_encrypt_all_env_files.py` alle unverschlüsselten `*_SECRET`-Variablen in `env_dev.env`, `env_int.env` und `env_prod.env` verschlüsselt.
|
||||
Diese Anleitung beschreibt, wie das PowerOn-Gateway-Tool `scripts/script_security_encrypt_all_env_files.py` alle unverschlüsselten `*_SECRET`-Variablen in `env_dev.env`, `env_int.env` und `env_prod.env` verschlüsselt.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ Das Tool kann in jedem Repository eingesetzt werden, sofern die untenstehenden V
|
|||
- Die zu verarbeitenden Env-Dateien: `env_dev.env`, `env_int.env`, `env_prod.env` (oder eine Teilmenge via `--files`).
|
||||
- **Rechte**: Schreibrechte auf die Env-Dateien, Leserechte auf die Masterkey-Quelle (siehe Punkt 2).
|
||||
|
||||
Hinweis: Das Tool importiert `encrypt_value` aus `modules/shared/configuration.py`. Stellen Sie sicher, dass dieser Pfad importierbar ist (Start im Gateway-Verzeichnis oder `PYTHONPATH` setzen).
|
||||
Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py`. Stellen Sie sicher, dass dieser Pfad importierbar ist (Start im Gateway-Verzeichnis oder `PYTHONPATH` setzen). Das Script fuegt `gateway` automatisch zu `sys.path` hinzu.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -25,12 +25,12 @@ Hinweis: Das Tool importiert `encrypt_value` aus `modules/shared/configuration.p
|
|||
|
||||
1. `requirements.txt` im Projekt (Minimalbeispiel):
|
||||
```
|
||||
cryptography>=42.0.0
|
||||
cryptography>=41.0.0
|
||||
```
|
||||
Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `gateway/requirements.txt`.
|
||||
|
||||
2. Notwendige Gateway-Komponenten (sofern außerhalb von `gateway` verwendet):
|
||||
- `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_get_master_key`, `encrypt_value`, `decrypt_value`)
|
||||
- `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_getMasterKey`, `encryptValue`, `decryptValue`)
|
||||
- Optional, aber unterstützt: `modules/shared/auditLogger.py` (Audit-Events; Ausfall ist toleriert)
|
||||
- `config.ini` im gleichen Baum wie `modules`, mit mindestens:
|
||||
- `APP_ENV_TYPE = dev|int|prod` (kann pro Env-Datei zusätzlich gesetzt werden)
|
||||
|
|
@ -80,7 +80,7 @@ Tool: `gateway/tool_security_encrypt_all_env_files.py`
|
|||
- Liest je Datei `APP_ENV_TYPE`.
|
||||
- Findet alle Schlüssel, deren Name auf `_SECRET` endet, und deren Werte noch kein `*_ENC:`-Präfix haben.
|
||||
- Unterstützt einzeilige und mehrzeilige JSON-Werte (Klammer-Auf/Zu wird erkannt).
|
||||
- Verschlüsselt die Werte mit dem passenden Umgebungs-Key und ersetzt die Originalwerte in der Datei durch `ENV_ENC:<payload>`.
|
||||
- Verschlüsselt die Werte mit dem passenden Umgebungs-Key und ersetzt die Originalwerte in der Datei durch den umgebungsspezifischen Prefix, z.B. `DEV_ENC:<payload>`, `INT_ENC:<payload>`, `PROD_ENC:<payload>` (abhaengig von `APP_ENV_TYPE`).
|
||||
- Legt vor Änderungen eine Backup-Datei mit Zeitstempel neben der Originaldatei an, z. B. `env_prod.env.20251015_101530.backup`.
|
||||
|
||||
- Trockenlauf (nur anzeigen, nichts schreiben):
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ This guide explains how to set up Google OAuth 2.0 authentication for the PowerO
|
|||
4. Enter a project name (e.g., "PowerOn OAuth")
|
||||
5. Click "Create"
|
||||
|
||||
## Step 2: Enable Google+ API
|
||||
## Step 2: Configure OAuth Consent Screen
|
||||
|
||||
1. In your new project, go to "APIs & Services" > "Library"
|
||||
2. Search for "Google+ API" or "Google Identity"
|
||||
3. Click on "Google+ API" and click "Enable"
|
||||
1. In your new project, go to "APIs & Services" > "OAuth consent screen"
|
||||
2. Configure the consent screen (Google+ API is deprecated, use Google Identity Services / OIDC)
|
||||
|
||||
## Step 3: Create OAuth 2.0 Credentials
|
||||
|
||||
|
|
@ -35,9 +34,10 @@ This guide explains how to set up Google OAuth 2.0 authentication for the PowerO
|
|||
4. Back to creating OAuth client ID:
|
||||
- Application type: "Web application"
|
||||
- Name: "PowerOn Web Client"
|
||||
- Authorized redirect URIs: Add your redirect URI
|
||||
- For development: `http://localhost:8000/api/google/auth/callback`
|
||||
- For production: `https://yourdomain.com/api/google/auth/callback`
|
||||
- Authorized redirect URIs: Add **two** redirect URIs per environment:
|
||||
- Login callback: `http://localhost:8000/api/google/auth/login/callback`
|
||||
- Data connect callback: `http://localhost:8000/api/google/auth/connect/callback`
|
||||
- For production: replace `localhost:8000` with your domain (HTTPS)
|
||||
|
||||
5. Click "Create"
|
||||
6. **Important**: Copy the Client ID and Client Secret - you'll need these for the next step
|
||||
|
|
@ -48,12 +48,19 @@ This guide explains how to set up Google OAuth 2.0 authentication for the PowerO
|
|||
2. Replace the placeholder values with your actual Google OAuth credentials:
|
||||
|
||||
```env
|
||||
# Google OAuth Configuration
|
||||
Service_GOOGLE_CLIENT_ID = your-actual-client-id-from-google-console
|
||||
Service_GOOGLE_CLIENT_SECRET = your-actual-client-secret-from-google-console
|
||||
Service_GOOGLE_REDIRECT_URI = http://localhost:8000/api/google/auth/callback
|
||||
# Google OAuth -- Auth App (Login)
|
||||
Service_GOOGLE_AUTH_CLIENT_ID = your-auth-client-id
|
||||
Service_GOOGLE_AUTH_CLIENT_SECRET = your-auth-client-secret
|
||||
Service_GOOGLE_AUTH_REDIRECT_URI = http://localhost:8000/api/google/auth/login/callback
|
||||
|
||||
# Google OAuth -- Data App (SharePoint/Drive Connection)
|
||||
Service_GOOGLE_DATA_CLIENT_ID = your-data-client-id
|
||||
Service_GOOGLE_DATA_CLIENT_SECRET = your-data-client-secret
|
||||
Service_GOOGLE_DATA_REDIRECT_URI = http://localhost:8000/api/google/auth/connect/callback
|
||||
```
|
||||
|
||||
> **Hinweis:** Das Gateway unterscheidet zwei OAuth-Apps: eine fuer Login (Auth) und eine fuer Daten-Connections (Data). Details: `routeSecurityGoogle.py`.
|
||||
|
||||
3. Save the file
|
||||
4. Restart your PowerOn gateway server
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,105 @@
|
|||
<!-- status: draft -->
|
||||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
|
||||
# Testing-Strategie
|
||||
|
||||
## Testpyramide
|
||||
|
||||
- **Unit Tests:** pytest (Gateway), vitest (Frontend)
|
||||
- **Integration Tests:** API-Tests gegen laufenden Gateway
|
||||
- **E2E Tests:** (zu definieren)
|
||||
```
|
||||
/ E2E \ <- Manuell / geplant
|
||||
/ Functional \ <- Standalone-Scripts (AI, real calls)
|
||||
/ Integration \ <- pytest (DB, Workflows, RBAC)
|
||||
/ Unit \ <- pytest (Models, Utils, Logic)
|
||||
```
|
||||
|
||||
## Akzeptanzkriterien-Format
|
||||
## Gateway: `gateway/tests/`
|
||||
|
||||
Given-When-Then Sätze in Arbeits-Dokumenten (`c-work/_TEMPLATE.md`)
|
||||
### Test-Kategorien
|
||||
|
||||
## Testplan-Tabelle
|
||||
| Kategorie | Pfad | Beschreibung | Ausfuehrung |
|
||||
|-----------|------|-------------|-------------|
|
||||
| **Unit** | `tests/unit/` | Datamodels, RBAC-Logic, Utils, Workflows | `pytest tests/unit/` |
|
||||
| **Integration** | `tests/integration/` | DB-abhaengig (RBAC, Workflow-Execution) | `pytest tests/integration/` |
|
||||
| **Validation** | `tests/validation/` | Architektur-Validierung | `pytest tests/validation/` |
|
||||
| **Functional** | `tests/functional/` | AI-Modell-Tests, KPI, JSON-Verarbeitung | `python tests/functional/<script>.py` (standalone, nicht pytest) |
|
||||
|
||||
Jedes Arbeits-Dokument enthält eine Testplan-Tabelle:
|
||||
### Test-Verzeichnisstruktur
|
||||
|
||||
```
|
||||
tests/
|
||||
conftest.py # sys.path Setup
|
||||
README.md # Ausfuehrungshinweise
|
||||
test_phase123_basic.py # Root-Level Basistest
|
||||
unit/
|
||||
datamodels/ # test_workflow_models, test_docref
|
||||
rbac/ # test_rbac_bootstrap, test_rbac_permissions
|
||||
services/ # test_renderer_pdf_smoke, test_json_extraction
|
||||
utils/ # test_json_utils
|
||||
workflows/ # test_automation2_graphUtils, test_state_management
|
||||
integration/
|
||||
rbac/ # test_rbac_database
|
||||
workflows/ # test_workflow_execution
|
||||
validation/
|
||||
test_architecture_validation.py
|
||||
functional/
|
||||
test01_ai_model_selection.py # Nummerierte AI-Testscripts
|
||||
... # test14_json_continuation_context.py etc.
|
||||
```
|
||||
|
||||
### Tests ausfuehren
|
||||
|
||||
```bash
|
||||
cd gateway/
|
||||
|
||||
# Standard (ohne expensive-Marker):
|
||||
pytest
|
||||
|
||||
# Alle Tests (inkl. expensive):
|
||||
pytest -m ""
|
||||
|
||||
# Nur Unit:
|
||||
pytest tests/unit/
|
||||
|
||||
# Mit Coverage:
|
||||
pytest --cov=modules tests/unit/
|
||||
```
|
||||
|
||||
### Marker
|
||||
|
||||
- `@pytest.mark.expensive` -- Standardmaessig uebersprungen (Default: `-m 'not expensive'` in `pytest.ini`)
|
||||
- `@pytest.mark.asyncio` -- Fuer async Tests
|
||||
|
||||
### Konfiguration
|
||||
|
||||
`pytest.ini` im `gateway/`-Root:
|
||||
- `testpaths = tests`, `pythonpath = .`
|
||||
- Log-Output: `logs/test_logs.log`
|
||||
- Default: `-v --tb=short -m 'not expensive'`
|
||||
|
||||
## Frontend Nyla
|
||||
|
||||
**Aktueller Stand (2026-04-05):** Kein automatisiertes Test-Framework installiert. `package.json` enthaelt keinen `test`-Script, keine Vitest/Jest/Cypress-Dependency.
|
||||
|
||||
**Qualitaets-Gate:** Nur ESLint (`npm run lint`).
|
||||
|
||||
**Empfehlung:** Vitest fuer Unit/Component-Tests, Playwright oder Cypress fuer E2E.
|
||||
|
||||
## Akzeptanzkriterien (AC-Format)
|
||||
|
||||
In Work-Items (`c-work/`) verwenden wir Given-When-Then:
|
||||
|
||||
```
|
||||
Given <Vorbedingung>
|
||||
When <Aktion>
|
||||
Then <erwartetes Ergebnis>
|
||||
```
|
||||
|
||||
### Testplan-Mapping
|
||||
|
||||
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|
||||
|----|----|-----|--------------|-----------|--------|
|
||||
| T1 | 1 | unit | ja | gateway/tests/unit/... | pending |
|
||||
| T2 | 2 | integration | ja | gateway/tests/integration/... | pending |
|
||||
| T3 | 3 | api | nein | -- | pending |
|
||||
|
||||
## Test-Pfade im Repo
|
||||
|
||||
- Gateway: `gateway/tests/`
|
||||
- Frontend: `frontend_nyla/src/**/*.test.ts`
|
||||
Referenz: -> `c-work/_TEMPLATE.md` (Testplan-Section)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Neutralisierung
|
||||
# Neutralisierung
|
||||
|
||||
**Stand:** 2026-03-29
|
||||
|
||||
|
|
@ -54,11 +54,11 @@ Eine Engine, drei Einstiege, aufgerufen an den Content-Einstiegspunkten aus Absc
|
|||
| `processText(text)` | Rohtext (Prompt, Message, Text-ContentPart, Text-Chunk) | **Ist** |
|
||||
| `processFile(fileId)` | Datei aus DB — wird nach MIME geroutet | **Ist** |
|
||||
| `processBinaryBytes` / `Async` | Bytes + Dateiname + MIME | **Ist** |
|
||||
| **`processImage(imageBytes, fileName)`** | Bild-Datei oder Bild-ContentPart (image/png, image/jpeg, …) | **Soll — fehlt heute** |
|
||||
| **`processImage(imageBytes, fileName)`** / `processImageAsync` | Bild-Datei oder Bild-ContentPart (image/png, image/jpeg, …) | **Ist** (seit ~2026 Q1) |
|
||||
|
||||
**Ist-Zustand Bilder:** `_processBinaryFile` überspringt Parts mit `typeGroup == 'image'` (unverändert durchgereicht). Eigenständige Bild-Dateien (`image/*` MIME) werden in `_isBinaryMimeType` als Skip behandelt. **Es gibt keinen Bild-Neutralisierungs-Pfad.**
|
||||
**Ist-Zustand Bilder (aktualisiert 2026-04-05):** `processImageAsync` ist implementiert und nutzt `NEUTRALIZATION_IMAGE` (Private LLM Vision). `_processBinaryFile` verarbeitet jetzt Bild-Parts ueber `processImageAsync`. **Einschraenkung:** Eigenstaendige Bild-Dateien (`image/*` MIME direkt an `processFile`) werden in `_isBinaryMimeType` weiterhin als Skip behandelt.
|
||||
|
||||
**Soll:** `processImage` als eigener Einstieg. Ruft internes Vision-Modell (`NEUTRALIZATION_IMAGE` → Private-LLM) auf, um sensible Inhalte in Bildern zu erkennen/entfernen. Kein externer Provider. Modell nicht verfügbar → Bild blockieren (nicht unbehandelt weiterreichen).
|
||||
**Ist (aktualisiert):** `processImageAsync` existiert als Einstieg. Ruft internes Vision-Modell (`NEUTRALIZATION_IMAGE` → Private-LLM) auf, um sensible Inhalte in Bildern zu erkennen/entfernen. Kein externer Provider. Modell nicht verfügbar → Bild blockieren (nicht unbehandelt weiterreichen).
|
||||
|
||||
**Ablauf nach MIME:**
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ PowerOn implementiert Schutzmassnahmen gegen die gängigsten Angriffsvektoren f
|
|||
|
||||
### 6.1 Cross-Site Request Forgery (CSRF)
|
||||
|
||||
Alle datenverändernden Operationen (Erstellen, Ändern, Löschen) erfordern ein gültiges Sicherheitstoken. Damit wird verhindert, dass schädliche Webseiten im Namen eines eingeloggten Nutzers Aktionen auslösen können.
|
||||
Alle datenverändernden Operationen (POST, PUT, DELETE, PATCH) erfordern einen `X-CSRF-Token` Header. Die aktuelle Implementierung validiert das Tokenformat (16-64 Zeichen Hex-String); es gibt kein serverseitiges Session-Binding (kein klassisches Double-Submit oder Synchronizer Token). In Kombination mit `SameSite=Strict` Cookies und CORS bietet dies Basisschutz gegen CSRF.
|
||||
|
||||
### 6.2 Ratenbegrenzung (Rate Limiting)
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ Jede API-Funktion ist mit individuellen Zugriffslimits versehen, die automatisie
|
|||
|
||||
| Funktion | Limit |
|
||||
|---|---|
|
||||
| Anmeldung | 5 Versuche pro Minute |
|
||||
| Anmeldung | 30 Versuche pro Minute |
|
||||
| Datenexport (DSGVO) | 5 Anfragen pro Minute |
|
||||
| Kontolöschung | 1 Anfrage pro Stunde |
|
||||
| Chatbot-Nutzung | 120 Anfragen pro Minute |
|
||||
|
|
|
|||