60 KiB
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
automationundautomation2wurden 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 aufpoweron_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.changedCallback-Pattern fuer reaktive Synchronisation- Handler laedt Workflow neu und prueft
activevor Execution - Execution-Logs als Audit Trail (capped auf 50 Eintraege)
- Creator-User Tracking via
sysCreatedByfuer Execution-Kontext
Von v2 beibehalten:
IntervalTriggerfuer 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:
- Lade Mandate-Rollen (via
UserMandate->UserMandateRole) - Lade Feature-Instanz-Rollen (via
FeatureAccess->FeatureAccessRole) - Lade
AccessRulesfuer alle gefundenen Rollen - Hoechste Prioritaet gewinnt bei DATA-Permissions
- View wird OR-verknuepft ueber alle Rollen der hoechsten Prioritaetsstufe
- Item-Spezifitaet innerhalb einer Stufe: exact > prefix > generic
RBAC-Datenmodell
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:
{
"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
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).
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
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
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):
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
AutoWorkflowmittemplateSourceId= Quelle,templateScope=USER; Ersteller = Empfaenger ueber Basis-Klassen-Felder beim Anlegen. - Freigabe: Scope auf
INSTANCEoderMANDATEsetzen,sharedReadOnly=Truefuer 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:
my= nur eigene User-Scope-Vorlagen (Abgleich Ersteller mit aktuellem User ueber Basis-Felder, z.B.sysCreatedBy). Ohne diese Einschraenkung waere „alle Rollen: CRUD“ aufuser-Scope widerspruechlich.- „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“.
- Instance Admin vs. Mandate Admin: Die Matrix codiert die Grenze: CRUD nur in der passenden Scope-Spalte; kreuzweise immer R.
- Sysadmin und
system-Bootstrap: Konsistent, solange Bootstrap-Vorlagen eindeutigtemplateScope=SYSTEMund vonsysadminstammen; normale User koennensystem-Vorlagen nicht umschreiben. - 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)
{
"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)
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)
- Unified Workflow Datenmodell (AutoWorkflow + AutoVersion + AutoRun + AutoStepLog + AutoTask)
- Greenfield DB
poweron_graphicaleditor - Feature Rename:
automation2->graphicalEditor - Legacy-Features
automationundautomation2entfernt - Bootstrap-Prozess konsolidiert und idempotent gemacht
- Boot-Performance optimiert (30s -> 22s)
Phase 2: Editor Enhancement -- ABGESCHLOSSEN (2026-04-07)
- AI Chat Sidebar im Editor (EditorChatPanel mit SSE, Graph-Manipulation)
- UDB Integration im Editor (Files + Sources Tabs, Mandate-gefiltert)
- AutoVersion Lifecycle (Draft/Published/Archived) im CanvasHeader
- Tracing Panel im Editor (RunTracingPanel)
- File/Source-Attachments im AI Chat (Drag&Drop + Source-Picker wie im Workspace)
- 3-Column Layout: [UDB] [Chat/Tracing] [Canvas] [Nodes]
Phase 3: Productization -- ABGESCHLOSSEN (2026-04-07)
- Workflow-Vorlagen: Template-Management mit Scope (user/instance/mandate/system)
- System-Template Bootstrap (2 Vorlagen: Personal Assistant, Treuhand)
- Trustee Node-Types (extractFromFiles, processDocuments, syncToAccounting)
- "Als Vorlage speichern" + "Neu aus Vorlage" im Editor
- Scope-Aenderung (erweitern + zuruecknehmen) in Templates-Verwaltung
- Umbenennen von Workflows und Templates
- 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)
- Toolbox Registry: Tool-Listen fuer alle 8 Toolboxes befuellt,
requestToolboxMeta-Tool mit Runtime-Refresh in agentLoop - Scheduler:
subAutomation2Scheduleausapp.pyentfernt,/schedule-syncaufWorkflowScheduler.syncNowmigriert, Billing-Init in Bootstrap verschoben - Enhanced AutoStepLog: InputSnapshot fuer Loops/Skipped/alle Pfade, I/O im UI (CollapsibleSection), Live-Push via SSE, Graph-Hervorhebung pro Step, Timestamps + RetryCount
app.pyCleanup: 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 vonpoweron_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
- Vereinheitlichtes Schema: AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask (Greenfield DB
poweron_graphicaleditor) - Feature-Code Rename
automation2->graphicalEditor(Backend + Frontend) - Frontend: UDB im Graph-Editor (UnifiedDataBar mit Files + Sources Tabs)
- Frontend: AI Chat Sidebar im Editor (EditorChatPanel mit SSE-Streaming, Graph-Manipulation-Tools)
- Frontend: Tracing Panel im Editor (RunTracingPanel mit Step-Log-Anzeige)
- Frontend: Version Management im Editor (Draft/Published/Archived Lifecycle via CanvasHeader)
- Vorlagen:
templateScope(user/instance/mandate/system), Freigabe/Kopie, Scope-Aenderung - Vorlagen: System-Template Bootstrap (
_bootstrapSystemTemplatesininterfaceBootstrap.py) - Vorlagen: 2 System-Templates (Personal Assistant E-Mail-Drafting, Treuhand PDF-Klassifizierung)
- Vorlagen: "Als Vorlage speichern" Button im Editor mit Scope-Auswahl
- Vorlagen: "Neu aus Vorlage" Template-Picker-Modal im Editor
- Vorlagen: Scope-Aenderung (erweitern + zuruecknehmen) in Templates-Seite
- Vorlagen: Umbenennen von Workflows und Templates in den jeweiligen Verwaltungsseiten
- Trustee Node-Types:
trustee.extractFromFiles,trustee.processDocuments,trustee.syncToAccounting - Node-Config Frontend: TrusteeNodeConfig.tsx mit Connection/Folder/Prompt-Feldern
- Legacy-Features
automationundautomation2aus Gateway und Frontend entfernt - Bootstrap: Idempotenter
initBootstrapmit_bootstrapDoneFlag - Bootstrap: Redundanter
_initRecordsFallback ininterfaceDbApp.pyentfernt - Boot-Performance: Stripe/APScheduler Debug-Logging unterdrueckt, AI Pre-Warming dedupliziert (30s -> 22s)
- UDB: Mandate-Filter fuer Active Data Sources und Feature Data Sources
- KeepAlive: Workflow-Laden bei Navigation von Workflows-Seite zum Editor (URL-Parameter reaktiv)
- RBAC Template-Rollen fuer graphicalEditor (admin/user/viewer)
- Toolbox Registry: Tool-Listen befuellt (core/ai/datasources/email/sharepoint/clickup/jira/workflow),
requestToolboxMeta-Tool implementiert,_activateToolboxesgenerisch - Scheduler-Konsolidierung:
subAutomation2Scheduleentfernt,/schedule-syncmigriert aufWorkflowScheduler.syncNow,app.pybereinigt - 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