# Automation (Graphical Editor) ## Ueberblick PowerOn hat ein **konsolidiertes Automatisierungssystem** basierend auf dem Feature `graphicalEditor`. Die frueheren separaten Systeme (Automation v1, Automation2) wurden entfernt; der gesamte Workflow-Lebenszyklus laeuft ueber ein einheitliches Datenmodell und eine gemeinsame **Unified Action Library** (`workflows/methods/` + `ActionExecutor`). **Architektur-Saeulen:** 1. **AI Service** -- Agent mit Toolbox-Registry, Streaming, Neutralisierung, Failover 2. **Graphical Editor** -- n8n-Style Flow-Builder mit AI Chat, UDB, Tracing, Versioning 3. **Consolidated Scheduler** -- `WorkflowScheduler` mit inkrementellem Sync (v1-Patterns) 4. **Unified Action Library** -- Method/Action-Bibliothek mit Toolbox-Zuordnung **Leitentscheide:** - Legacy-Features `automation` und `automation2` entfernt (Gateway + Frontend) - Greenfield-DB `poweron_graphicaleditor` (keine Migration von Altdaten) - v1-Scheduler-Patterns (inkrementell, `eventId`, `replaceExisting`, Stale-Removal) in konsolidierten Scheduler uebernommen - `app.py` als generischer Entry-Point ohne feature-spezifische Imports --- ## Datenmodell (Greenfield DB `poweron_graphicaleditor`) | Modell | Datei | Beschreibung | |--------|-------|-------------| | `AutoWorkflow` | `features/graphicalEditor/datamodelFeatureGraphicalEditor.py` | Workflow mit `graph`, `invocations`, `active`, `eventId`, Template-Felder (`isTemplate`, `templateScope`, `sharedReadOnly`) | | `AutoVersion` | gleiche Datei | Immutabler Graph-Snapshot: Status `draft`/`published`/`archived` | | `AutoRun` | gleiche Datei | Ausfuehrung: Status `running`/`paused`/`completed`/`failed`, `nodeOutputs`, `context`, `runEnvelope` | | `AutoStepLog` | gleiche Datei | Pro-Node-Log: `inputSnapshot`, `output`, `startedAt`, `completedAt`, `durationMs`, `tokensUsed`, `retryCount`, `error` | | `AutoTask` | gleiche Datei | Human-Task bei Pause: Status `pending`/`completed`/`rejected`/`expired` | **Invarianten:** - Pro Workflow hoechstens **eine** `PUBLISHED` Version; Scheduler bindet an die veroeffentlichte Version - `templateScope`: `user` | `instance` | `mandate` | `system` -- steuert Sichtbarkeit und RBAC - System-Templates (`templateScope=system`, `mandateId=None`) werden im Bootstrap erstellt ### Workflow-Vorlagen | Scope | Sichtbarkeit | Editierbar | Erstellt durch | |-------|-------------|------------|----------------| | `user` | Nur Ersteller | Ja | User ("Als Vorlage speichern") | | `instance` | Alle User der Feature-Instanz | Nein (read-only) | Scope-Erweiterung | | `mandate` | Alle User des Mandanten | Nein (read-only) | Scope-Erweiterung | | `system` | Plattformweit | Nein (read-only) | Bootstrap (`_bootstrapSystemTemplates`) | --- ## Scheduler (`WorkflowScheduler`) **Datei:** `workflows/scheduler/mainScheduler.py` Konsolidierter Scheduler mit v1-Patterns: | Aspekt | Implementierung | |--------|----------------| | Sync-Muster | Inkrementell: nur geaenderte Jobs re-registrieren (`eventId` Tracking) | | Stale-Removal | Jobs fuer geloeschte/deaktivierte Workflows werden entfernt | | Re-Registration | `replaceExisting=True` fuer idempotente Updates | | Active-Check | Vor Execution: Workflow `active` und Entry-Point `enabled` pruefen | | Cron-Parsing | Einfache Intervalle (*/N) als Sekunden; komplexe Cron via `parse_cron_to_kwargs` | | Thread-Bridge | `setMainLoop()` fuer async Handler aus Scheduler-Threads | | Delayed Sync | 5s nach Start fuer spaete DB-Verfuegbarkeit | | Change-Callback | `callbackRegistry` fuer `graphicalEditor.workflow.changed` | **Lifecycle:** - Start: `mainGraphicalEditor.onStart()` -> `startScheduler(eventUser)` - Stop: `mainGraphicalEditor.onStop()` -> `stopScheduler()` - Manual Sync: `POST /api/workflows/{instanceId}/schedule-sync` -> `syncNow()` - Main Loop: `app.py` setzt `setSchedulerMainLoop(main_loop)` beim Start **Run-Failure-Handling:** - In-App Notification fuer Workflow-Creator - Messaging-Subscription (`GraphicalEditorRunFailed`) fuer E-Mail-Benachrichtigung - Event-Emission (`graphicalEditor.run.failed`) --- ## Execution Engine **Datei:** `workflows/automation2/executionEngine.py` | Feature | Details | |---------|---------| | Graph-Execution | Topologische Sortierung, Branch-Erkennung (ifElse/switch), Loop-Support | | Pause/Resume | `PauseForHumanTaskError`, `PauseForEmailWaitError` mit Loop-State-Persistenz | | Retry | Pro-Node Retry-Policy (`retryMaxAttempts`, `retryDelaySeconds`) | | Step-Logging | `AutoStepLog` mit `inputSnapshot` fuer alle Pfade (inkl. Loops, Skipped) | | SSE Live-Push | `_emitStepEvent()` sendet Step-Updates an `EventManager`-Queue (`run-trace-{runId}`) | | Run-Events | `run_complete` / `run_failed` Events am Ende der Execution | **InputSnapshot-Abdeckung:** - Regulaere Nodes: Outputs aller Vorgaenger-Nodes - Loop-Header (`flow.loop`): Vorgaenger-Outputs - Loop-Body: `_loopItem`, `_loopIndex` + Vorgaenger-Outputs - Loop-Resume: `_loopItem`, `_loopIndex` + Vorgaenger-Outputs - Skipped Nodes: `_skipReason: "inactive_branch"` + Vorgaenger-Outputs --- ## Node-Types Definiert in `features/graphicalEditor/nodeDefinitions/`: | Kategorie | Nodes | |-----------|-------| | **Trigger** | `trigger.manual`, `trigger.schedule`, `trigger.webhook`, `trigger.form`, `trigger.event` | | **Flow** | `flow.ifElse`, `flow.switch`, `flow.loop`, `flow.merge`, `flow.delay` | | **Input** | `input.humanTask`, `input.emailWait` | | **AI** | `ai.prompt`, `ai.classify`, `ai.extract`, `ai.summarize` | | **Email** | `email.checkEmail`, `email.sendEmail`, `email.draftEmail` | | **SharePoint** | `sharepoint.listFiles`, `sharepoint.readFile`, `sharepoint.upload` | | **ClickUp** | `clickup.searchTasks`, `clickup.createTask`, `clickup.updateTask` | | **File** | `file.create` | | **Data** | `data.transform`, `data.filter`, `data.aggregate` | | **Trustee** | `trustee.refreshAccountingData`, `trustee.extractFromFiles`, `trustee.processDocuments`, `trustee.syncToAccounting` | --- ## Toolbox Registry **Datei:** `serviceCenter/services/serviceAgent/toolboxRegistry.py` Thematische Tool-Gruppierungen fuer den AI Agent: | Toolbox | Tools | Default | Requires Connection | |---------|-------|---------|-------------------| | `core` | 20 (readFile, listFiles, webSearch, writeFile, ...) | Ja | -- | | `ai` | 9 (summarizeContent, generateImage, executeCode, ...) | Ja | -- | | `datasources` | 8 (browseDataSource, searchDataSource, ...) | Ja | -- | | `email` | 5 (sendMail, outlook_readEmails, ...) | Nein | `microsoft` | | `sharepoint` | 3 (sharepoint_findDocuments, ...) | Nein | `microsoft` | | `clickup` | 3 (clickup_searchTasks, ...) | Nein | `clickup` | | `jira` | 3 (jira_connect, ...) | Nein | `jira` | | `workflow` | 9 (readWorkflowGraph, addNode, ...) | Nein | -- (featureCode: graphicalEditor) | | `trustee` | 1 (trustee_refreshAccountingData) | Nein | -- (featureCode: trustee) | **`requestToolbox` Meta-Tool:** - Agent kann zur Laufzeit inaktive Toolboxes anfordern - Handler in `mainServiceAgent._registerRequestToolbox()` - `agentLoop.py` refresht `toolDefinitions` nach erfolgreichem Aufruf - Nur inaktive Toolboxes werden als Enum-Optionen angeboten **Aktivierung:** - `_activateToolboxes` in `mainServiceAgent.py` prueft User-Connections - Toolboxes ohne `requiresConnection` sind immer verfuegbar - Tools aus inaktiven Toolboxes werden aus der Registry entfernt --- ## RBAC Feature-Code: `graphicalEditor` | Template-Rolle | UI-Zugriff | Daten-Zugriff | |----------------|-----------|---------------| | `graphicalEditor-viewer` | Dashboard, Workflows, Tasks, Templates (view) | Read: Mandate | | `graphicalEditor-user` | + Editor | CRUD: Mandate | | `graphicalEditor-admin` | Alle UI/Resource | CRUD: Mandate | Rollen werden beim Feature-Start via `_syncTemplateRolesToDb()` synchronisiert (inkl. Mandate-Instanz-Rollen). --- ## API-Endpunkte (Auswahl) | Methode | Pfad | Beschreibung | |---------|------|-------------| | POST | `/{instanceId}/execute` | Workflow ausfuehren | | GET | `/{instanceId}/runs/{runId}/stream` | SSE Live-Tracing fuer einen Run | | POST | `/{instanceId}/schedule-sync` | Scheduler manuell synchronisieren | | POST | `/{instanceId}/{workflowId}/chat/stream` | AI Chat SSE Stream | | GET | `/{instanceId}/node-types` | Verfuegbare Node-Types | | GET/POST | `/{instanceId}/workflows` | Workflows CRUD | | GET/POST | `/{instanceId}/templates` | Templates CRUD | | POST | `/{instanceId}/workflows/{workflowId}/versions/draft` | Draft-Version erstellen | | POST | `/{instanceId}/workflows/{workflowId}/versions/{versionId}/publish` | Version veroeffentlichen | --- ## System-Automatisierung (Meine Sicht) Mandatsuebergreifende Uebersicht im Frontend: Route **`/automations`** (`frontend_nyla` → `AutomationsDashboardPage`), Eintrag unter **Meine Sicht** in der Navigation. | Tab | Inhalt | |-----|--------| | **Dashboard** | Metriken (`GET /api/system/workflow-runs/metrics`), Runs-Tabelle mit Backend-Paginierung (`GET /api/system/workflow-runs`) | | **Workflows** | Liste aller nicht-Template-Workflows aus der Greenfield-DB, gefiltert nach Mandatszugehoerigkeit; Enrichment mit Mandats- und Instanz-Label; pro Zeile **`canEdit` / `canDelete` / `canExecute`** (Sysadmin: alles; Mandats-Admin fuer betroffenes Mandat: alles; sonst keine Mutationsaktionen im UI) | **Gateway:** `routes/routeWorkflowDashboard.py`, Router-Prefix **`/api/system/workflow-runs`**. | Methode | Pfad | Beschreibung | |---------|------|--------------| | GET | `/api/system/workflow-runs` | Runs (offset/limit, RBAC) | | GET | `/api/system/workflow-runs/metrics` | Aggregierte Kennzahlen | | GET | `/api/system/workflow-runs/{runId}/steps` | Step-Logs fuer einen Run | | GET | `/api/system/workflow-runs/workflows` | Workflows mandatsuebergreifend (Query: `active`, `mandateId`, `pagination` als JSON) | Instanzspezifische Verwaltung unveraendert unter **`/api/workflows/{instanceId}/...`** (`routeFeatureGraphicalEditor.py`). --- ## Schluessel-Dateien | Bereich | Pfade (`gateway/modules/`) | |---------|--------------------------| | Feature-Definition | `features/graphicalEditor/mainGraphicalEditor.py` | | API-Routes | `features/graphicalEditor/routeFeatureGraphicalEditor.py` | | Interface | `features/graphicalEditor/interfaceFeatureGraphicalEditor.py` | | Datenmodell | `features/graphicalEditor/datamodelFeatureGraphicalEditor.py` | | Node-Definitionen | `features/graphicalEditor/nodeDefinitions/` | | Execution Engine | `workflows/automation2/executionEngine.py` | | System-Runs / zentrale Workflow-Liste | `routes/routeWorkflowDashboard.py` | | Scheduler | `workflows/scheduler/mainScheduler.py` | | Toolbox Registry | `serviceCenter/services/serviceAgent/toolboxRegistry.py` | | Action Library | `workflows/methods/`, `workflows/processing/` (`ActionExecutor`, `methodDiscovery`) | | Agent Tools | `serviceCenter/services/serviceAgent/` (coreTools, actionToolAdapter, workflowTools) | | Bootstrap | `interfaces/interfaceBootstrap.py` (System-Templates, Billing) | --- ## Regeln / Invarianten 1. **Eine Action Library:** Aenderungen an Methods/Actions betreffen Workspace, Graph-Editor und Agent-Tools gleichzeitig -- `actionId`-Stabilitaet beachten. 2. **RBAC strikt trennen:** Mandantenrollen vs Feature-Instanz-Rollen nicht mischen; Permissions ueber AccessRules. 3. **Scheduler vs Editor:** Ausfuehrung und Zeitplanung gehoeren zum Scheduler; der Graph ist Version-gebunden (Draft vs Published). 4. **Tool-Skalierung:** Toolbox-Konzept mit `requestToolbox` Meta-Tool; connection-basierte Verfuegbarkeit. 5. **`app.py` generisch:** Keine feature-spezifischen Imports in `app.py`; Feature-Lifecycle in `mainGraphicalEditor.onStart/onStop`. 6. **Neutralisierung / KI:** Plattformweit gelten die zentralen KI-Datenpfade; Automation nutzt dieselben Services. 7. **Bootstrap idempotent:** `initBootstrap` mit `_bootstrapDone` Flag; System-Templates, Billing, Stripe-Prices.