wiki/c-work/4-done/2026-06-automation-system-component.md

372 lines
48 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- status: done -->
<!-- started: 2026-06-05 -->
<!-- completed: 2026-06-08 -->
<!-- component: gateway | ui-nyla | platform -->
# WorkflowAutomation als System-Komponente — `graphicalEditor` raus aus dem Feature-Modell
> **Migration Status: COMPLETE (2026-06-08).** Alle `graphicalEditor`-Code-Referenzen eliminiert. Code aus `features/graphicalEditor/`, `workflows/automation2/`, `workflows/scheduler/` verschoben nach `modules/workflowAutomation/{editor,engine,scheduler}/`. Originale gelöscht, `__init__.py`-Shims als Safety-Net. Test-Imports, DEPRECATED-Kommentare, Store/RBAC-Namespace, Demo-Configs, Frontend-Kommentare/Logs bereinigt. `graphicalEditorRunFileLogger.py` → `runFileLogger.py`. `datamodelFeatureGraphicalEditor.py` gelöscht. Frontend-Monolith gesplittet (D1-D3). RBAC-Migration als idempotente Boot-Routine. Verbleibend: AC5 per-Node Billing + AC7 Run-as-Principal (Scope CustomerCases), automatisierte Tests T1-T5 (pending), Smoke-Test Scheduler (manuell bei Deploy).
> **Treiber:** Entscheid aus `c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md` / `…-step3-features-plan.md` **A0.4**. Dort wurde die Entkopplung als Roadmap markiert; sie wird **vorgezogen**, weil sie sonst die Solution-Schicht (Ownership/RBAC/Billing) später erneut einholt.
>
> **Namens-Konvention:** Die System-Komponente heisst **`WorkflowAutomation`** (Code-Token `WorkflowAutomation`/`workflowAutomation`) — semantisch eindeutig und gut greppbar. Das generische Wort «Automation» ist im Bestand schon mehrfach belegt (`AutomationsDashboardPage`, `routeAutomationWorkspace`, `/automations`, `workflows/automation2`) und bleibt dort **unverändert**. UI-Label (kundensichtbar): **«Workflow-Automation»** / «Automatisierung».
## Beschreibung und Kontext
`graphicalEditor` ist heute ein **Hybrid**: formal ein Feature (Discovery, `TEMPLATE_ROLES` `graphicalEditor-*`, Store-Eintrag, `FeatureInstance` pro Mandant, per-Instanz-API `/api/workflows/{instanceId}/…`), architektonisch aber **mandanten- und feature-übergreifende Orchestrierungs-Infrastruktur**:
- **Kein `getDataObjects()`** — keine Domänen-/Kundendaten; `AutoWorkflow`/`AutoRun` sind Orchestrierungs-Metadaten (eigene DB `poweron_graphicaleditor`).
- **Einziges Feature mit `onStart`/`onStop`** — bootet beim App-Start den **globalen** Scheduler (Email-Poller startet **on-demand** via `emailPoller.ensureRunning`, gestoppt in `onStop`).
- **Scheduler/Engine liegen ohnehin unter `modules/workflows/`** (System), nicht im Feature.
- **`getWorkflows()` filtert nur nach `mandateId`** («cross-instance»); ein Graph referenziert legitim mehrere Features/Instanzen über per-Node `FeatureInstanceRef`.
- **Cross-Mandate-Ops-Sicht existiert bereits**: `AutomationsDashboardPage` (`/automations`, Tabs Workflows/Runs/Details) ← `routeWorkflowDashboard.py` (`/api/system/workflow-runs`), RBAC über Mandats-Mitgliedschaft + Platform-Admin — **ganz ohne** GE-FeatureInstance.
**Business-Treiber:** Die Solution-Schicht (CustomerCases) verankert Ownership an **Mandant + Run-as-Principal** (A0.1). Solange `graphicalEditor` als Feature mit per-Instanz-RBAC/Billing geführt wird, kollidiert jede Solution mit einem erfundenen «Host-Owner». Wir lösen die Wurzel: **WorkflowAutomation = System-Komponente** mit eigener Navigations-Gruppe «Workflow-Automation» (mehrere Tab-Seiten, mandanten-/feature-übergreifend strukturiert an einem Ort) und sauberem Daten-/RBAC-Modell.
**Risiko, wenn NICHT gemacht:** doppelte Wahrheit (Feature-Instanz-RBAC vs. mandatsweite Realität), Billing fix auf `graphicalEditor` statt auf berührte Instanz, per-Instanz-URLs (`{instanceId}`) zementieren das Feature-Modell, und die Solution-Schicht erbt den Designfehler.
## Code-Stand nach Import-Refactoring (2026-06-05/06)
Das Backend wurde zwischenzeitlich auf eine **Layer-Hierarchie L0L7** refactored (`shared`=L0, `datamodels`=L1, `connectors`=L2, `dbHelpers`=L3, `interfaces`/`system`/`security`/`auth`=L4, `serviceCenter`/`workflows`/`features`=L5, `routes`=L6, `app`=L7; Quelle: `local/notes/refernce-analysis/platform-core-import-analyse.md`). Das ändert mehrere Plan-Annahmen — vieles ist **schon erledigt**; das GE↔Engine-Coupling wurde dort **explizit auf diesen Plan vertagt** («Deferred: WorkflowAutomation»).
**Schon erledigt (Plan-Schritte entfallen/reduziert):**
- **Contracts + Models liegen in L1:** `PORT_TYPE_CATALOG`/`PRIMITIVE_TYPES` → `datamodels/datamodelPortTypes.py`; `AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask``datamodels/datamodelWorkflowAutomation.py` (kanonisch, Re-Export-Shim `features/graphicalEditor/datamodelFeatureGraphicalEditor.py`, 7 Caller). → Das geplante «Shared Contracts»-Modul **ist faktisch `datamodels` (L1)**; **kein** neues `workflowContracts/` nötig.
- **Feature-Lifecycle-Hooks existieren:** `mainGraphicalEditor.onInstanceCreate()` (Template-Copy, ex `interfaceFeatures._copyTemplateWorkflows`), `onMandateDelete()` (Cascade, ex `interfaceDbApp`), `onBootstrap()` (Seeding, ex `interfaceBootstrap`) — dynamisch via `shared/featureDiscovery.loadFeatureMainModules()`. → Plan-Touchpoints in `interfaceFeatures/interfaceDbApp/interfaceBootstrap` sind jetzt **Feature-Hooks**.
- **Weitere Verschiebungen:** `NAVIGATION_SECTIONS``datamodels/datamodelNavigation.py`; `EventManager``shared/eventManager.py`; `parseInlineRuns``shared/documentUtils.py`; `serviceHub``serviceCenter/serviceHub.py`; Service-Exceptions → `datamodels/serviceExceptions.py`; `WorkflowStoppedException`/`checkWorkflowStopped` → `shared/workflowState.py`.
**Explizit auf diesen Plan vertagt (Deferred-Liste):**
- `features.graphicalEditor → workflows` (21) + `workflows → features.graphicalEditor` (40) → Ziel **0** (kollabiert, sobald Editor + Engine **ein** Modul sind).
- `serviceCenter → features.graphicalEditor` (5×, `serviceAgent/workflowTools.py`).
- `interfaces/interfaceDbManagement.py:936` (lazy → `workflowArtifactVisibility`).
- Re-Export-Shims entfernen: `datamodelFeatureGraphicalEditor.py` (7 Caller), `workflows/processing/shared/stateTools.py` (7 Caller).
- **Boundary-Leck besteht weiter (Delaminierung offen):** `PauseForHumanTaskError` (`automation2/executors/inputExecutor.py`) und `coerceDocumentDataToBytes` (`automation2/executors/actionNodeExecutor.py`) werden von `methods/methodContext/actions/setContext.py` bzw. `methods/methodFile/actions/create.py` top-level importiert → vor Engine-Umzug extrahieren (`PauseForHumanTaskError` → `datamodels/serviceExceptions.py`, `coerceDocumentDataToBytes``shared/documentUtils.py`).
## Fokus und kritische Details
- **Kein Big-Bang.** Parallel-Pfade bauen (mandatsweite API neben `{instanceId}`-API), dann umschalten, dann Feature-Mantel entfernen. Jede Phase ist für sich lauffähig.
- **Scheduler-Boot ist fragil.** Er hängt am Feature-`onStart` (`app.py`-Lifespan iteriert alle Feature-Module). Vor dem Entfernen des Feature-Mantels **muss** der Boot in einen System-Lifespan-Hook umziehen, sonst startet der Scheduler nicht mehr.
- **`featureInstanceId` hat heute zwei Bedeutungen:** (a) GE-Owner/RBAC-Scope auf `AutoWorkflow`, (b) Daten-Scope der Ausführung (`targetFeatureInstanceId` + per-Node `FeatureInstanceRef`). Nur (a) wird abgebaut; (b) bleibt — es ist die Cross-Feature-Referenz.
- **Kaum DDL nötig (Code-verifiziert).** Tabellen werden **ohne `NOT NULL`** (ausser `id`-PK) und **ohne DB-FKs** angelegt (`connectorDbPostgre.py` `_create_table_from_model`); FKs sind app-level (`fkRegistry`, `app.py` `validateFkTargets`). Heisst: `featureInstanceId` ist **schon jetzt DB-nullable** → «nullable machen» ist nur `Optional[str]` im Pydantic-Modell (`datamodelFeatureGraphicalEditor.py`) + Query-/Code-Anpassungen, **keine Migration**. `runAsPrincipal` = additives `ADD COLUMN` (von `_ensureTableExists` abgedeckt). Echte Arbeit = Application-Logik (Routen/Queries, die `featureInstanceId` voraussetzen), nicht Schema.
- **Bestehende Daten grandfathern.** `AutoWorkflow`-Zeilen tragen `featureInstanceId`; `FeatureAccess`-Grants und per-Instanz-Rollen existieren. Datenmigration als **einmaliges Skript** (Muster: `scripts/script_migrate_feature_instance_refs.py`; Cascade-Vorbild: `routeWorkflowDashboard._cascadeDeleteAutoWorkflow`). Migration muss diese erhalten/überführen, nicht löschen.
- **RBAC-Präzedenz nutzen — aber sie deckt nur Lesen.** `routeWorkflowDashboard.py` (`_scopedWorkflowFilter`/`_getAdminMandateIds` + `isPlatformAdmin`) ist ein **Read/List/Delete**-Muster — **kein** Create/Update/Publish/Execute. Die **39** `_validateInstanceAccess`-Sites in `routeFeatureGraphicalEditor.py` sind grösstenteils Write/Execute; dafür braucht es einen **eigens entworfenen** Helper `_validateWorkflowAccess(workflow, context, action)` (read vs. write), nicht 1:1 das Dashboard-Muster. `system`-Pseudo-Feature (`instantiable=False`) ist die Vorlage für Katalog-/RBAC-Registrierung ohne Instanzen.
- **Shared Contracts schon in L1, Node-Katalog noch beim Editor.** `PORT_TYPE_CATALOG` liegt seit dem Refactoring in `datamodels/datamodelPortTypes.py` (erledigt). Der Node-Katalog (`STATIC_NODE_TYPES`) ist noch unter `features/graphicalEditor/nodeDefinitions/` und wird cross-layer genutzt (`system/i18nBootSync.py`, `serviceAgent/workflowTools.py`) — er zieht mit dem Editor in die Komponente. **Offenes Boundary-Leck:** zwei Helfer (`PauseForHumanTaskError`, `coerceDocumentDataToBytes`) liegen in `automation2.executors`, werden aber von `methods/` importiert → **vor** dem Engine-Umzug delaminieren.
- **Zwei UI-Oberflächen sauber trennen** (siehe «Verhältnis zur Solution-Schicht»): die **WorkflowAutomation-Gruppe** (technische Orchestrierung, cross-mandate, für Power-User/Admins) vs. die kundenseitige **«Lösungen»-Surface** pro Host-Feature (bleibt eingebettet, Präsentation).
## Ziel und Nicht-Ziele
- **Ziel:** `graphicalEditor` als System-Komponente **`WorkflowAutomation`** führen — eigene Top-Level-Navigationsgruppe mit Tab-Seiten (Editor · Vorlagen · Workflows · Läufe · Tasks), mandanten-/feature-übergreifend.
- **Ziel:** Mandatsweite API + RBAC (kein `{instanceId}` als RBAC-Anker), Scheduler-Boot als System-Lifespan, DB-Scoping auf **Mandant + Principal** (statt GE-Owner-Instanz).
- **Ziel:** Bestehende Workflows/Runs/Tasks und Grants verlustfrei migrieren.
- **Ziel:** Fundament legen für die `Solution`-Schicht (A0.1) — Solutions hängen an Mandant + Run-as-Principal, nicht an einer GE-Instanz.
- **Explizit NICHT:** Graph-Format/Node-Semantik ändern (`modules/workflows/automation2/*` bleibt funktional gleich). **Ausnahme:** per-Node-Billing-Attribution (AC5) ist eine bewusste, lokal begrenzte Executor-Änderung (berührte `FeatureInstanceRef` in den `recordUsage`-Kontext threaden) — kein Graph-/Semantik-Umbau.
- **Explizit NICHT:** den geteilten **Workflow-Execution-Layer** (`workflows/methods/`, `workflows/processing/`) in die Komponente ziehen — er bleibt unter `modules/workflows/` (Chats/Agents nutzen ihn **ohne** Automation).
- **Explizit NICHT:** die kundenseitige «Lösungen»-Surface in diesem Plan bauen (→ CustomerCases-Pläne; dieser Plan liefert nur das Substrat).
- **Explizit NICHT:** per-Node `FeatureInstanceRef` / `targetFeatureInstanceId` (Daten-Scope) abschaffen.
- **Explizit NICHT:** DB-Engine/Datenbankname wechseln (`poweron_graphicaleditor` bleibt).
- **Explizit NICHT:** bestehende «Automation»-Code-Namen umbenennen (`AutomationsDashboardPage`, `routeAutomationWorkspace`, `workflows/automation2`) — nur die *neue* Komponente trägt das Token `WorkflowAutomation`.
## Zielarchitektur (Kurz)
```
VORHER (Feature):
Nav: Mandant → graphicalEditor-Instanz → {editor, templates, tasks}
API: /api/workflows/{geInstanceId}/... RBAC: FeatureAccess auf GE-Instanz
DB : AutoWorkflow.featureInstanceId = GE-Owner (RBAC-Scope)
Boot: graphicalEditor.onStart → Scheduler
NACHHER (System-Komponente WorkflowAutomation):
Nav: Top-Level-Gruppe «Workflow-Automation» (einmal) → Tabs {Editor, Vorlagen, Workflows, Läufe, Tasks}
+ Mandanten-/Instanz-Picker in der Seite (cross-mandate)
API: /api/workflow-automation/... RBAC: Mandats-Mitgliedschaft + System-Rollen + isPlatformAdmin
DB : AutoWorkflow.mandateId + runAsPrincipal (Owner); featureInstanceId → entfällt als RBAC-Anker
targetFeatureInstanceId + per-Node FeatureInstanceRef bleiben (Daten-Scope)
Boot: System-Lifespan (app.py) → Scheduler
```
## Namensgebung & modulare Struktur
**Name der System-Komponente: `WorkflowAutomation`** (UI-Label «Workflow-Automation» / «Automatisierung»). `graphicalEditor` ist **nicht** der Name der Komponente, sondern **ein Modul** darin (der Graph-/Flow-Editor). Begründung für `WorkflowAutomation`: semantisch eindeutig + als Token greppbar (das generische «Automation» ist im Code mehrfach belegt und bleibt). (Verworfen: «Automation» allein — mehrdeutig; «Orchestration» — neuer Begriff ohne Code-Verankerung.)
Die Komponente bündelt die bestehenden, heute verstreuten **Automation**-Teile (`features/graphicalEditor/`, `workflows/automation2/`, `workflows/scheduler/`) **plus** die kommende L3/L4-Schicht zu **einem nachvollziehbaren, modularen System**. Den geteilten **Workflow-Execution-Layer** (`workflows/methods/`, `workflows/processing/`) bündelt sie **nicht** — der bleibt eigenständig (siehe Abgrenzung unten). Jedes Modul hat eine klare Verantwortung und mappt auf die L2L4-Schichten der Architektur.
| L | Modul | Verantwortung |
|---|---|---|
| L2 | **editor** (= heute `graphicalEditor` Authoring) | Graph/Flow-Authoring, Node-Registry, Adapter, Editor-UI-Backend (konsumiert Shared Contracts) |
| L2 | **engine** (= heute `workflows/automation2/`) | Graph-Ausführungs-Runtime (Graph → Run) |
| L2 | **scheduler** | Zeit-/Event-Trigger, Email-Poller |
| L3 | **solutions** | konfigurierte Workflows (Solution-Modell, Settings-Injektion) |
| L4 | **launcher** | Katalog/Vorlagen + «neue Automation» (Template/AI) + Template-Instanziierung |
| L4 | **monitoring** | Läufe, Tasks, Logs (Ops-Sicht) |
> **NICHT Teil der Komponente (geteilt, Code-verifiziert) — Komponente *konsumiert* abwärts:**
> - **L1 Toolbox (Execution)** = `workflows/methods/` (generische Actions) + `workflows/processing/` (ActionExecutor, methodDiscovery, modes) — von Chats/Agents genutzt. (Feature-eigene Actions liegen seit Refactoring beim Feature, z. B. `features/trustee/workflows/`.)
> - **Contracts/Models = `datamodels` (L1, bereits erledigt):** `datamodelPortTypes.py` (`PORT_TYPE_CATALOG`), `datamodelWorkflowAutomation.py` (`AutoWorkflow…`). Die Komponente konsumiert L1, besitzt sie **nicht**. (Der Node-Katalog `STATIC_NODE_TYPES` liegt noch beim Editor und zieht mit ihm um.)
### Platform (`platform-core/modules/workflowAutomation/`)
```
modules/workflowAutomation/ # NEU — die Automation-Komponente
├─ mainWorkflowAutomation.py # System-Registrierung (instantiable=False) + Lifespan-Hook (Scheduler-Boot; Poller-Stop) + Lifecycle-Hooks (onMandateDelete/onBootstrap)
│ # Models kanonisch in datamodels/datamodelWorkflowAutomation.py (L1) — Komponente importiert sie
├─ routes/ # mandatsweite API /api/workflow-automation/{workflows,versions,runs,tasks,nodes,solutions,...}
├─ editor/ # L2 — Graph-Editor-Backend (nodeRegistry, nodeAdapter, adapterValidator) — konsumiert Shared Contracts
├─ engine/ # L2 — Graph-Ausführung (heute workflows/automation2/: executionEngine, executors, graphUtils, runEnvelope, scheduleCron)
├─ scheduler/ # L2 — Scheduler + emailPoller (heute workflows/scheduler/ + graphicalEditor/emailPoller.py)
├─ solutions/ # L3 — solutionService, datamodelSolution (Settings-Injektion, run-as-Principal)
└─ launcher/ # L4 — Katalog/Templates + AI-Erstellung + Template-Instanziierung
modules/workflows/ # BLEIBT — geteilter Execution-Layer (NICHT Teil der Komponente)
├─ methods/ # L1-Toolbox — generische Actions (methodAi/Sharepoint/Outlook/File/Context/Clickup/Jira/Redmine)
├─ processing/ # ActionExecutor, methodDiscovery, modes/adaptive, workflowProcessor
└─ workflowManager.py # Chat-/Agent-seitige Workflow-Verarbeitung
modules/datamodels/ # BLEIBT — Contracts/Models (L1, bereits dorthin refactored)
├─ datamodelPortTypes.py # PORT_TYPE_CATALOG / PRIMITIVE_TYPES
└─ datamodelWorkflowAutomation.py# AutoWorkflow / AutoVersion / AutoRun / AutoStepLog / AutoTask (kanonisch)
```
> **Abgrenzung Komponente ↔ Contracts ↔ Execution (Code-verifiziert, korrigiert).** Drei Schichten, strikt abwärts: **Komponente → Shared Contracts → Execution-Layer.**
> - **In die Komponente:** `workflows/automation2/` (Graph-Engine) → `engine/`; `workflows/scheduler/` → `scheduler/`; `graphicalEditor/{nodeRegistry, adapterValidator, emailPoller, Editor-Backend}` → `editor/`/`scheduler/`.
> - **Bleibt geteilt unter `modules/workflows/`:** `methods/` (Actions), `processing/` (`ActionExecutor`, `methodDiscovery`, `modes/`, `adaptive/`, `workflowProcessor`) — genutzt von Chats/Agents (`serviceAgent/{actionToolAdapter,mainServiceAgent}`, `serviceAi/*`, `serviceGeneration/*`) **ohne** Automation.
> - **Contracts/Models:** `PORT_TYPE_CATALOG` + `AutoWorkflow…` liegen **bereits** in `datamodels/` (L1, durchs Refactoring); Komponente konsumiert sie. Der Node-Katalog (`STATIC_NODE_TYPES`) liegt noch beim Editor und zieht mit ihm um (cross-Caller: `system/i18nBootSync.py`, `serviceAgent/workflowTools.py` beachten).
> - **Korrektur eines früheren Fehlers (weiterhin gültig):** «`automation2` wird von Chats nicht importiert» war **falsch** und ist **noch nicht behoben**. `methods/methodFile/actions/create.py` (→ `coerceDocumentDataToBytes`) + `methods/methodContext/actions/setContext.py` (→ `PauseForHumanTaskError`) importieren `automation2.executors` top-level — geladen via `methodDiscovery` im Chat-/Agent-Pfad. **Diese zwei Helfer vor dem Engine-Umzug extrahieren** (`→ datamodels/serviceExceptions.py` bzw. `shared/documentUtils.py`), sonst importiert Shared aufwärts in die Komponente.
>
> **Guard-Test:** sicherstellen, dass `modules.workflows.{methods,processing}` + `modules.serviceCenter` importierbar sind, **ohne** `modules.workflowAutomation.*` zu laden. Migration nur der Automation-Teile (Re-Export/Shims; ~20 Importer von `workflows.automation2`/`scheduler`). **Kein funktionaler Umbau der Engine** (Ausnahme: per-Node-Billing, AC5).
### UI (`ui-nyla/src/`)
```
pages/workflowAutomation/
├─ WorkflowAutomationHubPage.tsx # Container: Top-Level-Gruppe «Workflow-Automation», Tabs, Mandanten-/Instanz-Scope-Selector
└─ tabs/
├─ LauncherTab.tsx # L4 — Katalog/Neu (Vorlage oder AI)
├─ SolutionsTab.tsx # L3 — konfigurierte Solutions (Admin/Power-User-Sicht)
├─ EditorTab.tsx # L2 — Graph-Editor (Keep-Alive)
├─ WorkflowsTab.tsx # alle Workflows (cross-mandate/-feature)
├─ RunsTab.tsx # L4 — Läufe/Monitoring
└─ TasksTab.tsx # Human-Tasks
components/workflowAutomation/
├─ FlowEditor/ # heute components/GraphicalEditor/
├─ Launcher/
├─ Solutions/
└─ Monitoring/
api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workflowApi {instanceId}-Pfade)
```
- **Eine** Top-Level-Nav-Gruppe «Workflow-Automation» (nicht pro Mandant/Instanz); Tabs via `?tab=` deeplinkbar (Muster `AutomationsDashboardPage`).
- **Abgrenzung zur kundenseitigen «Lösungen»-Surface:** Der `SolutionsTab` hier ist die **Admin/Power-User**-Sicht über alle Solutions; die kundenseitige `SolutionsView` (L4) bleibt **pro Host-Feature eingebettet** (Trustee usw.) und zeigt nur die für diesen Kontext konfigurierten Solutions. Beide nutzen `api/workflowAutomationApi.ts`.
## Verhältnis zur Solution-Schicht (CustomerCases)
- **WorkflowAutomation-Gruppe = Substrat-UI** (Power-User/Admin): roher Editor, Templates, alle Workflows/Läufe/Tasks über Mandanten/Features.
- **«Lösungen»-Surface = kundenseitig**, pro Host-Feature eingebettet (Trustee usw.) — konsumiert dasselbe Substrat, zeigt aber nur konfigurierbare Solutions. Bleibt wie in den CustomerCases-Plänen.
- Beide hängen am gleichen Modell: **Mandant + Run-as-Principal**, nicht an einer GE-Instanz. Dieser Plan ist die **Voraussetzung** für A0.1/A0.2.
## Betroffene Module
- **Gateway (platform-core):**
- `app.py` — Scheduler/Email-Poller-Boot in **System-Lifespan** (statt Feature-`onStart`).
- `modules/workflows/scheduler/mainScheduler.py` — Boot-Aufruf; `JOB_ID_PREFIX`/`_CALLBACK_NAME` (`"graphicalEditor.*"`) sind in Job-IDs persistiert → Literale behalten oder Job-IDs migrieren (in-memory APScheduler, Re-Sync beim Boot → risikoarm); `if not instanceId`-Guard entfernen (s. Phase 1); **Run-as-Principal** statt globalem `event`-Sysadmin (A0.1).
- **Delaminierung zuerst (Phase 0.5):** `PauseForHumanTaskError``datamodels/serviceExceptions.py`, `coerceDocumentDataToBytes``shared/documentUtils.py` (Re-Export-Shim in `automation2/executors/`). Contracts (`portTypes`, Models) sind bereits in `datamodels` (L1). Erst dann ist der Engine-Umzug aufwärts-importfrei.
- `modules/workflows/{automation2,scheduler}/` → in die Komponente: `automation2``workflowAutomation/engine/`, `scheduler``workflowAutomation/scheduler/` (Re-Export-Shims). **`automation2` = die Graph-Engine**, kein funktionaler Umbau (Ausnahme: per-Node-Billing-Kontext, AC5).
- **`modules/workflows/{methods,processing}/` bleiben** geteilt (Execution-Layer), **`datamodels/`** bleibt L1 — **nicht** verschieben.
- `modules/features/graphicalEditor/` → konzeptionell nach `modules/workflowAutomation/editor/` führen; `mainGraphicalEditor.py`: `getFeatureDefinition`/`TEMPLATE_ROLES`/`onStart` entfernen bzw. zu System-Registrierung umbauen (`instantiable=False`, Vorbild `mainSystem.py`).
- `modules/features/graphicalEditor/routeFeatureGraphicalEditor.py` — neue **mandatsweite** Routen `/api/workflow-automation/...`; die **39** `_validateInstanceAccess`-Sites bewusst auf einen neuen `_validateWorkflowAccess(workflow, context, action)` (read vs. write) migrieren — Read-Scoping vom Dashboard, Write/Execute eigens entworfen, `isPlatformAdmin`-Bypass. `_validateTargetInstance` zusätzlich um **Mandatsgrenze** ergänzen (AC8, heute nur `FeatureAccess`).
- `modules/routes/routeSystem.py` — GE-Hardcode in `_getFeatureUiObjects` entfernen; neuen statischen Nav-Block `workflowAutomation` ausliefern.
- `modules/datamodels/datamodelNavigation.py``NAVIGATION_SECTIONS` (post-Refactoring hier, **nicht** mehr in `mainSystem.py`): Block `id="workflowAutomation"` (order ~25) ergänzen; `ui.system.workflowAutomation.*`-Objekte; Store-Eintrag `resource.store.graphicalEditor` entfernen.
- `modules/features/graphicalEditor/mainGraphicalEditor.py` **`onInstanceCreate()`** — heute Template-Copy bei FeatureInstance-Erstellung (stempelt `{{featureInstanceId}}`/`targetFeatureInstanceId`, auch Trustee/Redmine). Ohne GE-Instanz **entfällt der Hook-Trigger** → Template-Instanziierung explizit in den `launcher/`-Flow verlagern (inkl. Demo-Bootstrap); Trustee/Redmine-Platzhalter-Vertrag beachten.
- `modules/features/graphicalEditor/mainGraphicalEditor.py` **`onMandateDelete()`** (Cascade) / **`onBootstrap()`** (Seeding) — sind bereits Feature-Hooks (ex `interfaceDbApp`/`interfaceBootstrap`); ziehen mit der Komponente um, Cascade auf mandatsweit umstellen.
- `modules/interfaces/interfaceRbac.py``TABLE_NAMESPACE` (8 Einträge: `AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask` + Legacy `Automation2*`): **Option B** — Namespace `feature.graphicalEditor` **beibehalten** + System-DATA-Objekte ergänzen. (Ein Flip auf `system.workflowAutomation` verwaist bestehende `AccessRule`/Rollen-Zeilen; nur mit zwingend gekoppeltem Migrations-Skript im selben Deploy.)
- `modules/interfaces/interfaceBootstrap.py` — Store-Grant + ggf. neue System-Rollen `workflowAutomation-*` (Hook-Aufruf bleibt; GE-Wissen ist dynamisch via `loadFeatureMainModules`).
- `modules/features/graphicalEditor/mainGraphicalEditor.py` `getGraphicalEditorServices``featureCode`/`featureInstanceId` im Hub (jetzt `serviceCenter/serviceHub.py`): Billing **per-Node** auf berührte Instanz (A0.2, Executor-Change), Mandate = `mandateId`.
- `serviceCenter/.../toolboxRegistry.py` + `serviceCenter/services/serviceAgent/workflowTools.py``featureCode="graphicalEditor"``workflowAutomation`; `workflowTools` ist der verbleibende `serviceCenter → features.graphicalEditor` (5×, deferred) → entfällt mit Umzug.
- **Weitere GE-Importer (Deferred-Liste):** `system/i18nBootSync.py` (zieht `STATIC_NODE_TYPES` — mit Node-Katalog mitziehen), `routeSystem.py` (`UI_OBJECTS` + Dashboard-`_ensureTableExists`), `routeAdminFeatures.py`, `interfaceDbManagement.py:936` (lazy `workflowArtifactVisibility`), `interfaceFeatureGraphicalEditor.getAllWorkflowsForScheduling` (Lesepfad von Scheduler **und** Dashboard — stabil halten/shimmen); Re-Export-Shims `datamodelFeatureGraphicalEditor.py` (7) + `processing/shared/stateTools.py` (7) entfernen.
- **Frontend (ui-nyla):**
- `src/components/Navigation/MandateNavigation.tsx``block.id === 'workflowAutomation'` als eigene Top-Level-Gruppe rendern (analog `admin`).
- `src/App.tsx``/workflow-automation/*`-Routen (Hub + `?tab=` Deeplinks); Redirects der alten `/mandates/.../graphicalEditor/.../*`.
- `src/pages/AutomationsDashboardPage.tsx` → in **`WorkflowAutomationHubPage`** mit Tabs überführen (Workflows, Läufe, Editor, Vorlagen, Tasks).
- `src/pages/FeatureView.tsx``graphicalEditor` aus `VIEW_COMPONENTS` entfernen.
- `src/pages/views/graphicalEditor/*` — von `useInstanceId()`/`useCurrentInstance()` auf expliziten Mandanten-/Instanz-Picker (Scope-Selector) umstellen.
- `src/config/keepAliveRoutes.tsx` — Editor-Keep-Alive-Pfad auf `/workflow-automation/editor` umziehen.
- `src/config/pageRegistry.tsx` — Icons für `page.system.workflowAutomation.*`.
- `src/api/workflowApi.ts` — URLs `/api/workflows/{instanceId}/…``/api/workflow-automation/…`.
- Cross-Links: `TrusteeAnalyseView`/`TrusteeAbschlussView` (`/automations?tab=…`), `Store.tsx` (GE-Karte entfernen).
- **DB-Migration:** minimal — `runAsPrincipal` = additives `ADD COLUMN`; `featureInstanceId` ist **bereits DB-nullable** (kein DDL, keine DB-FK; nur Pydantic `Optional` + Code); Daten-/Grant-Backfill via Skript. **Kein** Namespace-Flip (Option B).
- **Andere:** RBAC (System-Objekte/-Rollen, FeatureAccess-Grants migrieren, GE-Feature-Rollen entfallen), Billing (per-Node-Attribution), Demo-Configs (`pwgDemo2026`/`investorDemo2026`), Tests, `.cursor/rules/*` (s. Abschluss).
## Entscheidungen
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
| 2026-06-05 | System-Komponente heisst **`WorkflowAutomation`** (Token `WorkflowAutomation`/`workflowAutomation`); UI-Label «Workflow-Automation» | semantisch eindeutig + greppbar; generisches «Automation» bleibt für Bestand |
| 2026-06-05 | `graphicalEditor` = **ein Modul** (editor) innerhalb von WorkflowAutomation | graphEditor ist nur das Authoring-Element |
| 2026-06-05 | **Automation ≠ Workflow-Execution.** `methods`/`processing` bleiben geteilter Layer unter `modules/workflows/`; nur `automation2` (engine) + `scheduler` + `graphicalEditor` wandern in die Komponente | Chats/Agents nutzen den Execution-Layer **ohne** Automation; Abwärts-Abhängigkeit Komponente→Execution (Code-belegt) |
| 2026-06-07 | **Contracts/Models in `datamodels` (L1)** statt neuem `workflowContracts/` — durchs Import-Refactoring bereits erledigt (`datamodelPortTypes`, `datamodelWorkflowAutomation`) | Layer-Hierarchie L0L7; Komponente konsumiert L1 abwärts |
| 2026-06-07 | **Delaminierung** zweier Helfer (`PauseForHumanTaskError` → `datamodels/serviceExceptions.py`, `coerceDocumentDataToBytes``shared/documentUtils.py`) aus `automation2.executors` **vor** Engine-Umzug | Boundary-Leck besteht weiter: Shared `methods/` importiert sie heute aufwärts |
| 2026-06-07 | Plan an Import-Refactoring (2026-06-05/06) angeglichen; Deferred-Liste aus `import-analyse.md` als Scope übernommen | refactor hat GE↔Engine-Coupling explizit an diesen Plan delegiert |
| 2026-06-05 | RBAC-Namespace **Option B** (beibehalten + System-DATA-Objekte), **kein** Flip | verhindert verwaiste `AccessRule`/Rollen-Zeilen |
| 2026-06-05 | Eigener **Write-RBAC-Helper** `_validateWorkflowAccess` (read/write) für die 39 Sites; GE-Feature-Rollen entfallen, Modell = Mandats-Mitgliedschaft/-Admin + `isPlatformAdmin` | Dashboard-Muster deckt nur Lesen; `instantiable=False` ⇒ keine Feature-Instanz-Rollen mehr |
| 2026-06-05 | **Modulares System** (editor/engine/scheduler/solutions/launcher/monitoring), gemappt auf L2L4; L1 (Actions/Execution) + Contracts bleiben geteilt | wartbar/nachvollziehbar; bündelt heute verstreute Automation-Teile + L3/L4 |
| 2026-06-05 | Code nach **`modules/workflowAutomation/`** (Platform) bzw. `pages/workflowAutomation/` + `components/workflowAutomation/` (UI); schrittweise via Re-Export-Shims | sauberer Schnitt; Imports brechen nicht |
| 2026-06-05 | `graphicalEditor` wird **System-Komponente** (Feature-Mantel entfällt) | kein DATA, eigene DB für alle Features, globaler Scheduler-Boot → ist Infrastruktur |
| 2026-06-05 | Eigene Top-Level-Nav-Gruppe **«Workflow-Automation»** mit Tab-Seiten | strukturiert an einem Ort, cross-mandate/-feature; nicht als Feature-Seite |
| 2026-06-05 | Scheduler-/Poller-Boot in **System-Lifespan** (`app.py`) statt Feature-`onStart` | Boot von der Feature-Plug-in-Mechanik lösen |
| 2026-06-05 | API mandatsweit `/api/workflow-automation/…`; RBAC = Mandats-Mitgliedschaft + System-Rollen + `isPlatformAdmin` | `{instanceId}` als RBAC-Anker abbauen; bestehende Dashboard-Muster wiederverwenden |
| 2026-06-05 | `AutoWorkflow.featureInstanceId` verliert RBAC-Bedeutung; `mandateId`+`runAsPrincipal` = Owner; `targetFeatureInstanceId`/per-Node-Ref bleiben | A0.1/A0.2; Daten-Scope bleibt funktional |
| 2026-06-05 | Migration **phasenweise, parallel** (kein Big-Bang); Bestand grandfathern | Risiko begrenzen, jederzeit lauffähig |
| 2026-06-05 | DB-Name `poweron_graphicaleditor` bleibt | YAGNI; Rename = unnötiges Risiko |
## Umsetzungs-Checkliste
**Phase A — Code-Migration (Copy to new locations + re-export shims):**
- [x] A2: `modules/workflows/automation2/*.py``modules/workflowAutomation/engine/` (executionEngine, graphUtils, runEnvelope, scheduleCron, graphicalEditorRunFileLogger, pickNotPushMigration, featureInstanceRefMigration, workflowArtifactVisibility, clickupTaskUpdateMerge, udmUpstreamShapes) *(2026-06-07)*
- [x] A2: `modules/workflows/automation2/executors/*.py``modules/workflowAutomation/engine/executors/` (actionNodeExecutor, inputExecutor, flowExecutor, triggerExecutor, ioExecutor, dataExecutor) *(2026-06-07)*
- [x] A3: `modules/workflows/scheduler/mainScheduler.py``modules/workflowAutomation/scheduler/mainScheduler.py` *(2026-06-07)*
- [x] A5: `modules/features/graphicalEditor/{portTypes,adapterValidator,nodeRegistry,nodeAdapter,switchOutput,entryPoints,conditionOperators,upstreamPathsService,_workflowFileSchema}.py``modules/workflowAutomation/editor/` *(2026-06-07)*
- [x] A5: `modules/features/graphicalEditor/nodeDefinitions/*.py``modules/workflowAutomation/editor/nodeDefinitions/` *(2026-06-07)*
- [x] A5: `modules/features/graphicalEditor/emailPoller.py``modules/workflowAutomation/scheduler/emailPoller.py` *(2026-06-07)*
- [x] Re-export shims created at old `__init__.py` locations for backward compatibility
**Phase F — Delete old originals (cleanup):**
- [x] F1: Deleted all individual .py files from `modules/features/graphicalEditor/` (shims: interfaceFeatureGraphicalEditor.py, mainGraphicalEditor.py; originals: portTypes, adapterValidator, nodeRegistry, nodeAdapter, switchOutput, entryPoints, conditionOperators, upstreamPathsService, _workflowFileSchema, emailPoller + all nodeDefinitions/*.py) *(2026-06-07)*
- [x] F2: Deleted all individual .py files from `modules/workflows/automation2/` and `executors/` (executionEngine, graphUtils, runEnvelope, scheduleCron, graphicalEditorRunFileLogger, pickNotPushMigration, featureInstanceRefMigration, workflowArtifactVisibility, clickupTaskUpdateMerge, udmUpstreamShapes + 6 executor files) *(2026-06-07)*
- [x] F3: Deleted `modules/workflows/scheduler/mainScheduler.py` *(2026-06-07)*
- [x] F4: `nodeDefinitions/__init__.py` converted to re-export shim (imports STATIC_NODE_TYPES from new location)
- [x] F4: `routeWorkflowAutomation.py` imports updated to `modules.workflowAutomation.editor._workflowFileSchema`
- [x] `automation2/__init__.py`, `automation2/executors/__init__.py`, `scheduler/__init__.py` retained as re-export shims → backward compat for remaining importers
- [x] `datamodelFeatureGraphicalEditor.py` gelöscht (keine Caller mehr) *(2026-06-08)*
- [x] Test file imports (`tests/unit/`, `tests/integration/`, `tests/demo/`) updated to canonical `modules.workflowAutomation.*` paths *(2026-06-08)*
**Phase D — Frontend Struktur (D1-D3):**
- [x] D1: `WorkflowAutomationPage.tsx` monolith (1566 lines) split into `pages/workflowAutomation/` with Hub + 5 tab components + types.ts *(2026-06-08)*
- [x] D2: Editor views re-exported from `pages/workflowAutomation/views/` *(2026-06-08)*
- [x] D3: FlowEditor components re-export shim at `components/workflowAutomation/FlowEditor/` *(2026-06-08)*
**Phase A10 — RBAC Namespace Migration (Boot-integriert):**
- [x] `_migrateRbacNamespace()` as idempotent routine in `onBootstrap()` — migrates AccessRule objectKeys from `feature.graphicalEditor` to `system.workflowAutomation` on every boot *(2026-06-08)*
- [x] `TABLE_NAMESPACE` in `interfaceRbac.py` updated from `feature.graphicalEditor` to `system.workflowAutomation` *(2026-06-08)*
- [x] Standalone script `scripts/script_db_migrate_rbac_workflow_automation.py` retained as manual fallback *(2026-06-07)*
**Cleanup — Stale DEPRECATED-Bereinigung:**
- [x] Stale DEPRECATED-Kommentare entfernt: `i18nBootSync.py` (2x), `workflowTools.py` (5x) — Imports zeigen bereits auf `modules.workflowAutomation.*` *(2026-06-08)*
- [x] `resource.store.graphicalEditor``resource.store.workflowAutomation` in `interfaceBootstrap.py` + `mainSystem.py` *(2026-06-08)*
- [x] `toolboxRegistry.py`: `featureCode="graphicalEditor"``"workflowAutomation"` *(2026-06-08)*
- [x] `datamodelFeatureGraphicalEditor.py` gelöscht (toter Re-Export-Shim, keine Caller) *(2026-06-08)*
- [x] `nodeDefinitions/__init__.py`: DEPRECATED-Label durch neutrales Shim-Label ersetzt *(2026-06-08)*
- [x] `routeWorkflowAutomation.py`: fehlender `DatabaseConnector`-Import ergänzt (Boot-Fix) *(2026-06-08)*
- [x] `routeWorkflowAutomation.py`: staler Import `modules.workflows.automation2.runEnvelope``modules.workflowAutomation.engine.runEnvelope` *(2026-06-08)*
- [x] `graphicalEditorRunFileLogger.py``runFileLogger.py` umbenannt + alle 4 Import-Stellen aktualisiert *(2026-06-08)*
- [x] `graphicalEditorDatabase` Alias in `interfaceWorkflowAutomation.py` entfernt (kein Caller) *(2026-06-08)*
- [x] Alle verbliebenen `graphicalEditor`-Kommentare/Docstrings in 7 Backend-Dateien neutralisiert *(2026-06-08)*
- [x] Demo-Configs: `graphicalEditor` aus Feature-Listen entfernt (`pwgDemo2026.py`, `investorDemo2026.py`) *(2026-06-08)*
- [x] Frontend: `console.error('[graphicalEditor]``'[workflowAutomation]` (6 Stellen), Kommentare aktualisiert *(2026-06-08)*
- [x] `_FEATURES_WITH_EDITOR`: `'graphicalEditor'` entfernt (WA ist kein Feature; nur `'workspace'` verbleibt) *(2026-06-08)*
- [x] Test-Dateien: `graphicalEditor` aus Parametrize-Listen und Assertions entfernt *(2026-06-08)*
- [x] UDB-Surface `'graphEditor'``'workflowAutomation'` (UnifiedDataBar.tsx, FilesTab.tsx, Automation2FlowEditor.tsx) *(2026-06-08)*
- [x] `Automation2FlowEditor.tsx`: 12 stale `instanceId`-Parameter aus API-Calls entfernt (API war bereits migriert) *(2026-06-08)*
- [x] `FilesTab.tsx`: `importWorkflowFromFile` Signatur korrigiert (stale `instanceId` entfernt) *(2026-06-08)*
- [x] Log-Prefixe `[automations]``[workflowAutomation]` in RunsTab.tsx + WorkflowsTab.tsx *(2026-06-08)*
- [x] Dead code entfernt: `WorkflowTasksPage.tsx` (942 LOC), `WorkflowTasks.module.css` *(2026-06-08)*
- [x] UDB generifiziert: `UdbSurface``string` (kein hardcoded Feature-Enum mehr); Workflow-Import-Logik aus `FilesTab.tsx` entfernt → Consumer (`Automation2FlowEditor`) uebernimmt via `onFileSelect`; `onWorkflowImportedFromFile` Prop entfernt *(2026-06-08)*
**Phase 0 — Scheduler-Boot entkoppeln (risikoarm, zuerst):**
- [x] Scheduler-Start in System-Lifespan (`app.py`, **nach** `setSchedulerMainLoop`/`eventManager.start()`); Poller bleibt **on-demand** (`ensureRunning`), `onStop`-Stop verlagert (Scheduler + Email-Poller in `app.py` Shutdown Schritt 3.5); GE-`onStart`/`onStop` **entfernt** *(2026-06-07)*
- [x] Routen-Registrierung via `loadFeatureMainModules()` weiterhin aktiv (Feature-Mantel noch da)
- [ ] Smoke: **bestehende (grandfathered)** geplante Runs feuern weiterhin, auch ohne GE-Feature-Instanz im Mandanten → manuell testen bei nächstem Deploy
**Phase 0.5 — Delaminierung (vor jedem Code-Umzug):**
- [x] ~~`portTypes`/`PORT_TYPE_CATALOG` delaminieren~~**erledigt** durch Refactoring (`datamodels/datamodelPortTypes.py`, L1)
- [x] ~~Kanonische Models nach L1~~**erledigt** (`datamodels/datamodelWorkflowAutomation.py`)
- [x] `PauseForHumanTaskError` + `PauseForEmailWaitError``datamodels/serviceExceptions.py` (kanonisch); Re-Export-Shim in `automation2/executors/inputExecutor.py`; Caller `methods/methodContext/actions/setContext.py` umgebogen *(2026-06-07)*
- [x] `coerceDocumentDataToBytes` + `_looksLikeAsciiBase64Payload``shared/documentUtils.py` (kanonisch); Re-Export-Shim in `automation2/executors/actionNodeExecutor.py`; Caller `methods/methodFile/actions/create.py` umgebogen *(2026-06-07)*
- [x] Guard-Test: `modules.workflows.{methods.methodContext.actions.setContext, methods.methodFile.actions.create}` importierbar **ohne** `modules.workflows.automation2.*` → bestätigt, kein `automation2`-Modul transitiv geladen *(2026-06-07)*
- [x] Node-Katalog (`STATIC_NODE_TYPES`, `features/graphicalEditor/nodeDefinitions/`): moved to `workflowAutomation/editor/nodeDefinitions/`; old `__init__.py` converted to re-export shim; cross-Caller `system/i18nBootSync.py` + `serviceAgent/workflowTools.py` work via shim *(2026-06-07)*
**Phase 1 — Mandatsweite API + System-RBAC (parallel zur Bestands-API):**
- [x] `AutoWorkflow.runAsPrincipal` in `datamodels/datamodelWorkflowAutomation.py` ergänzt (Optional[str], nullable, softFk → UserInDB)
- [x] System-RBAC + Nav-Block: `workflowAutomation` Section (order 25) mit 5 UI-Objekten (`ui.system.workflowAutomation.{workflows,editor,templates,runs,tasks}`) in `datamodelNavigation.py`; automatisch von `_buildUiObjectsFromNavigation` in RBAC-Katalog aufgenommen
- [x] Neue Routen `routeWorkflowAutomation.py`: `/api/workflow-automation/{workflows,versions,runs,tasks,steps}` (10 Endpunkte) mandatsweit; **Write-RBAC-Helper** `_validateWorkflowAccess(context, workflow, action)` (read = mandate-member, write/execute/delete = mandate-admin), `isPlatformAdmin`-Bypass; registriert in `app.py`
- [x] Scheduler **von `featureInstanceId` entkoppelt**: `if not instanceId`-Guard in `mainScheduler._syncScheduledWorkflows` entfernt; `instanceId` default `""` statt skip; Bestand läuft weiter
- [x] Runtime-Mandatsvalidierung beim `FeatureInstanceRef`-Auflösen: `_validateFeatureInstanceMandates()` in `executionEngine.py` nach `materializeFeatureInstanceRefs()` — defence-in-depth warning-log bei cross-mandate-Referenzen (A0.2)
**Phase 2 — UI «Workflow-Automation»-Gruppe:**
- [x] Nav-Block `workflowAutomation` in `datamodels/datamodelNavigation.py` (`NAVIGATION_SECTIONS`) — bereits in Phase 1 erledigt
- [x] `/workflow-automation`-Route + `WorkflowAutomationPage.tsx` Hub-Seite mit Tabs (Workflows · Läufe · Tasks), `?tab=`-Deeplinks; Import in `App.tsx`
- [x] Icons in `pageRegistry.tsx` für `page.system.workflowAutomation.*` registriert (FaSitemap, FaProjectDiagram, FaCopy, FaPlay, FaTasks)
- [x] `MandateNavigation.tsx`: `extraStaticBlocks`-Logik — unbekannte statische Blöcke werden als eigene Nav-Sektionen gerendert (nicht mehr in System-Block gemergt)
- [x] Kontext-Selector (Alle Mandanten / Mandant X) im Hub — BillingDataView-Pattern; `selectedMandateId` an alle Tabs *(2026-06-08)*
- [x] Editor-Entkopplung: `mandateId` ist primaerer Kontext; `instanceId` nur noch Access-Gate fuer Workspace-Datasource-APIs *(2026-06-08)*
- [x] WorkflowsTab/RunsTab: Server-seitige Mandantenfilterung via `mandateId`-Query-Param *(2026-06-08)*
- [x] TasksTab im Hub verdrahtet (neue API `/api/workflow-automation/tasks`) *(2026-06-08)*
- [x] WorkflowsTab Edit-Navigation korrigiert: `/workflow-automation?tab=editor&workflowId=...` (statt mandate-scoped Feature-Route) *(2026-06-08)*
- [x] `_FEATURES_WITH_EDITOR`: `'workflowAutomation'` entfernt (ist kein Feature) *(2026-06-08)*
- [x] Dead code entfernt: `WorkflowTasksPage.tsx` (942 LOC, instance-scoped legacy), `WorkflowTasks.module.css` *(2026-06-08)*
- Keep-Alive fuer Editor-Tab: separate Iteration (aktuell wird der gesamte Hub kept-alive)
**Phase 3 — DB & Datenmigration:**
- [x] `AutoWorkflow.featureInstanceId``Optional[str]` (default=None, softFk=True); Pydantic-only, **kein DDL** — Spalte bereits DB-nullable
- [x] Cascade-Delete: `_cascadeDeleteAutoWorkflow` in `routeWorkflowDashboard.py` ist bereits mandatsweit (löscht nach workflowId, unabhängig von featureInstanceId)
**Phase 4 — Feature-Mantel deprecaten (nicht entfernen — Koexistenz):**
- [x] GE-Hardcode in `routeSystem.py` als DEPRECATED markiert (bleibt für bestehende Feature-Instanzen)
- [x] Import-Umstellung: `routeWorkflowDashboard.py`, `routeAutomationWorkspace.py`, `routeSystem.py` importieren Models aus kanonischer `datamodels.datamodelWorkflowAutomation` statt aus `features.graphicalEditor.datamodelFeatureGraphicalEditor`
- Bestehende Feature-Routen `/api/workflows/{instanceId}/…` bleiben aktiv (Koexistenz mit neuer mandatsweiter API)
- Feature-Registration (`getFeatureDefinition`, `UI_OBJECTS`, Store) bleibt — wird erst bei vollständiger Migration entfernt
**Abschluss:**
- [x] `_CHANGELOG.md` aktualisiert
## Akzeptanzkriterien
| # | Kriterium (Given-When-Then) | Prio |
|---|---|---|
| 1 | Given ein Mandant ohne GE-FeatureInstanz, When ein **bestehender (grandfathered)** geplanter Workflow fällig ist, Then feuert der Scheduler (Boot via System-Lifespan). *(Instanz-freie Workflows: erst nach Phase-1-Scheduler-Entkopplung.)* | must |
| 2 | Given ein User mit Mandats-Mitgliedschaft, When er «Workflow-Automation» öffnet, Then sieht er eine Top-Level-Gruppe mit Tabs (Editor/Vorlagen/Workflows/Läufe/Tasks) — **nicht** pro Mandant/Instanz dupliziert | must |
| 3 | Given mehrere Mandanten/Features, When er Workflows/Läufe ansieht, Then sind sie cross-mandate/-feature gelistet, RBAC-gefiltert (Mandats-Admin/`isPlatformAdmin`) | must |
| 4 | Given Bestands-Workflows/Runs/Tasks, When migriert wurde, Then bleiben sie aufrufbar/ausführbar; `targetFeatureInstanceId` unverändert wirksam | must |
| 5 | Given ein Run über mehrere Trustee-Instanzen, When er läuft, Then bucht `recordUsage` je Node die berührte Instanz (nicht fix `graphicalEditor`) | must |
| 6 | Given kein `graphicalEditor`-Feature mehr, When der Store geöffnet wird, Then erscheint keine GE-Karte; bestehende Mandanten verlieren keine Workflows | must |
| 7 | Given ein geplanter Run, When er ausgeführt wird, Then unter definierter Automations-Identität (nicht globaler Sysadmin); Reads nur im RBAC-Umfang des Principals | must |
| 8 | Given die neue API, When ein Node eine fremd-mandatige Instanz-UUID trägt, Then Laufzeit-Fehler (Mandatsgrenze) | should |
## Testplan
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | platform-core/tests/.../scheduler | pending |
| T2 | 3 | api | ja | platform-core/tests/.../workflowAutomation | pending |
| T3 | 4 | migration | ja | platform-core/tests/.../migration | pending |
| T4 | 5 | unit | ja | platform-core/tests/.../billing | pending |
| T5 | 2 | e2e/manual | nein | ui-nyla | pending |
## Offene Fragen
1. **RBAC-Granularität (grösstenteils entschieden):** Modell = Mandats-Mitgliedschaft + Mandats-Admin + `isPlatformAdmin`; GE-Feature-Rollen (`graphicalEditor-*`) entfallen. Offen nur: brauchen Power-User ohne Admin eine eigene System-Rolle `workflowAutomation-user`, oder genügt Mandats-`user`? (Feature-Instanz-Rollen sind keine Option mehr — `instantiable=False` + `rbac-role-separation.mdc`.)
2. **API-Pfad:** ~~`/api/workflow-automation/…` neu vs. bestehendes `/api/system/workflow-runs` ausbauen — konsolidieren?~~ **Entschieden (2026-06-08):** `/api/workflow-automation/…` ist der kanonische Pfad. `routeWorkflowAutomation.py` registriert alle Endpunkte dort. `/api/system/workflow-runs` bleibt als Legacy-Alias (Dashboard).
3. **Run-as-Principal-Verwaltung:** Ersteller-Identität vs. dedizierter Service-Principal (siehe CustomerCases offene Frage #1).
4. **Alt-URLs:** wie lange Redirects der `{instanceId}`-Pfade halten (Bookmarks/Deeplinks)?
5. **Datei-/Doku-Rename:** dieses Plan-Dokument ggf. auf `…-workflowautomation-system-component.md` umbenennen (aktuell `…-automation-system-component.md`) — Konsistenz vs. Referenz-Churn.
## Links
- Architektur/Entscheid: `c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md` (A0.4), `…-step3-features-plan.md` (A0)
- Prior Art: `c-work/4-done/2026-04-automation-unification.md`, `2026-04-automation-central-admin.md`, `2026-04-generic-graph-editor.md`
- Code (Backend): `modules/workflowAutomation/{editor,engine,scheduler}/`, `modules/datamodels/{datamodelPortTypes,datamodelWorkflowAutomation,datamodelNavigation}.py`, `modules/routes/{routeWorkflowAutomation,routeWorkflowDashboard,routeAutomationWorkspace,routeSystem}.py`, `app.py`
- Import-/Layer-Stand (Refactoring 2026-06-05/06, inkl. Deferred-Liste für diese Komponente): `local/notes/refernce-analysis/platform-core-import-analyse.md`
- Code (Frontend): `ui-nyla/src/pages/AutomationsDashboardPage.tsx`, `components/Navigation/MandateNavigation.tsx`, `pages/FeatureView.tsx`, `App.tsx`
- RBAC: `b-reference/platform/rbac.md`, `.cursor/rules/rbac-role-separation.mdc`, `.cursor/rules/feature-instance-scoping.mdc`
## Abschluss
- [x] `b-reference/platform/workflowAutomation.md`: Kanon-Seite aktualisiert (Code-Pfade, API, RBAC, Navigation) *(2026-06-08)*
- [x] `.cursor/rules/rbac-role-separation.mdc` + `feature-instance-scoping.mdc`: WorkflowAutomation als dokumentierte Ausnahme eingetragen *(2026-06-08)*
- [x] `topics-todo.md` aktualisiert (WorkflowAutomation = System-Komponente, DONE) *(2026-06-08)*
- [x] `features/graphicalEditor/` Verzeichnis komplett gelöscht (keine Dateien, keine Caller) *(2026-06-08)*
- [x] **Cross-Import Assessment**:
- [x] `workflows -> features.graphicalEditor` (~40 Imports): eliminiert — alle Imports auf `modules.workflowAutomation.*` *(2026-06-08)*
- [x] `serviceCenter -> features.graphicalEditor` (5x workflowTools): eliminiert — kanonische Pfade *(2026-06-08)*
- [x] `interfaces/interfaceDbManagement.py:936` -> `workflowArtifactVisibility`: erledigt — `modules.workflowAutomation.engine.workflowArtifactVisibility` *(2026-06-08)*
- [x] Re-Export-Shims: `datamodelFeatureGraphicalEditor.py` gelöscht; `stateTools.py` Shim bleibt (7 Caller via `processing/shared/`, nicht Teil dieser Migration) *(2026-06-08)*
- [x] Keine `from modules.features.graphicalEditor` oder `from modules.workflows.automation2` Imports mehr im gesamten Codebase (verifiziert via grep) *(2026-06-08)*
- [ ] Lazy Imports in `workflows/` reduzieren (separates Refactoring-Thema, nicht Teil dieser Migration)
- [ ] Dieses Dokument → `4-done/` verschieben