From c654001f0165ca22b61aaf3f42daadbcb6447b7d Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Sun, 7 Jun 2026 22:26:29 +0200 Subject: [PATCH] before refactory workflowAutomation --- b-reference/platform/workflowAutomation.md | 65 +++++++++ .../2026-06-automation-system-component.md | 125 ++++++++++-------- c-work/_CHANGELOG.md | 7 + 3 files changed, 144 insertions(+), 53 deletions(-) create mode 100644 b-reference/platform/workflowAutomation.md rename c-work/{1-plan => 2-build}/2026-06-automation-system-component.md (64%) diff --git a/b-reference/platform/workflowAutomation.md b/b-reference/platform/workflowAutomation.md new file mode 100644 index 0000000..6d460a5 --- /dev/null +++ b/b-reference/platform/workflowAutomation.md @@ -0,0 +1,65 @@ + + + +# WorkflowAutomation (System-Komponente) + +## Überblick + +**WorkflowAutomation** ist die mandanten- und feature-übergreifende Orchestrierungs-Infrastruktur der Plattform. Sie wurde aus dem ehemaligen Feature `graphicalEditor` extrahiert, da dieses keine Domänen-/Kundendaten hält, sondern ausschliesslich Orchestrierungs-Metadaten (`AutoWorkflow`, `AutoRun`, `AutoTask`) verwaltet und beim App-Start den globalen Scheduler bootet. + +**Warum System-Komponente:** `graphicalEditor` war ein Hybrid — formal Feature mit `FeatureInstance`-RBAC, architektonisch aber System-Infrastruktur (eigene DB `poweron_graphicaleditor`, globaler Scheduler, cross-instance Workflows). Die Solution-Schicht (CustomerCases) verankert Ownership an Mandant + Principal; das Feature-Modell kollidiert damit. + +## Architektur + +- **System-Lifespan Boot:** Scheduler- und Email-Poller-Start in `app.py` (nicht mehr Feature-`onStart`). +- **Mandatsweite API:** `/api/workflow-automation/{workflows,versions,runs,tasks,steps}` — kein `{instanceId}` als RBAC-Anker. +- **RBAC-Modell:** Mandats-Mitgliedschaft (read), Mandats-Admin (write/execute/delete), `isPlatformAdmin`-Bypass. Keine Feature-Instanz-Rollen; `instantiable=False`. +- **DB-Scoping:** `AutoWorkflow.mandateId` + `runAsPrincipal` (Owner). `targetFeatureInstanceId` + per-Node `FeatureInstanceRef` bleiben als Daten-Scope. + +## Code-Pfade + +| Schicht | Pfad | +|---------|------| +| Routen (mandatsweit) | `platform-core/modules/routes/routeWorkflowAutomation.py` | +| Models (kanonisch, L1) | `platform-core/modules/datamodels/datamodelWorkflowAutomation.py` | +| Navigation-Sektion | `platform-core/modules/datamodels/datamodelNavigation.py` (Block `workflowAutomation`) | +| Feature-Mantel (deprecated) | `platform-core/modules/features/graphicalEditor/` | +| Graph-Engine | `platform-core/modules/workflows/automation2/` | +| Scheduler | `platform-core/modules/workflows/scheduler/` | +| Frontend | `ui-nyla/src/pages/WorkflowAutomationPage.tsx` | + +## API + +**Basis-Pfad:** `/api/workflow-automation/` + +| Methode | Pfad | Beschreibung | +|---------|------|--------------| +| GET | `/workflows` | Workflows mandatsweit (RBAC-gefiltert) | +| GET | `/workflows/{id}` | Einzelner Workflow | +| GET | `/versions/{workflowId}` | Versionen eines Workflows | +| GET | `/runs` | Läufe mandatsweit | +| GET | `/runs/{id}` | Einzelner Run | +| GET | `/tasks` | Human-Tasks mandatsweit | +| POST | `/tasks/{id}/complete` | Task abschliessen | +| GET | `/steps/{runId}` | Step-Logs eines Runs | +| DELETE | `/workflows/{id}` | Workflow + Cascade löschen | +| DELETE | `/runs/{id}` | Run + Steps löschen | + +## Navigation + +Statischer Block `workflowAutomation` (order 25) mit UI-Objekten: +- `page.system.workflowAutomation.workflows` +- `page.system.workflowAutomation.editor` +- `page.system.workflowAutomation.templates` +- `page.system.workflowAutomation.runs` +- `page.system.workflowAutomation.tasks` + +## Migration + +Feature-Routen `/api/workflows/{instanceId}/…` bleiben aktiv (Koexistenz). Die GE-Feature-Registrierung (Store, `TEMPLATE_ROLES`, `UI_OBJECTS`) ist DEPRECATED, wird aber für bestehende Instanzen noch ausgeliefert. Vollständige Entfernung des Feature-Mantels erfolgt nach Abschluss der Datenmigration. + +## Siehe auch + +- Plan-Dokument: `c-work/2-build/2026-06-automation-system-component.md` +- RBAC: `b-reference/platform/rbac.md` +- Navigation: `b-reference/platform/navigation.md` diff --git a/c-work/1-plan/2026-06-automation-system-component.md b/c-work/2-build/2026-06-automation-system-component.md similarity index 64% rename from c-work/1-plan/2026-06-automation-system-component.md rename to c-work/2-build/2026-06-automation-system-component.md index fc4d437..8fbeff5 100644 --- a/c-work/1-plan/2026-06-automation-system-component.md +++ b/c-work/2-build/2026-06-automation-system-component.md @@ -22,6 +22,22 @@ **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 L0–L7** 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. @@ -30,7 +46,7 @@ - **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 statt Boundary-Leck (Code-verifiziert).** `graphicalEditor/portTypes` (`PORT_TYPE_CATALOG`) und der Node-Katalog (`STATIC_NODE_TYPES`) werden vom **geteilten** Layer + Chats genutzt (`methods/methodBase.py`, `processing/shared/parameterValidation.py`, `serviceAgent/actionToolAdapter.py`, `shared/i18nRegistry.py`) — sie dürfen **nicht** in die Komponente, sonst importiert Shared/Chat *aufwärts*. Zudem liegen zwei Helfer (`PauseForHumanTaskError`, `_coerce_document_data_to_bytes`) in `automation2.executors`, werden aber von `methods/` importiert → **vor** dem Engine-Umzug in den Shared-Layer **delaminieren**. +- **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 @@ -80,15 +96,15 @@ Die Komponente bündelt die bestehenden, heute verstreuten **Automation**-Teile | L4 | **monitoring** | Läufe, Tasks, Logs (Ops-Sicht) | > **NICHT Teil der Komponente (geteilt, Code-verifiziert) — Komponente *konsumiert* abwärts:** -> - **L1 Toolbox** = `workflows/methods/` (Actions) + `workflows/processing/` (ActionExecutor, methodDiscovery, modes) — von Chats/Agents genutzt. -> - **Shared Contracts** = `portTypes`/`PORT_TYPE_CATALOG` + Node-Katalog/`STATIC_NODE_TYPES` — von methods/processing/chats/i18n genutzt; bleibt im Shared-Layer (neu `workflows/workflowContracts/`). Die Komponente besitzt sie **nicht**. +> - **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) -├─ datamodelWorkflowAutomation.py # AutoWorkflow / AutoVersion / AutoRun / AutoTask (+ Legacy-Aliase) +├─ 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) @@ -96,19 +112,21 @@ modules/workflowAutomation/ # NEU — die Automation-Komponente ├─ solutions/ # L3 — solutionService, datamodelSolution (Settings-Injektion, run-as-Principal) └─ launcher/ # L4 — Katalog/Templates + AI-Erstellung + Template-Instanziierung -modules/workflows/ # BLEIBT — geteilt (NICHT Teil der Komponente) -├─ methods/ # L1 — Actions (methodAi/Trustee/Sharepoint/Outlook/File/Context/Clickup/Jira/Redmine) -├─ processing/ # L1 — ActionExecutor, methodDiscovery, modes/adaptive, workflowProcessor -├─ workflowContracts/ (NEU) # Shared Contracts: portTypes (PORT_TYPE_CATALOG) + Node-Katalog (STATIC_NODE_TYPES) -│ # — heute in graphicalEditor/, hierher delaminieren (genutzt von methods/processing/chats/i18n) -└─ workflowManager.py # Chat-/Agent-seitige Workflow-Verarbeitung +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. -> - **Shared Contracts (neu zu delaminieren):** `portTypes`/`PORT_TYPE_CATALOG` und der Node-Katalog/`STATIC_NODE_TYPES` liegen heute unter `graphicalEditor/`, werden aber von `methods/methodBase.py`, `processing/shared/parameterValidation.py`, `serviceAgent/actionToolAdapter.py` und `shared/i18nRegistry.py` genutzt → **bleiben geteilt** (`workflows/workflowContracts/`); die Komponente konsumiert sie. -> - **Korrektur eines früheren Fehlers:** «`automation2` wird von Chats nicht importiert» war **falsch**. `methods/methodFile/actions/create.py` + `methods/methodContext/actions/setContext.py` importieren `automation2.executors` (`_coerce_document_data_to_bytes`, `PauseForHumanTaskError`) top-level — geladen via `methodDiscovery` im Chat-/Agent-Pfad. **Diese zwei Helfer vor dem Engine-Umzug in den Shared-Layer extrahieren** (Delaminierung), sonst importiert Shared aufwärts in die Komponente. +> - **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). @@ -146,20 +164,20 @@ api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workfl - **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` + `_coerce_document_data_to_bytes` aus `automation2/executors/` in den Shared-Layer; `portTypes`/Node-Katalog (`STATIC_NODE_TYPES`) aus `graphicalEditor/` nach `workflows/workflowContracts/`. Erst dann ist der Engine-Umzug aufwärts-importfrei. + - **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}/` + `workflowContracts/` bleiben** geteilt — **nicht** verschieben. + - **`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/system/mainSystem.py` — `NAVIGATION_SECTIONS`: Block `id="workflowAutomation"` (order ~25) + `ui.system.workflowAutomation.*`-Objekte; Store-Eintrag `resource.store.graphicalEditor` entfernen. - - `modules/interfaces/interfaceFeatures.py` — `_copyTemplateWorkflows` läuft heute bei **FeatureInstance-Erstellung** und stempelt `{{featureInstanceId}}`/`targetFeatureInstanceId` (auch für Trustee/Redmine). Ohne GE-Instanz **entfällt der Trigger** → Template-Instanziierung explizit in den `launcher/`-Flow verlagern (inkl. Demo-Bootstrap); Trustee/Redmine-Platzhalter-Vertrag beachten. - - `modules/interfaces/interfaceDbApp.py` — Mandate-Delete-Cascade für WorkflowAutomation-Daten mandatsweit (statt per GE-Instanz; Vorbild `_cascadeDeleteAutoWorkflow`). + - `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-*`. - - `modules/features/graphicalEditor/mainGraphicalEditor.py` `getGraphicalEditorServices` — `featureCode`/`featureInstanceId` im Hub: Billing **per-Node** auf berührte Instanz (A0.2, Executor-Change), Mandate = `mandateId`. - - `serviceCenter/.../toolboxRegistry.py` — `ToolboxDefinition(featureCode="graphicalEditor")` → `workflowAutomation`. - - **Weitere GE-Importer (oft übersehen):** `shared/i18nRegistry.py` (zieht `STATIC_NODE_TYPES`/`PORT_TYPE_CATALOG` → nach Delaminierung auf `workflowContracts` umbiegen), `routeSystem.py` (`UI_OBJECTS` + Dashboard-`_ensureTableExists`), `routeAdminFeatures.py`, `interfaceDbManagement.py`, `interfaceFeatureGraphicalEditor.getAllWorkflowsForScheduling` (Lesepfad von Scheduler **und** Dashboard — stabil halten/shimmen). + - `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/.../*`. @@ -180,8 +198,9 @@ api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workfl | 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-05 | **Shared Contracts** (`portTypes`/`PORT_TYPE_CATALOG`, Node-Katalog) bleiben geteilt (`workflows/workflowContracts/`); Komponente konsumiert | Code-Beleg: methods/processing/chats/i18n nutzen sie — Verschieben = Aufwärts-Import | -| 2026-06-05 | **Delaminierung** zweier Helfer (`PauseForHumanTaskError`, `_coerce_document_data_to_bytes`) aus `automation2.executors` **vor** Engine-Umzug | sonst importiert Shared `methods/` aufwärts in die Komponente | +| 2026-06-07 | **Contracts/Models in `datamodels` (L1)** statt neuem `workflowContracts/` — durchs Import-Refactoring bereits erledigt (`datamodelPortTypes`, `datamodelWorkflowAutomation`) | Layer-Hierarchie L0–L7; 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 L2–L4; L1 (Actions/Execution) + Contracts bleiben geteilt | wartbar/nachvollziehbar; bündelt heute verstreute Automation-Teile + L3/L4 | @@ -197,45 +216,44 @@ api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workfl ## Umsetzungs-Checkliste **Phase 0 — Scheduler-Boot entkoppeln (risikoarm, zuerst):** -- [ ] Scheduler-Start in System-Lifespan (`app.py`, **nach** `setSchedulerMainLoop`; `eventUser` ist dort schon vorhanden); Poller bleibt **on-demand** (`ensureRunning`), nur `onStop`-Stop verlagern; GE-`onStart`/`onStop` entfernen -- [ ] Sicherstellen, dass das Komponenten-Modul weiter importiert wird (Routen-Registrierung) auch ohne Feature-Mantel -- [ ] Smoke: **bestehende (grandfathered)** geplante Runs feuern weiterhin, auch ohne GE-Feature-Instanz im Mandanten +- [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):** -- [ ] `PauseForHumanTaskError` + `_coerce_document_data_to_bytes` aus `automation2/executors/` in den Shared-Layer ziehen (Re-Export-Shim am alten Ort) -- [ ] `portTypes`/`PORT_TYPE_CATALOG` + Node-Katalog (`STATIC_NODE_TYPES`) → `workflows/workflowContracts/`; `i18nRegistry`, `methodBase`, `parameterValidation`, `actionToolAdapter` darauf umbiegen -- [ ] Guard-Test: `modules.workflows.{methods,processing}` + `serviceCenter` importieren **ohne** `modules.workflowAutomation.*` +- [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)* +- [ ] Node-Katalog (`STATIC_NODE_TYPES`, `features/graphicalEditor/nodeDefinitions/`): bleibt beim Editor, zieht mit ihm um; cross-Caller `system/i18nBootSync.py` + `serviceAgent/workflowTools.py` beachten **Phase 1 — Mandatsweite API + System-RBAC (parallel zur Bestands-API):** -- [ ] `AutoWorkflow.runAsPrincipal` ergänzen (additives `ADD COLUMN`, nullable) -- [ ] System-RBAC-Objekte `ui.system.workflowAutomation.*` + RESOURCE für `/api/workflow-automation/…`; DATA-Objekte unter **bestehendem** Namespace (Option B) -- [ ] Neue Routen `/api/workflow-automation/{workflows,versions,runs,tasks,nodes,…}` mandatsweit; **Write-RBAC-Helper** `_validateWorkflowAccess` (read = Dashboard-Scoping, write/execute eigens), `isPlatformAdmin`-Bypass -- [ ] Scheduler **von `featureInstanceId` entkoppeln**: `if not instanceId`-Guard (`mainScheduler.py`) entfernen, Interface/Services nicht mehr instanz-gekeyt auflösen, Ausführung über `targetFeatureInstanceId`/Mandant scopen -- [ ] Per-Node-Billing: berührte `FeatureInstanceRef` in den `recordUsage`-Kontext threaden (Executor-Change, AC5), Mandate = `mandateId` -- [ ] Run-as-Principal in Engine/Scheduler (statt globalem `event`-Sysadmin) + Read-RBAC analog Write-Pfad (A0.1) -- [ ] Runtime-Mandatsvalidierung beim `FeatureInstanceRef`-Auflösen (A0.2) +- [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:** -- [ ] Nav-Block `workflowAutomation` in `mainSystem.py` + Handling in `MandateNavigation.tsx` (Top-Level) -- [ ] `/workflow-automation/*`-Routen + Hub-Seite mit Tabs (Editor · Vorlagen · Workflows · Läufe · Tasks), `?tab=`-Deeplinks -- [ ] Mandanten-/Instanz-Scope-Selector in der Seite (kein per-Instanz-Nav) -- [ ] Editor-Komponenten von `useInstanceId()` lösen; Keep-Alive-Pfad umziehen -- [ ] Redirects alte → neue Pfade; Cross-Links (Trustee, Store) anpassen +- [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) +- Mandanten-Scope-Selector / Editor-Entkopplung / Keep-Alive: spätere Iteration (Editor braucht instanceId bis Feature-Mantel vollständig entfernt) **Phase 3 — DB & Datenmigration:** -- [ ] `AutoWorkflow.featureInstanceId` → `Optional` (Pydantic; **kein DDL** — Spalte bereits nullable, keine DB-FK); Routen/Queries auf leeren Wert tolerant machen; `validateFkTargets` tolerant -- [ ] `Solution`-Modell vorbereiten (A0.1 — Detail in CustomerCases-features-plan) -- [ ] Migrations-Skript: `FeatureAccess`-Grants → Mandats-Mitgliedschaft/-Rollen (GE-Feature-Rollen entfallen — **Sichtbarkeitsänderung dokumentieren**); `featureInstanceId`-RBAC-Bezug auflösen (Bestand grandfathern), `targetFeatureInstanceId` erhalten -- [ ] Mandate-Delete-Cascade mandatsweit (Vorbild `_cascadeDeleteAutoWorkflow`) +- [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 entfernen:** -- [ ] `getFeatureDefinition`/`registerFeature`/`TEMPLATE_ROLES`/`UI_OBJECTS`(feature)/Store-Eintrag entfernen; GE-Hardcode in `routeSystem.py` raus -- [ ] `FeatureView.tsx`-Eintrag + Store-Karte entfernen; Demo-Configs umstellen -- [ ] Alte `/api/workflows/{instanceId}/…`-Routen deprecaten/entfernen -- [ ] Tests grün (inkl. `tests/unit/graphicalEditor/*`, Demo-Bootstrap, Adapter-Drift) +**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:** -- [ ] `b-reference` aktualisieren; `_CHANGELOG.md` +- [x] `_CHANGELOG.md` aktualisiert ## Akzeptanzkriterien @@ -272,7 +290,8 @@ api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workfl - 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/features/graphicalEditor/`, `modules/workflows/{automation2,scheduler}/`, `modules/routes/{routeWorkflowDashboard,routeAutomationWorkspace,routeSystem}.py`, `modules/system/mainSystem.py`, `app.py` +- Code (Backend): `modules/features/graphicalEditor/`, `modules/workflows/{automation2,scheduler}/`, `modules/datamodels/{datamodelPortTypes,datamodelWorkflowAutomation,datamodelNavigation}.py`, `modules/routes/{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` diff --git a/c-work/_CHANGELOG.md b/c-work/_CHANGELOG.md index dc3c049..3117132 100644 --- a/c-work/_CHANGELOG.md +++ b/c-work/_CHANGELOG.md @@ -12,6 +12,13 @@ type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `platfor Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler. +## 2026-06-07 + +- 2026-06-07 | feat | platform-core, ui-nyla | **Phasen 1–4 ausgeführt (WorkflowAutomation-Plan)**: **Phase 1**: `AutoWorkflow.runAsPrincipal` (Optional), Nav-Block `workflowAutomation` (5 Items), mandatsweite API `routeWorkflowAutomation.py` (10 Endpunkte, `_validateWorkflowAccess` RBAC-Helper), Scheduler `if-not-instanceId`-Guard entfernt, `_validateFeatureInstanceMandates()` Guard in `executionEngine.py`. **Phase 2**: `WorkflowAutomationPage.tsx` Hub-Seite mit Tabs (Workflows/Läufe/Tasks), Route in `App.tsx`, Icons in `pageRegistry.tsx`, `MandateNavigation.tsx` rendert neue Nav-Sektionen als eigene Gruppen. **Phase 3**: `featureInstanceId` → `Optional[str]` (softFk). **Phase 4**: Route-Imports auf kanonische `datamodels.datamodelWorkflowAutomation` umgestellt (`routeWorkflowDashboard`, `routeAutomationWorkspace`, `routeSystem`); GE-Hardcode als DEPRECATED markiert. (c-work: c-work/1-plan/2026-06-automation-system-component.md) +- 2026-06-07 | feat | platform-core | **Phase 1 teilweise ausgeführt (WorkflowAutomation-Plan)**: `AutoWorkflow.runAsPrincipal` (Optional, nullable, softFk→UserInDB) in `datamodelWorkflowAutomation.py`. Nav-Block `workflowAutomation` (order 25, 5 Items) in `datamodelNavigation.py`. Neue mandatsweite API `routeWorkflowAutomation.py` mit 10 Endpunkten unter `/api/workflow-automation/` + Write-RBAC-Helper `_validateWorkflowAccess` (member=read, admin=write, isPlatformAdmin bypass). Scheduler `if-not-instanceId`-Guard in `mainScheduler.py` entfernt. Runtime-Mandatsvalidierung `_validateFeatureInstanceMandates()` in `executionEngine.py` (defence-in-depth, A0.2). (c-work: c-work/1-plan/2026-06-automation-system-component.md) +- 2026-06-07 | refactor | platform-core | **Phase 0 + 0.5 ausgeführt (WorkflowAutomation-Plan)**: Delaminierung erledigt — `PauseForHumanTaskError`/`PauseForEmailWaitError` → `datamodels/serviceExceptions.py`, `coerceDocumentDataToBytes` → `shared/documentUtils.py`, Re-Export-Shims in `automation2/executors/`, Cross-Boundary-Caller umgebogen. Scheduler-Boot von `mainGraphicalEditor.onStart` in System-Lifespan (`app.py`, nach `eventManager.start()`) verschoben; `onStart`/`onStop` aus `mainGraphicalEditor.py` entfernt; Scheduler- und Email-Poller-Stop in `app.py` Shutdown (Schritt 3.5). Guard-Test bestätigt: `methods/` lädt kein `automation2` mehr transitiv. (c-work: c-work/1-plan/2026-06-automation-system-component.md) +- 2026-06-07 | docs | wiki | **WorkflowAutomation-Plan an Import-Refactoring (2026-06-05/06) nachgeführt**: Codebase-Abgleich gegen `local/notes/refernce-analysis/platform-core-import-analyse.md`. Neue **Layer-Hierarchie L0–L7**; viele Plan-Vorarbeiten **bereits erledigt**: Contracts/Models nach `datamodels` (L1, `datamodelPortTypes`/`datamodelWorkflowAutomation`, statt geplantem `workflowContracts/`), Feature-Lifecycle-Hooks (`mainGraphicalEditor.onInstanceCreate/onMandateDelete/onBootstrap`, ex interfaceFeatures/interfaceDbApp/interfaceBootstrap), `NAVIGATION_SECTIONS`→`datamodels/datamodelNavigation`, `EventManager`/`parseInlineRuns`→shared, `serviceHub`→serviceCenter. GE↔Engine-Coupling wurde im Refactoring **explizit auf diesen Plan vertagt** (Deferred-Liste übernommen): `features.graphicalEditor↔workflows` (21/40), `serviceCenter→GE` (5× workflowTools), `interfaceDbManagement:936`, Re-Export-Shims. **Boundary-Leck besteht weiter**: `PauseForHumanTaskError`/`coerceDocumentDataToBytes` noch in `automation2/executors`, von `methods/` importiert → Delaminierung (→ `datamodels/serviceExceptions.py` bzw. `shared/documentUtils.py`) bleibt erster Schritt. Neuer Abschnitt «Code-Stand», Phase 0.5/Betroffene Module/Entscheidungen/Links angepasst. (c-work: c-work/1-plan/2026-06-automation-system-component.md) + ## 2026-06-05 - 2026-06-05 | docs | wiki | **WorkflowAutomation-Plan nach 2 kritischen Code-Reviews überarbeitet (+ Trennung Automation ↔ Execution)**: Zentrale Korrektur — **Automation** (Graph-Editor/Engine `automation2`/Scheduler/Solutions) und der geteilte **Workflow-Execution-Layer** (`workflows/methods`+`processing`, von reinen Chats/Agents genutzt) bleiben im Code getrennt; nur die Automation-Teile wandern in die Komponente. Frühere Aussage «`automation2` wird von Chats nicht importiert» als **falsch** korrigiert (shared `methods` importieren `automation2.executors`) → neue **Phase 0.5 Delaminierung** (`PauseForHumanTaskError`/`_coerce_document_data_to_bytes` + `portTypes`/`STATIC_NODE_TYPES` → neues geteiltes `workflows/workflowContracts/`). Weitere Review-Fixes: `featureInstanceId` ist **bereits DB-nullable** (kein DDL, keine DB-FK), Scheduler ist hart auf `featureInstanceId` gekeyt (Entkopplung als eigener Schritt), Dashboard-RBAC deckt nur Lesen → eigener Write-Helper `_validateWorkflowAccess` für 39 Sites, RBAC-Namespace **Option B** (kein Flip), Template-Instanziierungs-Trigger (`_copyTemplateWorkflows`) wandert in `launcher/`, per-Node-Billing als bewusste Executor-Ausnahme, `.cursor/rules/*` aktualisieren. (c-work: c-work/1-plan/2026-06-automation-system-component.md)