48 KiB
WorkflowAutomation als System-Komponente — graphicalEditor raus aus dem Feature-Modell
Migration Status: COMPLETE (2026-06-08). Alle
graphicalEditor-Code-Referenzen eliminiert. Code ausfeatures/graphicalEditor/,workflows/automation2/,workflows/scheduler/verschoben nachmodules/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.pygelö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.mdA0.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-TokenWorkflowAutomation/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/AutoRunsind Orchestrierungs-Metadaten (eigene DBpoweron_graphicaleditor). - Einziges Feature mit
onStart/onStop— bootet beim App-Start den globalen Scheduler (Email-Poller startet on-demand viaemailPoller.ensureRunning, gestoppt inonStop). - Scheduler/Engine liegen ohnehin unter
modules/workflows/(System), nicht im Feature. getWorkflows()filtert nur nachmandateId(«cross-instance»); ein Graph referenziert legitim mehrere Features/Instanzen über per-NodeFeatureInstanceRef.- 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 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-Shimfeatures/graphicalEditor/datamodelFeatureGraphicalEditor.py, 7 Caller). → Das geplante «Shared Contracts»-Modul ist faktischdatamodels(L1); kein neuesworkflowContracts/nötig. - Feature-Lifecycle-Hooks existieren:
mainGraphicalEditor.onInstanceCreate()(Template-Copy, exinterfaceFeatures._copyTemplateWorkflows),onMandateDelete()(Cascade, exinterfaceDbApp),onBootstrap()(Seeding, exinterfaceBootstrap) — dynamisch viashared/featureDiscovery.loadFeatureMainModules(). → Plan-Touchpoints ininterfaceFeatures/interfaceDbApp/interfaceBootstrapsind 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) undcoerceDocumentDataToBytes(automation2/executors/actionNodeExecutor.py) werden vonmethods/methodContext/actions/setContext.pybzw.methods/methodFile/actions/create.pytop-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. featureInstanceIdhat heute zwei Bedeutungen: (a) GE-Owner/RBAC-Scope aufAutoWorkflow, (b) Daten-Scope der Ausführung (targetFeatureInstanceId+ per-NodeFeatureInstanceRef). Nur (a) wird abgebaut; (b) bleibt — es ist die Cross-Feature-Referenz.- Kaum DDL nötig (Code-verifiziert). Tabellen werden ohne
NOT NULL(ausserid-PK) und ohne DB-FKs angelegt (connectorDbPostgre.py_create_table_from_model); FKs sind app-level (fkRegistry,app.pyvalidateFkTargets). Heisst:featureInstanceIdist schon jetzt DB-nullable → «nullable machen» ist nurOptional[str]im Pydantic-Modell (datamodelFeatureGraphicalEditor.py) + Query-/Code-Anpassungen, keine Migration.runAsPrincipal= additivesADD COLUMN(von_ensureTableExistsabgedeckt). Echte Arbeit = Application-Logik (Routen/Queries, diefeatureInstanceIdvoraussetzen), nicht Schema. - Bestehende Daten grandfathern.
AutoWorkflow-Zeilen tragenfeatureInstanceId;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 inrouteFeatureGraphicalEditor.pysind 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_CATALOGliegt seit dem Refactoring indatamodels/datamodelPortTypes.py(erledigt). Der Node-Katalog (STATIC_NODE_TYPES) ist noch unterfeatures/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 inautomation2.executors, werden aber vonmethods/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:
graphicalEditorals System-KomponenteWorkflowAutomationfü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ührteFeatureInstanceRefin denrecordUsage-Kontext threaden) — kein Graph-/Semantik-Umbau. - Explizit NICHT: den geteilten Workflow-Execution-Layer (
workflows/methods/,workflows/processing/) in die Komponente ziehen — er bleibt untermodules/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_graphicaleditorbleibt). - Explizit NICHT: bestehende «Automation»-Code-Namen umbenennen (
AutomationsDashboardPage,routeAutomationWorkspace,workflows/automation2) — nur die neue Komponente trägt das TokenWorkflowAutomation.
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 L2–L4-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-KatalogSTATIC_NODE_TYPESliegt 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 indatamodels/(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.pybeachten).- Korrektur eines früheren Fehlers (weiterhin gültig): «
automation2wird von Chats nicht importiert» war falsch und ist noch nicht behoben.methods/methodFile/actions/create.py(→coerceDocumentDataToBytes) +methods/methodContext/actions/setContext.py(→PauseForHumanTaskError) importierenautomation2.executorstop-level — geladen viamethodDiscoveryim Chat-/Agent-Pfad. Diese zwei Helfer vor dem Engine-Umzug extrahieren (→ datamodels/serviceExceptions.pybzw.shared/documentUtils.py), sonst importiert Shared aufwärts in die Komponente.Guard-Test: sicherstellen, dass
modules.workflows.{methods,processing}+modules.serviceCenterimportierbar sind, ohnemodules.workflowAutomation.*zu laden. Migration nur der Automation-Teile (Re-Export/Shims; ~20 Importer vonworkflows.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 (MusterAutomationsDashboardPage). - Abgrenzung zur kundenseitigen «Lösungen»-Surface: Der
SolutionsTabhier ist die Admin/Power-User-Sicht über alle Solutions; die kundenseitigeSolutionsView(L4) bleibt pro Host-Feature eingebettet (Trustee usw.) und zeigt nur die für diesen Kontext konfigurierten Solutions. Beide nutzenapi/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 globalemevent-Sysadmin (A0.1).- Delaminierung zuerst (Phase 0.5):
PauseForHumanTaskError→datamodels/serviceExceptions.py,coerceDocumentDataToBytes→shared/documentUtils.py(Re-Export-Shim inautomation2/executors/). Contracts (portTypes, Models) sind bereits indatamodels(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 nachmodules/workflowAutomation/editor/führen;mainGraphicalEditor.py:getFeatureDefinition/TEMPLATE_ROLES/onStartentfernen bzw. zu System-Registrierung umbauen (instantiable=False, VorbildmainSystem.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._validateTargetInstancezusätzlich um Mandatsgrenze ergänzen (AC8, heute nurFeatureAccess).modules/routes/routeSystem.py— GE-Hardcode in_getFeatureUiObjectsentfernen; neuen statischen Nav-BlockworkflowAutomationausliefern.modules/datamodels/datamodelNavigation.py—NAVIGATION_SECTIONS(post-Refactoring hier, nicht mehr inmainSystem.py): Blockid="workflowAutomation"(order ~25) ergänzen;ui.system.workflowAutomation.*-Objekte; Store-Eintragresource.store.graphicalEditorentfernen.modules/features/graphicalEditor/mainGraphicalEditor.pyonInstanceCreate()— heute Template-Copy bei FeatureInstance-Erstellung (stempelt{{featureInstanceId}}/targetFeatureInstanceId, auch Trustee/Redmine). Ohne GE-Instanz entfällt der Hook-Trigger → Template-Instanziierung explizit in denlauncher/-Flow verlagern (inkl. Demo-Bootstrap); Trustee/Redmine-Platzhalter-Vertrag beachten.modules/features/graphicalEditor/mainGraphicalEditor.pyonMandateDelete()(Cascade) /onBootstrap()(Seeding) — sind bereits Feature-Hooks (exinterfaceDbApp/interfaceBootstrap); ziehen mit der Komponente um, Cascade auf mandatsweit umstellen.modules/interfaces/interfaceRbac.py—TABLE_NAMESPACE(8 Einträge:AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask+ LegacyAutomation2*): Option B — Namespacefeature.graphicalEditorbeibehalten + System-DATA-Objekte ergänzen. (Ein Flip aufsystem.workflowAutomationverwaist bestehendeAccessRule/Rollen-Zeilen; nur mit zwingend gekoppeltem Migrations-Skript im selben Deploy.)modules/interfaces/interfaceBootstrap.py— Store-Grant + ggf. neue System-RollenworkflowAutomation-*(Hook-Aufruf bleibt; GE-Wissen ist dynamisch vialoadFeatureMainModules).modules/features/graphicalEditor/mainGraphicalEditor.pygetGraphicalEditorServices—featureCode/featureInstanceIdim Hub (jetztserviceCenter/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;workflowToolsist der verbleibendeserviceCenter → features.graphicalEditor(5×, deferred) → entfällt mit Umzug.- Weitere GE-Importer (Deferred-Liste):
system/i18nBootSync.py(ziehtSTATIC_NODE_TYPES— mit Node-Katalog mitziehen),routeSystem.py(UI_OBJECTS+ Dashboard-_ensureTableExists),routeAdminFeatures.py,interfaceDbManagement.py:936(lazyworkflowArtifactVisibility),interfaceFeatureGraphicalEditor.getAllWorkflowsForScheduling(Lesepfad von Scheduler und Dashboard — stabil halten/shimmen); Re-Export-ShimsdatamodelFeatureGraphicalEditor.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 (analogadmin).src/App.tsx—/workflow-automation/*-Routen (Hub +?tab=Deeplinks); Redirects der alten/mandates/.../graphicalEditor/.../*.src/pages/AutomationsDashboardPage.tsx→ inWorkflowAutomationHubPagemit Tabs überführen (Workflows, Läufe, Editor, Vorlagen, Tasks).src/pages/FeatureView.tsx—graphicalEditorausVIEW_COMPONENTSentfernen.src/pages/views/graphicalEditor/*— vonuseInstanceId()/useCurrentInstance()auf expliziten Mandanten-/Instanz-Picker (Scope-Selector) umstellen.src/config/keepAliveRoutes.tsx— Editor-Keep-Alive-Pfad auf/workflow-automation/editorumziehen.src/config/pageRegistry.tsx— Icons fürpage.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= additivesADD COLUMN;featureInstanceIdist bereits DB-nullable (kein DDL, keine DB-FK; nur PydanticOptional+ 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 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 |
| 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):
- A2:
modules/workflows/automation2/*.py→modules/workflowAutomation/engine/(executionEngine, graphUtils, runEnvelope, scheduleCron, graphicalEditorRunFileLogger, pickNotPushMigration, featureInstanceRefMigration, workflowArtifactVisibility, clickupTaskUpdateMerge, udmUpstreamShapes) (2026-06-07) - A2:
modules/workflows/automation2/executors/*.py→modules/workflowAutomation/engine/executors/(actionNodeExecutor, inputExecutor, flowExecutor, triggerExecutor, ioExecutor, dataExecutor) (2026-06-07) - A3:
modules/workflows/scheduler/mainScheduler.py→modules/workflowAutomation/scheduler/mainScheduler.py(2026-06-07) - A5:
modules/features/graphicalEditor/{portTypes,adapterValidator,nodeRegistry,nodeAdapter,switchOutput,entryPoints,conditionOperators,upstreamPathsService,_workflowFileSchema}.py→modules/workflowAutomation/editor/(2026-06-07) - A5:
modules/features/graphicalEditor/nodeDefinitions/*.py→modules/workflowAutomation/editor/nodeDefinitions/(2026-06-07) - A5:
modules/features/graphicalEditor/emailPoller.py→modules/workflowAutomation/scheduler/emailPoller.py(2026-06-07) - Re-export shims created at old
__init__.pylocations for backward compatibility
Phase F — Delete old originals (cleanup):
- 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) - F2: Deleted all individual .py files from
modules/workflows/automation2/andexecutors/(executionEngine, graphUtils, runEnvelope, scheduleCron, graphicalEditorRunFileLogger, pickNotPushMigration, featureInstanceRefMigration, workflowArtifactVisibility, clickupTaskUpdateMerge, udmUpstreamShapes + 6 executor files) (2026-06-07) - F3: Deleted
modules/workflows/scheduler/mainScheduler.py(2026-06-07) - F4:
nodeDefinitions/__init__.pyconverted to re-export shim (imports STATIC_NODE_TYPES from new location) - F4:
routeWorkflowAutomation.pyimports updated tomodules.workflowAutomation.editor._workflowFileSchema automation2/__init__.py,automation2/executors/__init__.py,scheduler/__init__.pyretained as re-export shims → backward compat for remaining importersdatamodelFeatureGraphicalEditor.pygelöscht (keine Caller mehr) (2026-06-08)- Test file imports (
tests/unit/,tests/integration/,tests/demo/) updated to canonicalmodules.workflowAutomation.*paths (2026-06-08)
Phase D — Frontend Struktur (D1-D3):
- D1:
WorkflowAutomationPage.tsxmonolith (1566 lines) split intopages/workflowAutomation/with Hub + 5 tab components + types.ts (2026-06-08) - D2: Editor views re-exported from
pages/workflowAutomation/views/(2026-06-08) - D3: FlowEditor components re-export shim at
components/workflowAutomation/FlowEditor/(2026-06-08)
Phase A10 — RBAC Namespace Migration (Boot-integriert):
_migrateRbacNamespace()as idempotent routine inonBootstrap()— migrates AccessRule objectKeys fromfeature.graphicalEditortosystem.workflowAutomationon every boot (2026-06-08)TABLE_NAMESPACEininterfaceRbac.pyupdated fromfeature.graphicalEditortosystem.workflowAutomation(2026-06-08)- Standalone script
scripts/script_db_migrate_rbac_workflow_automation.pyretained as manual fallback (2026-06-07)
Cleanup — Stale DEPRECATED-Bereinigung:
- Stale DEPRECATED-Kommentare entfernt:
i18nBootSync.py(2x),workflowTools.py(5x) — Imports zeigen bereits aufmodules.workflowAutomation.*(2026-06-08) resource.store.graphicalEditor→resource.store.workflowAutomationininterfaceBootstrap.py+mainSystem.py(2026-06-08)toolboxRegistry.py:featureCode="graphicalEditor"→"workflowAutomation"(2026-06-08)datamodelFeatureGraphicalEditor.pygelöscht (toter Re-Export-Shim, keine Caller) (2026-06-08)nodeDefinitions/__init__.py: DEPRECATED-Label durch neutrales Shim-Label ersetzt (2026-06-08)routeWorkflowAutomation.py: fehlenderDatabaseConnector-Import ergänzt (Boot-Fix) (2026-06-08)routeWorkflowAutomation.py: staler Importmodules.workflows.automation2.runEnvelope→modules.workflowAutomation.engine.runEnvelope(2026-06-08)graphicalEditorRunFileLogger.py→runFileLogger.pyumbenannt + alle 4 Import-Stellen aktualisiert (2026-06-08)graphicalEditorDatabaseAlias ininterfaceWorkflowAutomation.pyentfernt (kein Caller) (2026-06-08)- Alle verbliebenen
graphicalEditor-Kommentare/Docstrings in 7 Backend-Dateien neutralisiert (2026-06-08) - Demo-Configs:
graphicalEditoraus Feature-Listen entfernt (pwgDemo2026.py,investorDemo2026.py) (2026-06-08) - Frontend:
console.error('[graphicalEditor]→'[workflowAutomation](6 Stellen), Kommentare aktualisiert (2026-06-08) _FEATURES_WITH_EDITOR:'graphicalEditor'entfernt (WA ist kein Feature; nur'workspace'verbleibt) (2026-06-08)- Test-Dateien:
graphicalEditoraus Parametrize-Listen und Assertions entfernt (2026-06-08) - UDB-Surface
'graphEditor'→'workflowAutomation'(UnifiedDataBar.tsx, FilesTab.tsx, Automation2FlowEditor.tsx) (2026-06-08) Automation2FlowEditor.tsx: 12 staleinstanceId-Parameter aus API-Calls entfernt (API war bereits migriert) (2026-06-08)FilesTab.tsx:importWorkflowFromFileSignatur korrigiert (staleinstanceIdentfernt) (2026-06-08)- Log-Prefixe
[automations]→[workflowAutomation]in RunsTab.tsx + WorkflowsTab.tsx (2026-06-08) - Dead code entfernt:
WorkflowTasksPage.tsx(942 LOC),WorkflowTasks.module.css(2026-06-08) - UDB generifiziert:
UdbSurface→string(kein hardcoded Feature-Enum mehr); Workflow-Import-Logik ausFilesTab.tsxentfernt → Consumer (Automation2FlowEditor) uebernimmt viaonFileSelect;onWorkflowImportedFromFileProp entfernt (2026-06-08)
Phase 0 — Scheduler-Boot entkoppeln (risikoarm, zuerst):
- Scheduler-Start in System-Lifespan (
app.py, nachsetSchedulerMainLoop/eventManager.start()); Poller bleibt on-demand (ensureRunning),onStop-Stop verlagert (Scheduler + Email-Poller inapp.pyShutdown Schritt 3.5); GE-onStart/onStopentfernt (2026-06-07) - 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):
— erledigt durch Refactoring (portTypes/PORT_TYPE_CATALOGdelaminierendatamodels/datamodelPortTypes.py, L1)Kanonische Models nach L1— erledigt (datamodels/datamodelWorkflowAutomation.py)PauseForHumanTaskError+PauseForEmailWaitError→datamodels/serviceExceptions.py(kanonisch); Re-Export-Shim inautomation2/executors/inputExecutor.py; Callermethods/methodContext/actions/setContext.pyumgebogen (2026-06-07)coerceDocumentDataToBytes+_looksLikeAsciiBase64Payload→shared/documentUtils.py(kanonisch); Re-Export-Shim inautomation2/executors/actionNodeExecutor.py; Callermethods/methodFile/actions/create.pyumgebogen (2026-06-07)- Guard-Test:
modules.workflows.{methods.methodContext.actions.setContext, methods.methodFile.actions.create}importierbar ohnemodules.workflows.automation2.*→ bestätigt, keinautomation2-Modul transitiv geladen (2026-06-07) - Node-Katalog (
STATIC_NODE_TYPES,features/graphicalEditor/nodeDefinitions/): moved toworkflowAutomation/editor/nodeDefinitions/; old__init__.pyconverted to re-export shim; cross-Callersystem/i18nBootSync.py+serviceAgent/workflowTools.pywork via shim (2026-06-07)
Phase 1 — Mandatsweite API + System-RBAC (parallel zur Bestands-API):
AutoWorkflow.runAsPrincipalindatamodels/datamodelWorkflowAutomation.pyergänzt (Optional[str], nullable, softFk → UserInDB)- System-RBAC + Nav-Block:
workflowAutomationSection (order 25) mit 5 UI-Objekten (ui.system.workflowAutomation.{workflows,editor,templates,runs,tasks}) indatamodelNavigation.py; automatisch von_buildUiObjectsFromNavigationin RBAC-Katalog aufgenommen - 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 inapp.py - Scheduler von
featureInstanceIdentkoppelt:if not instanceId-Guard inmainScheduler._syncScheduledWorkflowsentfernt;instanceIddefault""statt skip; Bestand läuft weiter - Runtime-Mandatsvalidierung beim
FeatureInstanceRef-Auflösen:_validateFeatureInstanceMandates()inexecutionEngine.pynachmaterializeFeatureInstanceRefs()— defence-in-depth warning-log bei cross-mandate-Referenzen (A0.2)
Phase 2 — UI «Workflow-Automation»-Gruppe:
- Nav-Block
workflowAutomationindatamodels/datamodelNavigation.py(NAVIGATION_SECTIONS) — bereits in Phase 1 erledigt /workflow-automation-Route +WorkflowAutomationPage.tsxHub-Seite mit Tabs (Workflows · Läufe · Tasks),?tab=-Deeplinks; Import inApp.tsx- Icons in
pageRegistry.tsxfürpage.system.workflowAutomation.*registriert (FaSitemap, FaProjectDiagram, FaCopy, FaPlay, FaTasks) MandateNavigation.tsx:extraStaticBlocks-Logik — unbekannte statische Blöcke werden als eigene Nav-Sektionen gerendert (nicht mehr in System-Block gemergt)- Kontext-Selector (Alle Mandanten / Mandant X) im Hub — BillingDataView-Pattern;
selectedMandateIdan alle Tabs (2026-06-08) - Editor-Entkopplung:
mandateIdist primaerer Kontext;instanceIdnur noch Access-Gate fuer Workspace-Datasource-APIs (2026-06-08) - WorkflowsTab/RunsTab: Server-seitige Mandantenfilterung via
mandateId-Query-Param (2026-06-08) - TasksTab im Hub verdrahtet (neue API
/api/workflow-automation/tasks) (2026-06-08) - WorkflowsTab Edit-Navigation korrigiert:
/workflow-automation?tab=editor&workflowId=...(statt mandate-scoped Feature-Route) (2026-06-08) _FEATURES_WITH_EDITOR:'workflowAutomation'entfernt (ist kein Feature) (2026-06-08)- 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:
AutoWorkflow.featureInstanceId→Optional[str](default=None, softFk=True); Pydantic-only, kein DDL — Spalte bereits DB-nullable- Cascade-Delete:
_cascadeDeleteAutoWorkflowinrouteWorkflowDashboard.pyist bereits mandatsweit (löscht nach workflowId, unabhängig von featureInstanceId)
Phase 4 — Feature-Mantel deprecaten (nicht entfernen — Koexistenz):
- GE-Hardcode in
routeSystem.pyals DEPRECATED markiert (bleibt für bestehende Feature-Instanzen) - Import-Umstellung:
routeWorkflowDashboard.py,routeAutomationWorkspace.py,routeSystem.pyimportieren Models aus kanonischerdatamodels.datamodelWorkflowAutomationstatt ausfeatures.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:
_CHANGELOG.mdaktualisiert
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
- 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-RolleworkflowAutomation-user, oder genügt Mandats-user? (Feature-Instanz-Rollen sind keine Option mehr —instantiable=False+rbac-role-separation.mdc.) - API-Pfad:
Entschieden (2026-06-08):/api/workflow-automation/…neu vs. bestehendes/api/system/workflow-runsausbauen — konsolidieren?/api/workflow-automation/…ist der kanonische Pfad.routeWorkflowAutomation.pyregistriert alle Endpunkte dort./api/system/workflow-runsbleibt als Legacy-Alias (Dashboard). - Run-as-Principal-Verwaltung: Ersteller-Identität vs. dedizierter Service-Principal (siehe CustomerCases offene Frage #1).
- Alt-URLs: wie lange Redirects der
{instanceId}-Pfade halten (Bookmarks/Deeplinks)? - Datei-/Doku-Rename: dieses Plan-Dokument ggf. auf
…-workflowautomation-system-component.mdumbenennen (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
b-reference/platform/workflowAutomation.md: Kanon-Seite aktualisiert (Code-Pfade, API, RBAC, Navigation) (2026-06-08).cursor/rules/rbac-role-separation.mdc+feature-instance-scoping.mdc: WorkflowAutomation als dokumentierte Ausnahme eingetragen (2026-06-08)topics-todo.mdaktualisiert (WorkflowAutomation = System-Komponente, DONE) (2026-06-08)features/graphicalEditor/Verzeichnis komplett gelöscht (keine Dateien, keine Caller) (2026-06-08)- Cross-Import Assessment:
workflows -> features.graphicalEditor(~40 Imports): eliminiert — alle Imports aufmodules.workflowAutomation.*(2026-06-08)serviceCenter -> features.graphicalEditor(5x workflowTools): eliminiert — kanonische Pfade (2026-06-08)interfaces/interfaceDbManagement.py:936->workflowArtifactVisibility: erledigt —modules.workflowAutomation.engine.workflowArtifactVisibility(2026-06-08)- Re-Export-Shims:
datamodelFeatureGraphicalEditor.pygelöscht;stateTools.pyShim bleibt (7 Caller viaprocessing/shared/, nicht Teil dieser Migration) (2026-06-08) - Keine
from modules.features.graphicalEditoroderfrom modules.workflows.automation2Imports 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