235 lines
12 KiB
Markdown
235 lines
12 KiB
Markdown
<!-- status: canonical -->
|
|
<!-- lastReviewed: 2026-04-23 -->
|
|
<!-- verifiedAgainst: gateway (codebase audit 2026-04-07, post Automation Unification) -->
|
|
|
|
# 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:**
|
|
|
|
- **Typed Pick-not-Push (2026-04):** Action-Nodes füllen Parameter nur noch über explizite `DataRef` / Static / SystemVar (`resolveParameterReferences`). Laufzeit-Wire-Handover (`applyWireHandover`) ist entfernt. `executeGraph` ruft `materializeConnectionRefs` (leere `connectionReference` → Ref auf `connection.id`) und `validateGraph` mit **harter** Port-Typprüfung (Ausnahme: Ziel-Port nur `Transit` = untypisierter Sink). Upstream-Pfade: `POST/GET …/upstream-paths` und Agent-Tools `listUpstreamPaths` / `bindNodeParameter`.
|
|
- 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`** (`ui-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 (`platform-core/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.
|