wiki/c-work/4-done/2026-04-automation-unification.md

1206 lines
60 KiB
Markdown

<!-- status: done -->
<!-- started: 2026-04-05 -->
<!-- completed: 2026-04-07 -->
<!-- component: gateway | frontend-nyla | platform -->
# Automation Unification -- Konsolidierung v1/v2/Workspace
## Beschreibung und Kontext
PowerOn hat drei teilweise ueberlappende Automatisierungssysteme: Automation v1 (Template+Cron), Automation2 (n8n-Style Graph-Editor), und AI Workspace (Chat-Agent mit Tools). Alle nutzen die gleiche Action Library (`workflows/methods/` + `ActionExecutor`), aber unterschiedliche Persistenz, Scheduler und Execution Engines.
**Business-Treiber:** Inkonsistenzen zwischen den Systemen (zwei DB-Schemas, zwei Scheduler-Patterns, zwei Engines) erhoehen den Wartungsaufwand und erschweren Feature-Paritaet.
**Risiko bei Nicht-Umsetzung:** Wachsende Divergenz, doppelter Aufwand bei neuen Aktionen, inkonsistentes Verhalten fuer Endbenutzer.
**Leitprinzipien:**
- Keine Migration von Altdaten -- Automation v1 war nicht produktiv, wurde nicht migriert
- Legacy-Features `automation` und `automation2` wurden entfernt (2026-04-07)
- Klare Datenmodelle mit definierten State Machines als stabile, erweiterbare Grundlage
- Klare Trennung von Mandant/Feature/Feature-Instanz und zugehoeriger RBAC-Logik
- Skalierbare AI-Tool-Architektur mit Toolboxes und Sub-Agents fuer 50-100+ Tools
- Einheitlicher **`Auto`-Prefix** fuer alle neuen Datenobjekte (z.B. `AutoWorkflow`, `AutoVersion`, `AutoRun`) -- klare Erkennbarkeit in der Codebase
- **Greenfield-Migration:** Neue DB (`poweron_graphicaleditor`), kein Schema-Umbau auf `poweron_automation2`. Alte DB bleibt als Archiv bestehen, Daten werden **nicht** migriert
---
## Ist-Analyse
### Drei bestehende Systeme
| System | Modell | Staerke | Schwaeche |
|--------|--------|---------|-----------|
| **Automation v1** | Template + Cron + Placeholders | Stabiles, bewaehrtes Scheduling mit Callback-basiertem Sync, inkrementeller Job-Registrierung, Execution-Logs | Kein visuelles Editing, kein Branching, starres Template-Modell |
| **Automation2** | Graph-Editor (n8n-style) + Run/Task-Modell | Visuelles Modellieren, Branching, Loops, Human-in-the-loop, Pause/Resume, diverse Node-Typen | Kein AI-Chat im Editor, kein UDB-Zugang, Scheduler-Sync weniger robust als v1 |
| **AI Workspace** | Chat-driven AI Agent mit Tools | Natural-language Interaktion, 40+ Core Tools + Action Tools, Streaming, RAG | Kein persistiertes Workflow-Modell, kein Scheduling |
### Wer nutzt die Method/Action Library?
Die `workflows/methods/` Library (methodAi, methodOutlook, methodSharepoint, etc.) ist die de facto gemeinsame Basis. Alle Systeme nutzen `ActionExecutor.executeAction()`:
| Consumer | Pfad zur Action Library |
|----------|------------------------|
| **Workspace AI Agent** | `ActionToolAdapter` registriert `dynamicMode=True` Actions als Agent-Tools -> LLM waehlt Tool -> `ActionExecutor` |
| **Automation2 Graph Engine** | `ActionNodeExecutor` liest `_method`/`_action` aus Node-Definition -> `ActionExecutor` |
| **Automation v1** | `WorkflowProcessor` -> `modeAutomation` -> `ActionExecutor` |
| **Workspace Dynamic Mode** | `WorkflowProcessor` -> `modeDynamic` -> AI plant Tasks -> `ActionExecutor` |
### Wer nutzt die AI Tools?
| Tool-Typ | Registrierung | Nutzung |
|----------|--------------|---------|
| **Core Tools** (40: readFile, webSearch, sendMail, etc.) | `registerCoreTools()` via `coreTools/` | Workspace Agent, CommCoach Agent |
| **Action Tools** (dynamicMode Actions) | `ActionToolAdapter.registerAll()` | Workspace Agent (toolSet-uebergreifend) |
| **Graph Node Types** (ai.prompt, email.checkEmail, etc.) | `STATIC_NODE_TYPES` in `nodeDefinitions/` | Automation2 `executeGraph` |
### Identifizierte Inkonsistenzen
| # | Inkonsistenz | Status |
|---|-------------|--------|
| **I-1** | Zwei Datenmodelle: `AutomationDefinition` (v1) vs `Automation2Workflow` (v2) -- kein gemeinsames Workflow-Konzept | **behoben** -- Unified `AutoWorkflow` in Greenfield DB |
| **I-2** | Zwei Datenbanken: `poweron_automation` vs `poweron_automation2` | **behoben** -- Neue DB `poweron_graphicaleditor`, Legacy entfernt |
| **I-3** | Zwei Scheduler: v1 (inkrementell) vs v2 (full wipe + re-register) | offen (Phase 4) |
| **I-4** | Zwei Execution Engines: `WorkflowManager` + `WorkflowProcessor` vs `executionEngine.executeGraph` | offen (bewusst getrennt) |
| **I-5** | Kein AI-Chat im Graphical Editor | **behoben** -- EditorChatPanel mit SSE |
| **I-6** | `WorkspaceInput` ist nicht als wiederverwendbare Komponente extrahiert | offen (Phase 4) |
| **I-7** | UDB nur in Workspace und CommCoach, nicht im Graphical Editor | **behoben** -- UDB im Editor integriert |
| **I-8** | AI Tools skalieren nicht: 50+ Tools ohne Gruppierungslogik | offen (Phase 4: Toolbox Registry) |
---
## Ziel-Architektur: Vier Saeulen
```
+----------------------------------------------------------------------+
| POWERON UNIFIED PLATFORM |
| |
| +--------------+ +-----------------------+ +------------------+ |
| | AI Service | | Graphical Editor | | Automation | |
| | (Saeule 1) | | (Saeule 2) | | Scheduler | |
| | | | | | (Saeule 3) | |
| | - AI Gateway | | - Visual Flow Builder | | | |
| | - Agent Loop | | - Node Palette | | - Cron Engine | |
| | - Toolboxes | | - AI Chat Sidebar | | - Event Trigger | |
| | - Sub-Agents | | - UDB Integration | | - Webhook Entry | |
| | - Streaming | | - Tracing/Debug Log | | - Run History | |
| | - Failover | | - Test Runner | | - Monitoring | |
| | - Neutraliz. | | - Version Management | | - Notifications | |
| +------+--------+ +-----------+-------------+ +--------+---------+ |
| | | | |
| +------v------------------------v---------------------------v----------+ |
| | SAEULE 4: UNIFIED ACTION LIBRARY (Toolboxes) | |
| | | |
| | Toolbox "ai" | Toolbox "email" | Toolbox "files" | |
| | ai.process | outlook.readEmails | context.extract | |
| | ai.webResearch | outlook.searchEmails | context.neutralize | |
| | ai.summarize | outlook.draftEmail | file.create | |
| | ai.translate | outlook.sendDraft | context.transform | |
| | | | | |
| | Toolbox "sharepoint"| Toolbox "clickup" | Toolbox "jira" | |
| | sharepoint.findDoc | clickup.searchTasks | jira.connect | |
| | sharepoint.readDocs | clickup.createTask | jira.exportTickets | |
| | sharepoint.upload | clickup.updateTask | jira.importTickets | |
| | | | | |
| | Toolbox "workflow" | Toolbox "trustee" | [future toolboxes] | |
| | readWorkflowGraph | trustee.extract | slack.sendMessage | |
| | addNode, removeNode | trustee.process | teams.postChannel | |
| | connectNodes | trustee.syncAcctng | google.readDrive | |
| +----------------------------------------------------------------------+ |
+------------------------------------------------------------------------+
```
### Saeule 1: AI Service (besteht, zu erweitern in Phase 4)
**Status:** Kern bereit (`serviceAi` + `serviceAgent` + `aicore`). AI Chat im Editor integriert (EditorChatPanel).
**Offen:** Toolbox-Architektur fuer 50-100+ Tools (siehe Abschnitt Toolboxes, Phase 4).
### Saeule 2: Graphical Editor (Feature "graphicalEditor")
**Status:** Implementiert. Legacy-Features `automation` und `automation2` entfernt.
| # | Funktionalitaet | Status |
|---|-----------------|--------|
| 1 | **Visual Flow Builder** -- Canvas, Nodes, Connections, Branching, Loops | umgesetzt |
| 2 | **Node Palette** -- Trigger, Flow, AI, Email, SharePoint, ClickUp, File, Trustee | umgesetzt |
| 3 | **AI Chat Sidebar** -- EditorChatPanel mit SSE-Streaming, Graph-Manipulation-Tools | umgesetzt |
| 4 | **UDB Integration** -- UnifiedDataBar mit Files + Sources Tabs, Mandate-gefiltert | umgesetzt |
| 5 | **Tracing/Debug Log** -- RunTracingPanel mit AutoStepLog-Anzeige | umgesetzt (Basis) |
| 6 | **Test Runner** -- Visual Highlighting, Step-by-Step, AI-assisted Debugging | zu erweitern |
| 7 | **Version Management** -- Draft/Published/Archived Lifecycle via CanvasHeader | umgesetzt |
| 8 | **Template Management** -- Save as Template, New from Template, Scope-Verwaltung | umgesetzt |
| 9 | **File/Source Attachments** -- Drag&Drop + Source-Picker im AI Chat (wie Workspace) | umgesetzt |
### Saeule 3: Automation Scheduler (zu konsolidieren)
**Von v1 uebernehmen:**
- Inkrementeller Sync (nur geaenderte Jobs registrieren/entfernen, nicht full wipe)
- Persistierter Job-Handle (`eventId`) auf dem Workflow fuer Debugging
- `automation.changed` Callback-Pattern fuer reaktive Synchronisation
- Handler laedt Workflow neu und prueft `active` vor Execution
- Execution-Logs als Audit Trail (capped auf 50 Eintraege)
- Creator-User Tracking via `sysCreatedBy` fuer Execution-Kontext
**Von v2 beibehalten:**
- `IntervalTrigger` fuer einfache Wiederholungen
- Main-Loop-Bridging (`call_soon_threadsafe`) fuer Thread-Safety
- Delayed Startup Sync (5s) fuer DB-Readiness
- Striktes Cron-Parsing (5/6 Felder)
### Saeule 4: Unified Action Library mit Toolboxes
**Status:** Infrastruktur besteht (`workflows/methods/` + `methodDiscovery` + `ActionExecutor`). Trustee-Nodes hinzugefuegt. Toolbox-Konzept offen (Phase 4).
---
## Fokus und kritische Details
- Scheduler-Robustheit: v1 hat bewaehrtes inkrementelles Pattern, v2 macht Full-Wipe-Re-Register
- Tool-Skalierung: 40+ Core-Tools + dynamische Actions -- flache Tool-Listen skalieren nicht
- Human-in-the-Loop: Pause/Resume nur in v2 implementiert
- Keine Migration von v1-Altdaten (nicht produktiv)
---
## Ziel und Nicht-Ziele
- **Ziel:** Einheitliche Plattform mit v1-Scheduler-Robustheit und v2-Graph-Faehigkeiten
- **Ziel:** Toolbox-Architektur fuer skalierbare Tool-Verwaltung (requestToolbox, availableToolboxes)
- **Ziel:** Einheitliches Workflow/Version/Run Datenmodell (Draft -> Published, Runs, Tracing)
- **Explizit NICHT:** Migration von v1-Daten; Abloesung des AI Workspace Chat-Modells
---
## Mandant/Feature/RBAC-Architektur
### Hierarchie
```
System (PowerOn Platform)
|
+-- System Template Rollen (isSystemRole=true, mandateId=null, featureCode=null)
| "admin", "user", "viewer"
| -> kopiert bei Mandant-Erstellung via copySystemRolesToMandate()
|
+-- Feature Template Rollen (isSystemRole=false, mandateId=null, featureCode=X)
| "workspace-admin", "workspace-user", "workspace-viewer"
| "graphicalEditor-admin", "graphicalEditor-user", ...
| -> kopiert bei Feature-Instanz-Erstellung via _copyTemplateRoles()
|
+-- Mandant (Tenant)
+-- Mandate-Rollen (kopiert von System Templates)
| mandateId=X, featureInstanceId=null, featureCode=null
| "admin", "user", "viewer"
| -> UserMandateRole <- UserMandate <- User
|
+-- Feature-Instanz A (z.B. "AI Workspace Produktion")
| +-- Feature-Instanz-Rollen (kopiert von Feature Templates)
| | mandateId=X, featureInstanceId=Y, featureCode="workspace"
| | "workspace-admin", "workspace-user", "workspace-viewer"
| | -> FeatureAccessRole <- FeatureAccess <- User
| +-- Daten (Workflows, Files, Chats, ...)
|
+-- Feature-Instanz B (z.B. "Graphical Editor Dev")
+-- Feature-Instanz-Rollen
+-- Daten (Workflows, Runs, Tasks, ...)
```
### Zwei getrennte Template-Rollen-Systeme
**System Template Rollen (fuer Mandanten)**
| Feld | Wert |
|------|------|
| `isSystemRole` | `true` |
| `mandateId` | `null` |
| `featureInstanceId` | `null` |
| `featureCode` | `null` |
| `roleLabel` | `"admin"`, `"user"`, `"viewer"` |
| Kopier-Mechanismus | `copySystemRolesToMandate()` in `interfaceBootstrap.py` |
| Ausgeloest bei | Mandant-Erstellung |
**Feature Template Rollen (fuer Feature-Instanzen)**
| Feld | Wert |
|------|------|
| `isSystemRole` | `false` |
| `mandateId` | `null` |
| `featureInstanceId` | `null` |
| `featureCode` | z.B. `"workspace"`, `"automation2"` |
| `roleLabel` | z.B. `"workspace-admin"`, `"workspace-user"` |
| Kopier-Mechanismus | `_copyTemplateRoles()` in `interfaceFeatures.py` |
| Ausgeloest bei | Feature-Instanz-Erstellung |
**Wichtig:** Templates werden **nur bei Erstellung** kopiert. Spaetere Aenderungen werden **nicht** automatisch propagiert.
### RBAC-Resolution (Priority-System)
| Rollen-Typ | Scope | RBAC Priority |
|------------|-------|---------------|
| **Global/Template** | `mandateId=null, featureInstanceId=null` | 1 (niedrigste) |
| **Mandate-Rolle** | `mandateId=X, featureInstanceId=null` | 2 |
| **Instanz-Rolle** | `mandateId=X, featureInstanceId=Y` | 3 (hoechste) |
**Resolution:**
1. Lade Mandate-Rollen (via `UserMandate` -> `UserMandateRole`)
2. Lade Feature-Instanz-Rollen (via `FeatureAccess` -> `FeatureAccessRole`)
3. Lade `AccessRules` fuer alle gefundenen Rollen
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
### RBAC-Datenmodell
```python
class Role(PowerOnModel):
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"
isSystemRole: bool
class AccessRule(PowerOnModel):
roleId: str # FK -> Role
context: AccessRuleContext # DATA | UI | RESOURCE
item: Optional[str] # null=generic, oder spezifisch
view: bool
read: Optional[AccessLevel] # "n" | "o" | "m" | "a"
create: Optional[AccessLevel]
update: Optional[AccessLevel]
delete: Optional[AccessLevel]
class AccessLevel(str, Enum):
NONE = "n"
OWN = "o"
MANDATE = "m"
ALL = "a"
```
### AccessRule-Kontexte
| Kontext | Item-Beispiel | Prueft |
|---------|---------------|--------|
| `UI` | `ui.feature.graphicalEditor.editor` | Seitenleiste, Navigation, Buttons |
| `RESOURCE` | `resource.feature.graphicalEditor.execute` | Ausfuehrungsberechtigungen |
| `DATA` | Auto-generiert aus Tabellenname + featureCode | CRUD auf Datenbank-Ebene |
---
## AI-Tool-Architektur: Toolboxes und Sub-Agents
### Problem: Tool-Explosion
Aktuell werden ~50 Tools dem LLM in einem einzigen Prompt exponiert. Bei 100+ Tools:
- LLM-Context wird ueberladen -> schlechtere Tool-Auswahl
- Irrelevante Tools fuer den aktuellen Kontext -> Confusion und Halluzinationen
- Keine Feature-isolierte Tool-Bereitstellung
### Konzept: Toolboxes
Eine **Toolbox** ist eine thematisch gebuendelte Gruppe von Tools mit einem klaren Scope:
```
Toolbox-Registry
|
+-- Toolbox "core" (immer verfuegbar)
| readFile, listFiles, searchInFileContent, writeFile, deleteFile,
| renameFile, copyFile, listFolders, createFolder, deleteFolder,
| webSearch, readUrl, detectLanguage, translateText
|
+-- Toolbox "ai" (AI-Operationen)
| summarizeContent, describeImage, generateImage, textToSpeech,
| speechToText, renderDocument, createChart, executeCode, neutralizeData
|
+-- Toolbox "datasources" (Externe Verbindungen)
| listConnections, browseDataSource, searchDataSource,
| downloadFromDataSource, uploadToExternal, browseContainer,
| readContentObjects, extractContainerItem
|
+-- Toolbox "email" (Outlook-Integration, requiresConnection="outlook")
| sendMail, outlook.readEmails, outlook.searchEmails, outlook.draftEmail
|
+-- Toolbox "sharepoint" (requiresConnection="sharepoint")
| sharepoint.findDoc, sharepoint.read, sharepoint.upload, ...
|
+-- Toolbox "clickup" (requiresConnection="clickup")
| clickup.searchTasks, clickup.createTask, ...
|
+-- Toolbox "jira" (requiresConnection="jira")
| jira.connect, jira.exportTickets, ...
|
+-- Toolbox "workflow" (Graph-Manipulation fuer Editor-Chat)
| readWorkflowGraph, addNode, removeNode, connectNodes,
| setNodeParameter, listAvailableNodeTypes, validateGraph,
| listWorkflowHistory, readWorkflowMessages
|
+-- Toolbox "trustee" (featureCode="trustee")
| trustee.extract, trustee.process, trustee.syncAccounting
|
+-- Toolbox "chatbot" (featureCode="chatbot")
chatbot.queryDatabase
```
### Toolbox-Bereitstellung: Initiales Set + dynamische Eskalation
**Kern-Idee:** Der Agent startet mit einem kompakten Tool-Set. Er kennt den **Katalog aller verfuegbaren Toolboxes**. Wenn er Spezial-Tools braucht, kann er eine Toolbox **anfordern** -- und bekommt sie in der naechsten Runde.
```
Runde 1:
Tools: core (readFile, webSearch, ...) + requestToolbox
System-Prompt: "Verfuegbare Toolboxes: email, sharepoint, clickup, ..."
User: "Lies meine letzten Emails und fasse sie zusammen"
LLM: -> requestToolbox("email") [braucht Email-Tools]
Runde 2:
Tools: core + email (sendMail, outlook_readEmails, ...) + requestToolbox
LLM: -> outlook_readEmails(connectionRef, folder="Inbox", limit=10)
Runde 3:
LLM: -> (Text-Antwort mit Zusammenfassung) -> COMPLETED
```
**`requestToolbox` Meta-Tool:**
```python
{
"name": "requestToolbox",
"description": "Request additional specialized tools for the current task.",
"parameters": {
"toolboxId": {
"type": "string",
"enum": [...] # Dynamisch: nur verfuegbare Toolboxes
},
"reason": {"type": "string"}
}
}
```
### Toolbox-Datenmodell
```python
class ToolboxDefinition(BaseModel):
id: str # z.B. "core", "email", "sharepoint"
label: Dict[str, str] # Multilingual: {"en": "Email", "de": "E-Mail"}
description: str
featureCode: Optional[str] # null = Feature-unabhaengig
tools: List[str] # Tool-Namen in dieser Toolbox
isDefault: bool = False # Immer aktiv (z.B. "core")
requiresConnection: Optional[str] # "outlook" -> auto-aktiviert bei Connection
class ToolboxRegistry:
_toolboxes: Dict[str, ToolboxDefinition]
_toolRegistry: ToolRegistry
def registerToolbox(self, toolbox: ToolboxDefinition): ...
def getActiveToolboxes(self, featureCode, userConnections, explicitToolboxes): ...
def getToolsForToolboxes(self, activeToolboxIds) -> List[ToolDefinition]: ...
class AgentConfig(BaseModel):
maxRounds: int = 25
maxCostCHF: Optional[float] = None
initialToolboxes: List[str] = ["core"]
availableToolboxes: List[str] = []
temperature: Optional[float] = None
```
### Toolbox-Zuordnung pro Feature
| Feature | `initialToolboxes` | `availableToolboxes` (anforderbar) |
|---------|--------------------|------------------------------------|
| **Workspace** | `["core"]` | `["ai", "datasources", "email", "sharepoint", "clickup", "jira", "workflow"]` -- gefiltert nach User-Connections |
| **Graphical Editor Chat** | `["core", "workflow"]` | `["ai"]` |
| **CommCoach** | `["core"]` | `[]` (keine Eskalation erlaubt) |
| **Chatbot** | `["core"]` | `[]` |
**Automatische Toolbox-Verfuegbarkeit:** Welche Toolboxes in `availableToolboxes` erscheinen, haengt von den aktiven User-Connections ab. Keine Outlook-Verbindung -> `"email"` erscheint nicht.
### Sub-Agents (Feature Data Agents)
```
User Prompt im Workspace
|
v
Main Agent (Toolboxes: core, ai, datasources, ...)
|
+-- Tool: queryFeatureInstance("trustee", instanceId, question)
| |
| v
| Sub-Agent (Feature Data Agent)
| Eigene ToolRegistry: browseTable, queryTable
| Eigenes System-Prompt mit Schema-Wissen
| Limitiert: maxRounds=5, maxCost=0.10 CHF
| |
| v
| Antwort zurueck an Main Agent
|
+-- Tool: readFile(fileId) -- Core Tool, direkt
+-- Tool: outlook_readEmails(connectionRef) -- Action Tool, direkt
```
**Faustregel:** Toolbox wenn die Tools generisch sind. Sub-Agent wenn Feature-spezifisches Kontext-/Schema-Wissen noetig ist.
### State Machine: AI Agent Run (mit Toolbox-Eskalation)
```
+----------+
| IDLE |
+----+-----+
| runAgent(prompt, initialToolboxes, availableToolboxes)
v
+----------+
+---->| THINKING |<-------------------------------+
| +----+-----+ |
| | |
| +-- LLM Response (Text only) ----------+---> COMPLETED
| | |
| +-- LLM Response (ToolCalls) |
| | |
| v |
| +--------------------+ |
| | EXECUTING_TOOLS | |
| +----+---------------+ |
| | |
| +-- requestToolbox(id) --+ |
| | v |
| | +---------------------+ |
| | | TOOLBOX_ESCALATION | |
| | | Toolbox aktiviert | |
| | | Tools erweitert | |
| | +----------+----------+ |
| | | |
| +-- Sub-Agent call --+ | |
| | v | |
| | +-------------+| |
| | |SUB_AGENT_CALL|| |
| | +------+------+| |
| | | | |
| +-- Regular tools-+-------+-------------+
| (results -> next round)
|
| maxRounds / maxCost reached
v
+----------+
| COMPLETED | (oder FAILED / CANCELLED)
+----------+
```
---
## Unified Workflow Datenmodell (Ziel)
### Entitaeten
**Naming-Konvention:** Alle Datenobjekte tragen den Prefix **`Auto`** fuer eindeutige Erkennbarkeit in der Codebase. Enums ohne Prefix (domainweit gueltig).
```python
class AutoWorkflowStatus(str, Enum):
DRAFT = "draft"
PUBLISHED = "published"
ARCHIVED = "archived"
class AutoWorkflow(PowerOnModel):
id: str
mandateId: str
featureInstanceId: str
label: str
description: Optional[str]
tags: List[str] = []
isTemplate: bool = False
templateSourceId: Optional[str] # geklont von diesem Template
templateScope: Optional[str] # user | instance | mandate | system (siehe Abschnitt Workflow-Vorlagen)
sharedReadOnly: bool = False # Freigabe: Nutzung ohne strukturelle Aenderung
currentVersionId: Optional[str] # aktive/published Version
active: bool = True # Scheduler-enabled
eventId: Optional[str] # APScheduler Job-ID (v1-Pattern)
class AutoVersion(PowerOnModel):
id: str
workflowId: str # FK -> AutoWorkflow
versionNumber: int # auto-increment
status: AutoWorkflowStatus # draft | published | archived
graph: Dict[str, Any] # { nodes: [...], connections: [...] }
invocations: List[Dict[str, Any]] # Entry-Points (manual, schedule, webhook, form)
publishedAt: Optional[float]
publishedBy: Optional[str]
```
### State Machine: AutoVersion.status
```
+-------+
create --->| DRAFT |<--- edit (graph mutation via API oder AI Tools)
+---+---+
| publish
v
+-----------+
unpublish->| PUBLISHED |
(->DRAFT) +-----+-----+
| archive
v
+-----------+
| ARCHIVED |--> re-publish (-> PUBLISHED)
+-----------+
Invariante: Pro AutoWorkflow maximal 1 AutoVersion mit status=PUBLISHED.
Scheduler nutzt immer die PUBLISHED AutoVersion.
```
### Run-Modell
```python
class AutoRunStatus(str, Enum):
PENDING = "pending"
RUNNING = "running"
PAUSED = "paused"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class AutoRun(PowerOnModel):
id: str
workflowId: str # FK -> AutoWorkflow
versionId: str # FK -> AutoVersion
status: AutoRunStatus
trigger: Dict[str, Any] # { type: "manual"|"schedule"|"webhook"|..., metadata }
startedAt: float
completedAt: Optional[float]
nodeOutputs: Dict[str, Any] # Outputs pro Node-ID
currentNodeId: Optional[str] # Paused bei diesem Node
resumeContext: Dict[str, Any] # Kontext fuer Resume
error: Optional[str]
costTokens: Optional[int] # Aggregierte Token-Kosten
costCredits: Optional[float] # Aggregierte Credit-Kosten
```
### State Machine: AutoRun.status
```
+---------+
executeGraph-->| RUNNING |
+----+----+
|
+----------------+----------------+
| | |
v v v
+--------+ +----------+ +--------+
| PAUSED | |COMPLETED | | FAILED |
+---+----+ +----------+ +--------+
|
| resume(taskResult | emailReceived)
v
+---------+
| RUNNING |---> COMPLETED | FAILED | PAUSED | CANCELLED
+---------+
Pause-Gruende:
- input.* Node -> AutoTask erstellt
- email.checkEmail -> EmailWait (Background Poller)
Cancel:
- Manuell durch User
- Timeout bei AutoTask (expiresAt)
```
### AutoStepLog und AutoTask
```python
class AutoStepStatus(str, Enum):
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
SKIPPED = "skipped"
class AutoStepLog(PowerOnModel):
id: str
runId: str # FK -> AutoRun
nodeId: str # Node-ID im Graph
nodeType: str # z.B. "ai.prompt", "email.checkEmail"
status: AutoStepStatus
inputSnapshot: Dict[str, Any] # Parameters + Upstream-Daten bei Execution
output: Optional[Dict[str, Any]]
error: Optional[str]
startedAt: float
completedAt: Optional[float]
durationMs: Optional[int]
tokensUsed: Optional[int]
retryCount: int = 0
class AutoTaskStatus(str, Enum):
PENDING = "pending"
COMPLETED = "completed"
CANCELLED = "cancelled"
EXPIRED = "expired"
class AutoTask(PowerOnModel):
id: str
runId: str # FK -> AutoRun
workflowId: str # FK -> AutoWorkflow (Convenience-FK)
nodeId: str
nodeType: str # input.approval, input.form, etc.
config: Dict[str, Any] # Node-Parameter (Formular-Felder, Approval-Text)
assigneeId: str
status: AutoTaskStatus
result: Optional[Dict[str, Any]]
expiresAt: Optional[float]
```
### ER-Diagramm
```
+------------------+ +----------------------+
| AutoWorkflow | 1---N | AutoVersion |
|------------------| |----------------------|
| id | | id |
| mandateId | | workflowId (FK) |
| featureInstanceId| | versionNumber |
| label | | status |
| description | | graph {} |
| tags [] | | invocations [] |
| isTemplate | | publishedAt |
| currentVersionId +---1-->| publishedBy |
| active | +----------+-----------+
| eventId | | 1:N
+------------------+ +----------v-----------+
| AutoRun |
|----------------------|
| id |
| workflowId (FK) |
| versionId (FK) |
| status |
| trigger {} |
| nodeOutputs {} |
| currentNodeId |
| resumeContext {} |
| costTokens |
| costCredits |
+----------+-----------+
1:N | | 1:N
+-------------+ +-----------+
v v
+------------------+ +------------------+
| AutoStepLog | | AutoTask |
|------------------| |------------------|
| runId (FK) | | runId (FK) |
| nodeId | | workflowId (FK) |
| nodeType | | nodeId |
| status | | config {} |
| inputSnapshot {} | | assigneeId |
| output {} | | status |
| durationMs | | result {} |
| tokensUsed | | expiresAt |
| retryCount | +------------------+
+------------------+
```
---
## Workflow-Vorlagen (Template-Management)
Vorlagen sind spezielle AutoWorkflows (oder dedizierte Template-Entitaeten mit Referenz auf eine `AutoVersion`), die als Wiederverwendbare Startpunkte dienen. Das Template-Management ist Teil der Automation-Unification: ein einheitliches Modell fuer Erstellung, Scope, Bootstrap und Freigabe.
### Anforderungen (Produktlogik)
| Aspekt | Regel |
|--------|--------|
| **Zugehoerigkeit** | Jede Vorlage gehoert zu genau einer **Feature-Instanz** (`featureInstanceId`); der **Ersteller** entspricht wie bei allen Modellen den systemseitig gepflegten Feldern der **Basis-Klasse** (z.B. `sysCreatedBy`). |
| **Scope** | Jede Vorlage hat einen **Template-Scope**: `user`, `instance`, `mandate`, `system`. Der Scope steuert Sichtbarkeit, RBAC und ob Inhalte gemeinsam nutzbar oder nur persoenlich sind. |
| **Default bei Erstellung** | Ohne explizite Abweichung: **Instanz** = Instanz des aktuellen Users (Kontext der UI/API); **Scope** = `user` (persoenliche Vorlage). |
| **Bootstrap** | Initiale Plattform-Vorlagen werden beim Bootstrap mit Scope **`system`** angelegt, technisch durch den User **`sysadmin`** (oder dedizierter System-Principal), damit sie mandantenuebergreifend policy-konform verwaltbar sind. |
| **Teilen (1) -- Kopie** | Eine Vorlage (oder Snapshot einer Version) kann als **Kopie** an einen anderen User gesendet werden. Die Kopie ist eine **neue** Vorlage im Scope `user` des Empfaengers; Ersteller-Felder der Basis-Klasse zeigen den Empfaenger, plus Instanz-Kontextregeln beim Import. |
| **Teilen (2) -- Freigabe** | Statt Kopie: **Freigabe zur gemeinsamen Nutzung** mit Scope **`instance`** oder **`mandate`**. Alle Berechtigten duerfen die Vorlage **nutzen** (z.B. Workflow daraus ableiten, starten); sie duerfen die **freigegebene Vorlage selbst nicht aendern** (kein Update/Delete der Canonical-Definition ausser fuer Rollen mit explizitem Schreibrecht laut unten). |
### RBAC nach Rolle (Feature- und Plattform-Rollen)
**Regel:** **CRUD** nur auf der Spalte, die zum **Template-Scope** der Vorlage passt (und bei `user` nur auf **eigenen** Vorlagen). Alle anderen Spalten: **R** = lesen und nutzen, **keine** Aenderung der Vorlagen-Definition.
| Rolle | `user` (nur **eigene**) | `instance` | `mandate` | `system` |
|-------|-------------------------|------------|-----------|----------|
| Alle Rollen (mit Feature-Zugriff) | CRUD | R | R | R |
| Instance Admin | CRUD | CRUD | R | R |
| Mandate Admin | CRUD | CRUD | CRUD | R |
**Sysadmin:** **CRUD** auf `system`-Vorlagen; fuer `user` / `instance` / `mandate` nach Plattform-Policy (Break-Glass / Support).
**Hinweis:** Abbildung auf `AccessRule` (DATA + RESOURCE „instanziieren/ausfuehren“) in der Implementierung.
### Datenmodell-Erweiterung (Vorschlag)
Ergänzung zum `AutoWorkflow`-Modell (bereits `isTemplate`, `templateSourceId`):
```python
class AutoTemplateScope(str, Enum):
USER = "user" # persoenlich; „eigen“ = Ersteller laut Basis-Klasse (z.B. sysCreatedBy)
INSTANCE = "instance" # gemeinsam nutzbar auf Feature-Instanz
MANDATE = "mandate" # gemeinsam nutzbar im Mandanten
SYSTEM = "system" # plattformweit, verwaltet durch sysadmin
class AutoWorkflow(PowerOnModel):
# ... bestehende Felder ...
isTemplate: bool = False
templateSourceId: Optional[str]
templateScope: Optional[AutoTemplateScope] # gesetzt wenn isTemplate True
sharedReadOnly: bool = False # True bei Freigabe: Nutzer duerfen nicht mutieren
```
- **Kopie an User:** neuer `AutoWorkflow` mit `templateSourceId` = Quelle, `templateScope=USER`; Ersteller = Empfaenger ueber Basis-Klassen-Felder beim Anlegen.
- **Freigabe:** Scope auf `INSTANCE` oder `MANDATE` setzen, `sharedReadOnly=True` fuer Nicht-Admins; Admins mit CRUD laut Matrix duerfen weiterhin Pflege betreiben.
### Konsistenz: ist die Logik stimmig?
**Ja, insgesamt konsistent**, wenn diese Punkte explizit gemacht werden:
1. **`my` = nur eigene User-Scope-Vorlagen** (Abgleich Ersteller mit aktuellem User ueber Basis-Felder, z.B. `sysCreatedBy`). Ohne diese Einschraenkung waere „alle Rollen: CRUD“ auf `user`-Scope widerspruechlich.
2. **„R“ bei Freigabe** umfasst fachlich **Lesen + Nutzen** (Instanziierung/Ableiten); **kein Update/Delete** der Canonical-Vorlage fuer Nicht-Admins -- passt zur Anforderung „nur nutzen, nicht veraendern“.
3. **Instance Admin vs. Mandate Admin:** Die Matrix codiert die Grenze: **CRUD** nur in der passenden Scope-Spalte; kreuzweise immer **R**.
4. **Sysadmin und `system`-Bootstrap:** Konsistent, solange Bootstrap-Vorlagen eindeutig `templateScope=SYSTEM` und von `sysadmin` stammen; normale User koennen `system`-Vorlagen nicht umschreiben.
5. **Begriff „alle Rollen“:** Im Kontext **Feature-Instanz** natürlich
**Viewer**-Rollen Vorlagen haben keine Rechte hier.
**Kopie senden** kann an einen user sein, den ich mit meinen berechtigungen "sehe"
---
## Graph-Struktur und Node-Definitionen
### Graph-Schema (innerhalb AutoVersion.graph)
```json
{
"nodes": [
{
"id": "node-uuid",
"type": "trigger.schedule",
"position": { "x": 100, "y": 200 },
"parameters": { "cronExpression": "0 8 * * 1-5" }
},
{
"id": "node-uuid-2",
"type": "ai.prompt",
"position": { "x": 300, "y": 200 },
"parameters": { "prompt": "Analysiere die Emails..." }
}
],
"connections": [
{ "source": "node-uuid", "target": "node-uuid-2", "sourceOutput": 0, "targetInput": 0 }
]
}
```
### Node-Type zu Method/Action Mapping
| Node Type | `_method` | `_action` | `_paramMap` |
|-----------|-----------|-----------|-------------|
| `trigger.manual` | -- | -- | -- (TriggerExecutor) |
| `trigger.schedule` | -- | -- | -- (TriggerExecutor) |
| `trigger.form` | -- | -- | -- (TriggerExecutor) |
| `flow.ifElse` | -- | -- | -- (FlowExecutor) |
| `flow.switch` | -- | -- | -- (FlowExecutor) |
| `flow.loop` | -- | -- | -- (FlowExecutor) |
| `input.*` | -- | -- | -- (InputExecutor -> AutoTask) |
| `ai.prompt` | `ai` | `process` | `prompt->aiPrompt` |
| `ai.webResearch` | `ai` | `webResearch` | `query->prompt` |
| `ai.summarizeDocument` | `ai` | `summarizeDocument` | -- |
| `ai.translateDocument` | `ai` | `translateDocument` | `targetLanguage->targetLanguage` |
| `ai.generateDocument` | `ai` | `generateDocument` | `prompt->prompt` |
| `email.checkEmail` | `outlook` | `readEmails` | `connectionId->connectionReference` |
| `email.searchEmail` | `outlook` | `searchEmails` | `connectionId->connectionReference` |
| `email.draftEmail` | `outlook` | `composeAndDraft...` | `connectionId->connectionReference` |
| `sharepoint.*` | `sharepoint` | entsprechend | `connectionId->connectionReference` |
| `clickup.*` | `clickup` | entsprechend | `connectionId->connectionReference` |
| `file.create` | `file` | `create` | `template->template` |
| `trustee.extractFromFiles` | `trustee` | `extractFromFiles` | `connectionId->connectionReference` |
| `trustee.processDocuments` | `trustee` | `processDocuments` | `documentList->documentList` |
| `trustee.syncToAccounting` | `trustee` | `syncToAccounting` | `documentList->documentList` |
### Execution-Routing
```
executeGraph(graph, services, ...)
|
+-- parseGraph() -> nodes, connections, nodeIds
+-- validateGraph() -> Konsistenzpruefung
+-- topoSort(nodes, connectionMap) -> geordnete Node-Liste
|
+-- Pro Node:
|
+-- nodeType.startsWith("trigger.") -> TriggerExecutor
+-- nodeType.startsWith("flow.") -> FlowExecutor
| ifElse: evaluiert Bedingung, setzt active path
| switch: evaluiert Match, setzt active path
| loop: iteriert mit _loopState
+-- nodeType.startsWith("input.") -> InputExecutor
| -> erstellt AutoTask, setzt Run auf PAUSED
+-- alles andere -> ActionNodeExecutor
+-- _getNodeDefinition(nodeType) -> _method, _action, _paramMap
+-- Parameter-Mapping (Node-Params -> Action-Params)
+-- Upstream-Daten mergen (documents von vorherigen Nodes)
+-- ActionExecutor.executeAction(method, action, params)
```
---
## Konsolidierter Scheduler (Ziel)
```python
class WorkflowScheduler:
def start(self, eventUser):
eventManager.start()
self._syncScheduledWorkflows(eventUser)
self._registerDelayedSync(eventUser, delaySeconds=5)
callbackRegistry.register("workflow.changed",
lambda _: self._syncScheduledWorkflows(eventUser))
def _syncScheduledWorkflows(self, eventUser):
"""Inkrementeller Sync (v1-Pattern)."""
workflows = self._getAllSchedulableWorkflows()
for wf in workflows:
jobId = f"workflow.{wf.id}"
if wf.active and wf.currentVersionId:
version = self._getPublishedVersion(wf.currentVersionId)
cronKwargs = self._extractSchedule(version)
if cronKwargs:
handler = self._createHandler(wf, version, eventUser)
eventManager.registerCron(
jobId=jobId, func=handler,
cronKwargs=cronKwargs,
replaceExisting=True # v1-Pattern: atomic replace
)
if wf.eventId != jobId:
self._updateEventId(wf.id, jobId)
else:
self._removeJob(jobId)
if wf.eventId:
self._updateEventId(wf.id, None)
def _createHandler(self, wf, version, eventUser):
"""Handler: Reload + Active-Check + Execute (v1-Pattern)."""
async def _handler():
current = self._getWorkflow(wf.id)
if not current or not current.active:
return
services = self._buildServices(current, eventUser)
result = await executeGraph(graph=version.graph, services=services, ...)
self._appendExecutionLog(current.id, result) # capped audit trail
return self._wrapAsync(_handler) # Thread-Bridge (v2-Pattern)
```
---
## Use Cases
### UC-1: Workflow im Workspace erstellen/bearbeiten
User beschreibt im Workspace-Chat einen gewuenschten Workflow -> Agent nutzt Toolbox `"workflow"` -> generiert Graph -> speichert als Draft -> User oeffnet im Graphical Editor.
Voraussetzung: Die `"workflow"` Toolbox muss im Workspace aktivierbar sein. Die Tools validieren jeden Graph-Mutationsschritt:
- `addNode(type, parameters)` -> prueft: existiert der Node-Typ? Sind die Parameter valide?
- `connectNodes(source, target)` -> prueft: sind die I/O-Typen kompatibel? Keine Zyklen?
- `validateGraph()` -> vollstaendige Validierung inkl. Trigger-Pruefung
### UC-2: AI Chat im Graphical Editor
Sidebar mit Chat. Agent nutzt Toolbox `"workflow"` mit System-Prompt, der den aktuellen Graph kennt. Er kann Nodes hinzufuegen, entfernen, umkonfigurieren und den Graph erklaeren. Gleicher `serviceAgent.runAgent()` Pfad wie Workspace, aber mit `toolboxes: ["core", "workflow"]` und Graph als Kontext im System-Prompt.
### UC-3: Workflow testen mit Tracing Log
User klickt "Test Run" -> Graph wird ausgefuehrt -> jeder Node wird visuell hervorgehoben (Status-Farben) -> Tracing Log zeigt pro Node: Input, Output, Dauer, Fehler. Bei Fehlern: User bespricht den Fehler im AI Chat -> Agent liest AutoStepLog und schlaegt Korrekturen vor.
**Technisch:** `AutoStepLog` pro Node mit Timestamps, Input-Snapshot, Duration, Error-Stack. SSE/WebSocket fuer Live-Updates. Run-Modes: "Full Run" und "Step-by-Step" (Pause nach jedem Node).
### UC-4: Workflow automatisieren (Scheduler)
User konfiguriert Schedule im Editor (via trigger.schedule Node oder Invocation) -> konsolidierter Scheduler registriert Cron-Job -> Run-History wird persistiert -> bei Fehlern Notifications.
---
## Backend Code-Struktur (Ziel)
```
gateway/modules/
|
+-- features/
| +-- graphicalEditor/ <-- NEUES FEATURE (ersetzt automation2)
| | +-- mainGraphicalEditor.py
| | | FEATURE_CODE = "graphicalEditor"
| | | UI_OBJECTS = ["ui.feature.graphicalEditor.editor",
| | | "ui.feature.graphicalEditor.workflows",
| | | "ui.feature.graphicalEditor.tasks"]
| | | RESOURCE_OBJECTS = ["resource.feature.graphicalEditor.execute",
| | | "resource.feature.graphicalEditor.schedule"]
| | | TEMPLATE_ROLES = ["graphicalEditor-admin",
| | | "graphicalEditor-user",
| | | "graphicalEditor-viewer"]
| | +-- routeFeatureGraphicalEditor.py (prefix: /api/workflows)
| | +-- interfaceFeatureGraphicalEditor.py (DB: poweron_workflows)
| | +-- datamodelFeatureGraphicalEditor.py
| | +-- nodeDefinitions/
| | triggers.py, flow.py, input.py, ai.py, email.py, sharepoint.py, clickup.py, file.py, trustee.py
| |
| +-- workspace/ <-- BLEIBT (AI Chat mit UDB)
| +-- commcoach/ <-- BLEIBT
| +-- chatbot/ <-- BLEIBT
| +-- trustee/ <-- BLEIBT
|
+-- serviceCenter/services/
| +-- serviceAgent/
| | +-- mainServiceAgent.py <-- Core Tools + Toolbox-Tagging
| | +-- agentLoop.py <-- Toolbox-Filtering statt toolSet
| | +-- toolRegistry.py <-- BLEIBT
| | +-- toolboxRegistry.py <-- NEU: Toolbox-Verwaltung
| | +-- actionToolAdapter.py <-- BLEIBT (+ Toolbox-Zuordnung)
| | +-- featureDataAgent.py <-- BLEIBT (Sub-Agent Pattern)
| | +-- datamodelAgent.py <-- toolboxes: List[str] statt toolSet
|
+-- workflows/
| +-- methods/ <-- BLEIBT (Unified Action Library)
| +-- processing/ <-- BLEIBT (ActionExecutor, methodDiscovery)
| +-- automation2/ <-- Graph Engine BLEIBT (executionEngine)
| +-- scheduler/ <-- NEU (konsolidierter Scheduler, Phase 4)
| | +-- mainScheduler.py
| +-- workflowManager.py <-- BLEIBT (fuer Workspace Dynamic Mode)
```
---
## Frontend Code-Struktur (umgesetzt)
```
frontend_nyla/src/
|
+-- components/ <-- SHARED COMPONENTS
| +-- UnifiedDataBar/ <-- BLEIBT (Files + Sources Tabs, Mandate-gefiltert)
| +-- FlowEditor/ <-- Umgesetzt (ehemals Automation2FlowEditor)
| +-- editor/
| Automation2FlowEditor.tsx Hauptkomponente mit 3-Column Layout
| CanvasHeader.tsx Neu/Speichern/Vorlage/Version-Buttons
| EditorChatPanel.tsx AI Chat mit File/Source-Attachments
| RunTracingPanel.tsx Step-Log-Anzeige mit SSE Live-Push + Canvas-Highlighting
| NodeConfigPanel.tsx Node-Konfiguration (inkl. Trustee)
| TemplatePicker.tsx Modal: Vorlage auswaehlen
| +-- nodes/configs/
| TrusteeNodeConfig.tsx Trustee-Node-Konfiguration
| index.ts NODE_CONFIG_REGISTRY
| +-- index.ts Exports (PendingFile, EditorDataSource, etc.)
|
+-- pages/views/
| +-- workspace/
| | WorkspacePage.tsx Nutzt ChatBar, ChatStream, UDB
| +-- graphicalEditor/ <-- Umgesetzt (ehemals automation2)
| GraphicalEditorPage.tsx FlowEditor + UDB + State-Management
| GraphicalEditorWorkflowsPage.tsx Workflow-Liste mit Umbenennen
| GraphicalEditorTemplatesPage.tsx Vorlagen mit Scope-Verwaltung
| GraphicalEditorTasksPage.tsx
|
+-- api/
workflowApi.ts <-- Konsolidiert (Templates, Versions, Workflows)
```
---
## Empfehlungen und offene Punkte
### Starke Konzepte (umsetzen)
| Konzept | Bewertung |
|---------|-----------|
| **Toolbox-Architektur** | Skaliert von 50 auf 100+ Tools ohne LLM-Ueberlastung. Klare Isolierung. |
| **Sub-Agents pro Feature** | Bewaehrtes Pattern (Trustee), erweiterbar. Haelt Main Agent schlank. |
| **Validierungs-Layer fuer Workflow-Modellierung** | Graph-Mutation nur ueber validierte Tools. |
| **v1-Scheduling-Patterns in v2 uebernehmen** | Inkrementeller Sync ist robuster als Full-Wipe. |
| **State Machines als Grundlage** | Klare Zustaende, klare Uebergaenge. Erweiterbar. |
### Was User brauchen
| User Need | Feature | Prioritaet |
|-----------|---------|-----------|
| **Schneller Einstieg** | Workflow-Templates fuer haeufige Use Cases | Hoch |
| **Vertrauen** | Tracing Log + Test Runner | Hoch |
| **Effizienz** | AI-gestuetzte Workflow-Erstellung per Chat | Hoch |
| **Fehlertoleranz** | Retry-Policies, Pause/Resume, klare Fehlermeldungen | Hoch |
| **Kontext** | UDB im Editor -- Zugriff auf Files/Sources bei Konfiguration | Hoch |
| **Zusammenarbeit** | Workflows teilen im Mandant, Rollen-basierter Zugriff | Mittel |
| **Monitoring** | Dashboard: laufende Automationen, Fehlerrate, Kosten | Mittel |
| **Flexibilitaet** | Custom Script Nodes (Python-Sandbox), AI Decision Nodes | Mittel |
| **Mobile** | Notifications + Approval-Tasks per Mobile | Phase 2 |
### Offene Architektur-Fragen
| Frage | Empfehlung |
|-------|------------|
| **Toolbox-Selektion: statisch oder dynamisch?** | Hybrid: Basis pro Feature statisch, Connection-basierte dynamisch. |
| **Sub-Agent Tiefe: verschachtelt?** | Maximal 1 Level tief. Kein Sub-Sub-Agent. |
| **Graph-Execution und WorkflowManager zusammenfuehren?** | Nein, getrennt. `executeGraph` fuer Editor, `WorkflowManager` fuer Workspace Dynamic Mode. |
| **Feature-Code: `automation2` -> `graphicalEditor`?** | Ja, Rename in Phase 1. |
---
## Phasen-Plan
### Phase 1: Foundation -- ABGESCHLOSSEN (2026-04-05 bis 2026-04-07)
- [x] Unified Workflow Datenmodell (AutoWorkflow + AutoVersion + AutoRun + AutoStepLog + AutoTask)
- [x] Greenfield DB `poweron_graphicaleditor`
- [x] Feature Rename: `automation2` -> `graphicalEditor`
- [x] Legacy-Features `automation` und `automation2` entfernt
- [x] Bootstrap-Prozess konsolidiert und idempotent gemacht
- [x] Boot-Performance optimiert (30s -> 22s)
### Phase 2: Editor Enhancement -- ABGESCHLOSSEN (2026-04-07)
- [x] AI Chat Sidebar im Editor (EditorChatPanel mit SSE, Graph-Manipulation)
- [x] UDB Integration im Editor (Files + Sources Tabs, Mandate-gefiltert)
- [x] AutoVersion Lifecycle (Draft/Published/Archived) im CanvasHeader
- [x] Tracing Panel im Editor (RunTracingPanel)
- [x] File/Source-Attachments im AI Chat (Drag&Drop + Source-Picker wie im Workspace)
- [x] 3-Column Layout: [UDB] [Chat/Tracing] [Canvas] [Nodes]
### Phase 3: Productization -- ABGESCHLOSSEN (2026-04-07)
- [x] Workflow-Vorlagen: Template-Management mit Scope (user/instance/mandate/system)
- [x] System-Template Bootstrap (2 Vorlagen: Personal Assistant, Treuhand)
- [x] Trustee Node-Types (extractFromFiles, processDocuments, syncToAccounting)
- [x] "Als Vorlage speichern" + "Neu aus Vorlage" im Editor
- [x] Scope-Aenderung (erweitern + zuruecknehmen) in Templates-Verwaltung
- [x] Umbenennen von Workflows und Templates
- [x] KeepAlive-Navigation-Fix (Workflow-Laden bei URL-Parameter-Aenderung)
- [ ] Marketplace / Katalog (optional, auf Basis derselben Vorlagen-API)
- [ ] Monitoring Dashboard
- [ ] Retry Policies pro Node
- [ ] Notifications bei Scheduler-Fehlern
### Phase 4: Advanced -- ABGESCHLOSSEN (2026-04-07)
- [x] Toolbox Registry: Tool-Listen fuer alle 8 Toolboxes befuellt, `requestToolbox` Meta-Tool mit Runtime-Refresh in agentLoop
- [x] Scheduler: `subAutomation2Schedule` aus `app.py` entfernt, `/schedule-sync` auf `WorkflowScheduler.syncNow` migriert, Billing-Init in Bootstrap verschoben
- [x] Enhanced AutoStepLog: InputSnapshot fuer Loops/Skipped/alle Pfade, I/O im UI (CollapsibleSection), Live-Push via SSE, Graph-Hervorhebung pro Step, Timestamps + RetryCount
- [x] `app.py` Cleanup: keine feature-spezifischen Imports/Logik mehr (Scheduler, EmailPoller, Billing)
- [ ] AI Decision Node (`ai.decide`)
- [ ] Custom Script Node (Python Sandbox)
- [ ] Sub-Agent Pattern fuer weitere Features
---
## Betroffene Module
- Gateway: `features/graphicalEditor/`, `workflows/`, `serviceCenter/services/serviceAgent/`, `interfaces/interfaceBootstrap.py`
- Frontend: `components/FlowEditor/`, `pages/views/graphicalEditor/`, `components/UnifiedDataBar/`
- Entfernt: `features/automation/`, `features/automation2/`, `components/Automation2FlowEditor/`, `pages/views/automation2/`
- DB-Migration: nein (Greenfield -- neue DB `poweron_graphicaleditor`, keine Migration von `poweron_automation2`)
- Andere: Scheduler (APScheduler/eventManager), RBAC Template-Rollen
## Entscheidungen
| Datum | Entscheidung | Begruendung |
|-------|-------------|------------|
| 2026-04-05 | v1-Scheduler-Pattern in v2 uebernehmen | Robuster (inkrementell, Job-Handle, Reload+active-Check) |
| 2026-04-05 | Toolbox-Konzept statt flache Tool-Listen | Skalierbarkeit bei 50-100+ Tools |
| 2026-04-05 | Keine v1-Datenmigration | v1 nicht produktiv |
| 2026-04-05 | Feature-Code `automation2` -> `graphicalEditor` | Klarer Name fuer User und Entwickler |
| 2026-04-05 | Graph-Execution und WorkflowManager getrennt lassen | Verschiedene Orchestrierungsmodelle |
| 2026-04-05 | Sub-Agent maximal 1 Level tief | Komplexitaet kontrollierbar |
| 2026-04-06 | Workflow-Vorlagen mit Scope + getrenntem RBAC; `my` = nur eigene User-Scope-Vorlagen | Einheitliches Teilen (Kopie vs. read-only Freigabe) ohne Widerspruch zu Mandant/Instanz |
| 2026-04-06 | `Auto`-Prefix fuer alle Datenobjekte (AutoWorkflow, AutoVersion, AutoRun, AutoStepLog, AutoTask) | Eindeutige Erkennbarkeit in der Codebase; kein Namenskonflikt mit bestehenden Modellen |
| 2026-04-06 | Greenfield-Migration statt DB-Schema-Umbau | Neue DB `poweron_graphicaleditor`; `poweron_automation2` bleibt als Archiv; kein Migrationsrisiko |
| 2026-04-07 | Legacy-Features `automation` und `automation2` entfernt | Konsolidierung abgeschlossen; kein Altcode mehr im Gateway/Frontend |
| 2026-04-07 | Bootstrap idempotent gemacht (`_bootstrapDone` Flag) | Verhindert doppelte Ausfuehrung; `_initRecords` Workaround entfernt |
| 2026-04-07 | Stripe/APScheduler Debug-Logging unterdrueckt | Boot-Performance: 30s -> 22s; AI Pre-Warming dedupliziert |
| 2026-04-07 | UDB Data Sources Mandate-gefiltert | Verhindert Cross-Mandate-Datenlecks bei Active Data Sources |
| 2026-04-07 | Trustee Node-Types im Editor | 3 neue Nodes (extract, process, sync) fuer Treuhand-Workflows |
| 2026-04-07 | System-Templates im Bootstrap | 2 Vorlagen (Personal Assistant, Treuhand) als Startpunkt fuer neue User |
| 2026-04-07 | Template Scope-Aenderung bidirektional | Scope kann erweitert und zurueckgenommen werden; `sharedReadOnly` dynamisch |
| 2026-04-07 | `app.py` als generischer Entry-Point | Keine feature-spezifischen Imports; Scheduler/EmailPoller/Billing in Feature-Lifecycle bzw. Bootstrap |
| 2026-04-07 | SSE Live-Push fuer Run-Tracing | `EventManager`-Queue pro Run; Fallback auf Polling bei SSE-Fehler |
| 2026-04-07 | Canvas Graph-Hervorhebung | `highlightedNodeIds` Prop; farbcodiert nach Step-Status; Glow-Animation bei `running` |
| 2026-04-07 | `requestToolbox` als Meta-Tool | Agent kann zur Laufzeit Toolboxes anfordern; `agentLoop` refresht `toolDefinitions` nach Aufruf |
## Umsetzungs-Checkliste
- [x] Vereinheitlichtes Schema: AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask (Greenfield DB `poweron_graphicaleditor`)
- [x] Feature-Code Rename `automation2` -> `graphicalEditor` (Backend + Frontend)
- [x] Frontend: UDB im Graph-Editor (UnifiedDataBar mit Files + Sources Tabs)
- [x] Frontend: AI Chat Sidebar im Editor (EditorChatPanel mit SSE-Streaming, Graph-Manipulation-Tools)
- [x] Frontend: Tracing Panel im Editor (RunTracingPanel mit Step-Log-Anzeige)
- [x] Frontend: Version Management im Editor (Draft/Published/Archived Lifecycle via CanvasHeader)
- [x] Vorlagen: `templateScope` (user/instance/mandate/system), Freigabe/Kopie, Scope-Aenderung
- [x] Vorlagen: System-Template Bootstrap (`_bootstrapSystemTemplates` in `interfaceBootstrap.py`)
- [x] Vorlagen: 2 System-Templates (Personal Assistant E-Mail-Drafting, Treuhand PDF-Klassifizierung)
- [x] Vorlagen: "Als Vorlage speichern" Button im Editor mit Scope-Auswahl
- [x] Vorlagen: "Neu aus Vorlage" Template-Picker-Modal im Editor
- [x] Vorlagen: Scope-Aenderung (erweitern + zuruecknehmen) in Templates-Seite
- [x] Vorlagen: Umbenennen von Workflows und Templates in den jeweiligen Verwaltungsseiten
- [x] Trustee Node-Types: `trustee.extractFromFiles`, `trustee.processDocuments`, `trustee.syncToAccounting`
- [x] Node-Config Frontend: TrusteeNodeConfig.tsx mit Connection/Folder/Prompt-Feldern
- [x] Legacy-Features `automation` und `automation2` aus Gateway und Frontend entfernt
- [x] Bootstrap: Idempotenter `initBootstrap` mit `_bootstrapDone` Flag
- [x] Bootstrap: Redundanter `_initRecords` Fallback in `interfaceDbApp.py` entfernt
- [x] Boot-Performance: Stripe/APScheduler Debug-Logging unterdrueckt, AI Pre-Warming dedupliziert (30s -> 22s)
- [x] UDB: Mandate-Filter fuer Active Data Sources und Feature Data Sources
- [x] KeepAlive: Workflow-Laden bei Navigation von Workflows-Seite zum Editor (URL-Parameter reaktiv)
- [x] RBAC Template-Rollen fuer graphicalEditor (admin/user/viewer)
- [x] Toolbox Registry: Tool-Listen befuellt (core/ai/datasources/email/sharepoint/clickup/jira/workflow), `requestToolbox` Meta-Tool implementiert, `_activateToolboxes` generisch
- [x] Scheduler-Konsolidierung: `subAutomation2Schedule` entfernt, `/schedule-sync` migriert auf `WorkflowScheduler.syncNow`, `app.py` bereinigt
- [x] AutoStepLog + Enhanced Visual Tracing: InputSnapshot fuer alle Pfade (Loops, Skipped), I/O CollapsibleSections im UI, Live-Push via SSE (`/runs/{runId}/stream`), Graph-Hervorhebung (Canvas Highlighting), Timestamps + RetryCount
- [ ] Neutralisierung: keine Aenderung (nutzt gleiche Services)
- [ ] Billing-Impact: pruefen (Automation-Runs zaehlen?)
## Akzeptanzkriterien
| # | Kriterium (Given-When-Then) | Prio |
|---|---------------------------|------|
| 1 | Given ein Automation2-Workflow mit Schedule, When der Scheduler neu startet, Then werden nur geaenderte Jobs aktualisiert (inkrementell wie v1) | must |
| 2 | Given ein Agent mit 50+ Tools, When der Agent startet, Then sind nur core-Toolboxes geladen und Spezial-Toolboxes werden on-demand nachgeladen | should |
| 3 | Given ein Workflow-Run, When ein Human-Task-Node erreicht wird, Then pausiert der Run und wartet auf User-Input | must |
| 4 | Given ein Workflow-Graph im Editor, When der User im AI-Chat "Fuege einen Email-Check hinzu" tippt, Then fuegt der Agent einen email.checkEmail Node ein und verbindet ihn korrekt | should |
| 5 | Given ein Workflow mit Published Version, When der User den Graph editiert, Then wird ein neuer Draft erstellt und die Published Version bleibt aktiv | must |
## Testplan
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | gateway/tests/test_automation2_scheduler.py | pending |
| T2 | 2 | integration | ja | gateway/tests/test_agent_toolbox.py | pending |
| T3 | 3 | api | ja | gateway/tests/test_workflow_pause_resume.py | pending |
| T4 | 4 | integration | ja | gateway/tests/test_editor_chat_graph.py | pending |
| T5 | 5 | unit | ja | gateway/tests/test_workflow_versioning.py | pending |
## Glossar
| Begriff | Definition |
|---------|-----------|
| **Toolbox** | Thematisch gebuendelte Gruppe von AI-Tools, kontextabhaengig aktiviert |
| **Sub-Agent** | Spezialisierter Mini-Agent mit eigener Tool-Registry, aufgerufen vom Main Agent |
| **AutoWorkflow** | Persistiertes Automatisierungsmodell mit Graph-Struktur |
| **AutoVersion** | Immutable Snapshot eines Workflow-Graphen (draft, published, archived) |
| **AutoRun** | Einzelne Ausfuehrung einer AutoVersion |
| **AutoStepLog** | Detaillierter Log pro Node-Execution innerhalb eines Runs |
| **AutoTask** | Aufgabe fuer menschliche Eingabe, erstellt bei Pause eines Runs |
| **AutoTemplateScope** | `user` \| `instance` \| `mandate` \| `system` -- steuert Sichtbarkeit und RBAC von Workflow-Vorlagen |
| **Node** | Ausfuehrungsschritt im Graph (Trigger, Action, Flow-Control, Input/Human) |
| **Method** | Integrations-Kategorie (z.B. methodOutlook) mit mehreren Actions |
| **Action** | Spezifische Operation innerhalb einer Method (z.B. outlook.readEmails) |
| **Invocation** | Entry-Point fuer einen Workflow (Manual, Schedule, Webhook, Form, Event) |
| **UDB** | Unified Data Bar -- Multi-Tab-Panel fuer Chats, Files und Sources |
| **ChatBar** | Wiederverwendbare Prompt-Input-Komponente |
| **Feature Container** | Einheitliches Verzeichnis-Pattern fuer ein Feature |
## Links
- Detail-Spec (Business): z-archive/b-reference/automation-business-spec.md
- Detail-Spec (Datenmodell): z-archive/b-reference/automation-data-model.md
- Referenz (Ist-Zusammenfassung): b-reference/gateway/automation.md
## Abschluss
**Vollstaendiger Umbau abgeschlossen am 2026-04-07.** Phasen 1-4 umgesetzt.
**Phase 4 Umsetzung (2026-04-07):**
| Punkt | Umgesetzt |
|-------|-----------|
| **Toolbox Registry** | Tool-Listen fuer alle 8 Toolboxes befuellt (core: 20, ai: 9, datasources: 8, email: 5, sharepoint: 3, clickup: 3, jira: 3, workflow: 9). `requestToolbox` Meta-Tool mit Schema, Handler in `mainServiceAgent._registerRequestToolbox()`, Runtime-Refresh in `agentLoop.py`. `_activateToolboxes` generisch (entfernt inaktive Tools). |
| **Scheduler-Konsolidierung** | `subAutomation2Schedule` komplett aus `app.py` entfernt. `/schedule-sync` Endpoint migriert auf `WorkflowScheduler.syncNow()`. `setMainLoop` in `app.py` fuer Thread-Bridge. Billing-Init in `interfaceBootstrap._bootstrapBilling()` verschoben. EmailPoller-Stop in `mainGraphicalEditor.onStop()`. |
| **Enhanced AutoStepLog + Visual Tracing** | `inputSnapshot` fuer alle Pfade: Loop-Header, Loop-Body (`_loopItem`/`_loopIndex`), Resume-Path, Skipped-Nodes (`_skipReason`). RunTracingPanel: CollapsibleSection fuer Input/Output, Timestamps, RetryCount, Loop-Indikator. Live-Push via SSE (`GET /runs/{runId}/stream`) mit Fallback auf 3s-Polling. Canvas Graph-Hervorhebung: `highlightedNodeIds` Prop auf FlowCanvas, farbcodiert nach Status (running=gelb+Glow, completed=gruen, failed=rot, skipped=grau). |
**Verbleibende optionale Erweiterungen:**
- AI Decision Node (`ai.decide`)
- Custom Script Node (Python Sandbox)
- Sub-Agent Pattern fuer weitere Features
- [ ] b-reference/gateway/automation.md aktualisiert
- [ ] TOPICS.md aktualisiert
- [ ] Dieses Dokument -> z-archive/ verschoben