wiki/c-work/4-done/2026-04-trustee-workflow-audit-and-run-workspace.md
2026-06-02 09:42:12 +02:00

19 KiB

Trustee Workflow-Audit (A1) & Generischer Workflow-Run-Workspace (A2)

Beschreibung und Kontext

Der User klickt im Trustee-Dashboard Service-Karten an (Budget-Vergleich, KPI-Dashboard, Cashflow, Forecast, Jahresabschluss-Pruefung) und landet auf Tabs in TrusteeAnalyseView / TrusteeAbschlussView, wo der jeweilige Workflow gestartet wird.

Zwei Themen:

  • A1 Audit: Sind diese Workflows wirklich auf dem aktuellen Pick-not-Push / Typed-Action-Stack? -- JA, alle GREEN (siehe Befund unten). Hier wird nur dokumentiert.
  • A2 Result-Sichtbarkeit: Wenn der User waehrend des Runs die Seite wechselt, ist das Resultat (KI-Antwort + generierte Files) anschliessend weg -- es lebt nur im React-State der Source-View. Persistenz existiert zwar in AutoRun/AutoStepLog, ist aber nirgends als User-UI erschlossen.

Geschaeftstreiber: UX-Bruch ("ich war kurz auf einer anderen Seite, jetzt ist mein Report weg") + fehlende Single-Source-of-Truth fuer Workflow- Outputs. Plus: Workflow muss eine klare Ziel-Feature-Instanz haben, damit Datenquellen, RBAC und Workspace-Filterung sauber funktionieren.

Architekturentscheidung: GraphicalEditor bleibt Feature

Der GraphicalEditor (GE) ist konzeptuell eine Plattform-Capability (nicht ein Domain-Feature wie Trustee). Er bleibt aber aus pragmatischen Gruenden als Feature registriert (isolierte DB, Feature-Roles, Template-Kopier- Mechanismus). Die URL-Struktur /api/workflows/{geInstanceId}/... nutzt die GE-Instanz als RBAC-Scope/Eigentuemer.

Neues Konzept: targetFeatureInstanceId -- das Feld am Workflow, das bestimmt welche Daten (Dateien, Connections, Domain-Objekte) zur Verfuegung stehen. Dies ist NICHT die GE-Instanz (Eigentuemer), sondern die Ziel-Feature-Instanz (Daten-Scope bei Execution).

Kein Multi-Instance: Ein Workflow = Ein Ziel-Scope

  • ALLE Nodes eines Workflows operieren auf derselben targetFeatureInstanceId.
  • Kein per-Node Override -- Engine resolved {{featureInstanceId}} zentral aus dem Workflow-Level-Feld.
  • Wenn Daten aus einer anderen Instanz benoetigt werden: diese Daten im Ziel-Scope bereitstellen (z.B. via Data-Connection, File-Import), NICHT einen Multi-Instance-Workflow bauen.
  • RBAC bei Execution: ein Check auf targetFeatureInstanceId reicht.

targetFeatureInstanceId kann auch die GE-Instanz selbst sein

Fuer generische Workflows ohne Domain-Daten (z.B. "AI verarbeitet Eingabetext und generiert Report") waehlt der User die GE-Instanz selbst ("Automation allgemein") als Ziel. Dann stehen nur Files/Connections zur Verfuegung, die direkt an der GE-Instanz haengen.

Fokus und kritische Details

  • POST /api/workflows/{instanceId}/execute ist heute synchron (await executeGraph(...), kein BackgroundTask). Der Workspace muss den Request nicht aendern -- er macht nur die persistierten AutoRun-Daten auffindbar.
  • AutoWorkflow.featureInstanceId = GE-Instanz (Eigentuemer). NICHT anfassen. Neues Feld targetFeatureInstanceId daneben. Hinweis: Pydantic-Model hat featureInstanceId: str (required, nicht Optional), aber DB-Spalte ist nullable=YES. System-Templates setzen featureInstanceId="" oder ueberspringen die Validation.
  • System-Templates (isTemplate=True) haben targetFeatureInstanceId=NULL (Template hat kein konkretes Ziel, erst die Kopie).
  • Scheduler bindet targetFeatureInstanceId vom persistierten Workflow -- kein Override moeglich.
  • Tab-Position: User wuenscht Workspace explizit unter /automations (Seite "Nutzung > Automation") als zusaetzlichen Tab neben Dashboard + Workflows.
  • AutoRun hat heute KEIN featureInstanceId-Feld -- Instanz-Zuordnung laeuft indirekt ueber AutoRun.workflowId -> AutoWorkflow.targetFeatureInstanceId.

Ziel und Nicht-Ziele

  • Ziel A1: Audit-Befund GREEN dokumentiert (Wiki-Update).
  • Ziel A2: Generische Workflow-Run-Workspace-View; jeder Workflow (non- template) hat Pflicht-targetFeatureInstanceId; TrusteeAnalyseView verweist statt Inline-Result auf den Workspace.
  • NICHT: Async-Umstellung des Execute-Endpoints.
  • NICHT: Browser-Push-Notification.
  • NICHT: De-Featuring des GraphicalEditors (bewusster pragmatischer Kompromiss, siehe Architekturentscheidung).
  • NICHT: Multi-Instance-Workflows.

Betroffene Module

  • Gateway:
    • platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py (neues Feld AutoWorkflow.targetFeatureInstanceId).
    • platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py (Save-Validation: non-template braucht targetFeatureInstanceId).
    • platform-core/modules/features/graphicalEditor/interfaceFeatureGraphicalEditor.py (createWorkflow/updateWorkflow: Feld durchreichen).
    • platform-core/modules/workflows/automation2/executionEngine.py (executeGraph: {{featureInstanceId}} aus targetFeatureInstanceId resolven).
    • platform-core/modules/workflows/scheduler/mainScheduler.py (Schedule-Fire nutzt targetFeatureInstanceId vom Workflow).
    • platform-core/modules/features/trustee/mainTrustee.py (Templates pruefen: targetFeatureInstanceId wird bei _copyTemplateWorkflows gesetzt).
    • platform-core/modules/interfaces/interfaceFeatures.py (_copyTemplateWorkflows: targetFeatureInstanceId auf Ziel-Instanz setzen bei Kopie).
    • Neue Route-Datei: platform-core/modules/routes/routeAutomationWorkspace.py (User-facing /api/automations/runs/... Endpoints).
  • Frontend:
    • Neuer Tab in ui-nyla/src/pages/AutomationsDashboardPage.tsx.
    • Neue Komponenten WorkflowRunWorkspaceView, WorkflowRunDetailView.
    • FlowEditor CanvasHeader: Pflicht-Dropdown "Ziel-Instanz" (targetFeatureInstanceId).
    • TrusteeAnalyseView.tsx: Inline-Result-Anzeige raus, Link zum Workspace-Detail.
    • TrusteeAbschlussView.tsx: analog -- Link zum Workspace-Detail.
  • DB-Migration: AutoWorkflow bekommt neue Spalte targetFeatureInstanceId (nullable, wegen Templates). Bestand: Dev-Audit zeigt 0 non-template Workflows ohne Instance (alle 24 regulaeren Workflows haben bereits featureInstanceId aus dem URL- Context). Migration: fuer Bestand targetFeatureInstanceId := featureInstanceId setzen (selbe Instanz wie GE = Default fuer alte generische Workflows ODER aus Graph-Nodes extrahieren wenn dort konkreter Wert steht).
  • RBAC: Neue Endpoints pruefen targetFeatureInstanceId gegen User- Berechtigungen via FeatureAccess.

Befund A1 (Audit) -- bereits GREEN

Service Workflow-ID Backend-Definition Status
Budget-Vergleich trustee-budget-comparison mainTrustee.py ~430-461 GREEN
KPI-Dashboard trustee-kpi-dashboard mainTrustee.py ~463-478 GREEN
Cashflow-Rechnung trustee-cashflow mainTrustee.py ~480-492 GREEN
Prognose trustee-forecast mainTrustee.py ~494-507 GREEN
Jahresabschluss-Pruefung trustee-year-end-check mainTrustee.py ~509-522 GREEN

Engine-Pipeline: executeGraph (in workflows/automation2/executionEngine.py Z. ~305-350) ruft materializeFeatureInstanceRefs (typed-ref envelopes, NICHT Placeholder-Substitution) + materializeConnectionRefs + validateGraph vor jedem Lauf auf.

ACHTUNG: {{featureInstanceId}}-Placeholder werden heute NUR in _copyTemplateWorkflows pre-baked (graphJson.replace(...), Z. ~336-338 in interfaceFeatures.py). executeGraph selbst hat KEINE Placeholder-Substitution -- diese muss NEU gebaut werden (Phase 1).

Zusaetzlich zu den 5 Analyse-Workflows existieren noch 2 weitere Trustee-Templates (trustee-receipt-import, trustee-sync-accounting) in TEMPLATE_WORKFLOWS. Diese verwenden ebenfalls {{featureInstanceId}}-Placeholders und sind GREEN.

Entscheidungen

Datum Entscheidung Begruendung
2026-04-29 GE bleibt Feature, neues Feld targetFeatureInstanceId De-Featuring zu teuer; targetFeatureInstanceId loest das eigentliche Problem sauber
2026-04-29 Kein Multi-Instance: 1 Workflow = 1 Ziel-Scope Einfach, klar, RBAC auf Workflow-Ebene pruefbar; bei Bedarf Daten im Ziel-Scope bereitstellen
2026-04-29 targetFeatureInstanceId kann auch die GE-Instanz selbst sein Generische Workflows ohne Domain-Daten brauchen einen Scope
2026-04-29 Workspace ist GENERISCH plattformweit, nicht Trustee-spezifisch Doppelt-Bauen vermeiden; alle Features profitieren
2026-04-29 Workspace lebt unter /automations als Tab "Workspace" User-Vorgabe; Nutzungspfad "Nutzung > Automation > Workspace"
2026-04-29 Neuer Endpoint /api/automations/runs/... statt Erweiterung von System-Dashboard Klare Trennung User-Workspace (RBAC-gefiltert) vs. Admin-Dashboard
2026-04-29 Bestand-Migration: targetFeatureInstanceId := featureInstanceId (GE-Instanz) Dev-Audit: 0 non-template ohne Instance; 24 regulaere haben GE-Instance aus URL
2026-04-29 TrusteeAnalyseView: Inline-Result raus, Workspace-Link rein Single Source of Truth im Workspace; kein verlorener State bei Seitenwechsel
2026-04-29 Kein interaktives Migrations-Skript noetig Dev-Audit: 0 echte Workflows betroffen (nur 2 System-Templates, die NULL behalten duerfen)

Umsetzungs-Checkliste

Phase 1 -- targetFeatureInstanceId + Validation

  • datamodelFeatureGraphicalEditor.py: targetFeatureInstanceId: Optional[str] = Field(default=None, ...) (nullable wegen Templates).
  • interfaceFeatureGraphicalEditor.py createWorkflow: aus Body oder Fallback self.featureInstanceId uebernehmen.
  • interfaceFeatureGraphicalEditor.py updateWorkflow: Feld im Update-Payload erlauben (NICHT strippen wie featureInstanceId).
  • routeFeatureGraphicalEditor.py Save-Endpoint: wenn isTemplate=False und targetFeatureInstanceId fehlt/leer -> 400.
  • routeFeatureGraphicalEditor.py Execute-Endpoint: Vorab-Check targetFeatureInstanceId vorhanden, User hat FeatureAccess darauf.
  • executionEngine.py executeGraph: NEU BAUEN -- VOR materializeFeatureInstanceRefs eine Placeholder-Substitution einfuegen: alle {{featureInstanceId}}-Vorkommen im serialisierten Graph-JSON durch targetFeatureInstanceId (uebergeben als neuer Parameter) ersetzen. Bestehende hart-kodierte UUIDs in Nodes bleiben unangetastet (Backward-Compat fuer kopierte Templates, wo _copyTemplateWorkflows bereits pre-baked hat). Hinweis: materializeFeatureInstanceRefs macht typed-ref-envelope- Rewriting, NICHT Placeholder-Substitution -- beides ist noetig.
  • mainScheduler.py: Schedule-Fire liest heute workflow["featureInstanceId"] (= GE-Instanz) und uebergibt es als instanceId an executeGraph. Aendern: zusaetzlich workflow["targetFeatureInstanceId"] lesen und als neuen Parameter targetFeatureInstanceId an executeGraph uebergeben (fuer die Placeholder-Substitution). instanceId (GE-Instanz) bleibt fuer RBAC-Scope bestehen.
  • interfaceFeatures.py _copyTemplateWorkflows: bei Kopie targetFeatureInstanceId = instanceId (die Ziel-Feature-Instanz) EXPLIZIT im createWorkflow-Payload setzen. Hinweis: heute wird featureInstanceId NICHT im Payload gesetzt, sondern kommt implizit aus dem GE-Interface-Context (getGraphicalEditorInterface(..., instanceId)). targetFeatureInstanceId muss explizit uebergeben werden. In-Graph-Placeholders werden wie bisher auch pre-baked (graphJson.replace("{{featureInstanceId}}", instanceId)).
  • Bestand-Migration (einmalig, idempotent): UPDATE "AutoWorkflow" SET "targetFeatureInstanceId" = "featureInstanceId" WHERE "targetFeatureInstanceId" IS NULL AND "isTemplate" IS NOT TRUE (kann als Boot-Telemetrie oder im Audit-Skript laufen).
  • Unit-Test: Workflow-Save ohne targetFeatureInstanceId -> 400.
  • Unit-Test: Execute mit targetFeatureInstanceId das User nicht zugreifen darf -> 403.

Phase 2 -- FlowEditor Toolbar Dropdown

  • CanvasHeader: neues Dropdown "Ziel-Instanz" (Pflicht fuer non- template). Optionen: alle FeatureInstances des Mandats (inkl. GE- Instanz als "Automation allgemein"), gefiltert nach User-FeatureAccess.
  • Bei Wechsel: Workflow-Update mit neuem targetFeatureInstanceId, Datenquellen-Browser (SourcesTab, UDB-Listen) refreshen auf neuen Scope.
  • Wenn targetFeatureInstanceId leer (z.B. frisch aus Template): User MUSS erst Instanz waehlen bevor Save/Run moeglich.

Phase 3 -- Generischer WorkflowRunWorkspace

  • Neue Route-Datei platform-core/modules/routes/routeAutomationWorkspace.py: - GET /api/automations/runs (Query-Params: scope=mine|mandate, status, targetInstanceId, workflowId, limit, offset). RBAC: nur Runs sichtbar wo User FeatureAccess auf targetFeatureInstanceId hat. - GET /api/automations/runs/{runId}/detail -- kombiniert AutoRun + AutoStepLog + verlinkte FileItems.
  • Tab "Workspace" in AutomationsDashboardPage.tsx (neben Dashboard, Workflows).
  • Komponente WorkflowRunWorkspaceView: Liste mit Filtern (Status, Workflow-Name, Ziel-Instanz, Zeitraum), Pagination.
  • Komponente WorkflowRunDetailView: Chat-aehnliche Ansicht - Header: Workflow-Name, Status, Start/Ende, Ziel-Instanz. - Eingabe-Bubble: Trigger-Payload (formatiert). - Step-Bubbles: chronologisch, pro Step-Output kollabierbar. - Final-Bubble: KI-Antwort als Markdown. - Documents-Sektion: alle generierten FileItems als Karten mit Direkt-Download.

Phase 4 -- Trustee-Views Refactor + Notifications

  • TrusteeAnalyseView: resultText / resultDocuments State (Z. ~124-125) und die zugehoerige Output-Extraktion (Z. ~202-253) raus. Nach Run-Ende: Navigation/Link zum Workspace-Detail (runId).
  • TrusteeAbschlussView: hat KEIN resultText/resultDocuments -- zeigt nur Status/runSummary/runError. Aenderung: nach Run-Ende zusaetzlich Link zum Workspace-Detail einfuegen (fuer die Detail-Ansicht der Step-Outputs).
  • Toast bei Run-Ende: erweitern um Klick-Action zum Detail-View.
  • Sidebar-Badge auf "Automation" (Counter "neu seit letztem Besuch", localStorage-basiert).

Akzeptanzkriterien

# Kriterium (Given-When-Then) Prio
1 Given non-template Workflow ohne targetFeatureInstanceId, When Save, Then 400 must
2 Given Workflow mit targetFeatureInstanceId, When User keinen FeatureAccess auf diese Instanz hat, When Execute, Then 403 must
3 Given Trustee-Run gestartet, When User Seite wechselt und zu Tab "Workspace" geht, Then Run mit allen Outputs sichtbar must
4 Given Run mit generiertem File, When User auf Document-Karte klickt, Then File wird direkt heruntergeladen must
5 Given FlowEditor offen, When User "Ziel-Instanz" waehlt, Then Datenquellen-Browser zeigt nur Daten dieser Instanz must
6 Given Run-Ende-Toast, When User klickt, Then Navigation direkt zum WorkflowRunDetailView should
7 Given neue Runs seit letztem Besuch, When User Sidebar sieht, Then "Automation" hat Counter-Badge should
8 Given Template-Workflow kopiert, When Kopie in Mandate entsteht, Then targetFeatureInstanceId automatisch auf Ziel-Instanz gesetzt must

Testplan

ID AC Art Automatisiert Repo-Pfad Status
T1 1 api ja platform-core/tests/features/graphicalEditor/test_workflow_save_target_instance.py pending
T2 2 api ja platform-core/tests/features/graphicalEditor/test_workflow_execute_rbac.py pending
T3 3,4 e2e ja ui-nyla/tests/e2e/workflow-run-workspace.spec.ts pending
T4 5 unit ja ui-nyla/src/components/flowEditor/tests/TargetInstanceDropdown.test.tsx pending
T5 8 api ja platform-core/tests/features/test_copy_template_workflows.py pending

Dev-DB-Befund (2026-04-29)

  • DB: poweron_graphicaleditor, Tabelle AutoWorkflow
  • Spalte featureInstanceId: text, nullable=YES (kein NOT NULL)
  • Total: 26 Workflows (24 regulaer, 2 System-Templates)
  • 0 regulaere Workflows ohne featureInstanceId -> KEINE Daten-Migration noetig
  • 2 System-Templates (isTemplate=True, templateScope='system'): featureInstanceId=NULL, mandateId=NULL -> korrekt, bleiben NULL
  • 2 orphan AutoRun-Rows (workflowId='transient-XXX') -> Test-Reste, zu loeschen
  • Bestand-Migration: targetFeatureInstanceId := featureInstanceId fuer alle non-template Rows (= GE-Instanz als initialer Default, da diese Workflows generisch sind bzw. Graph-intern bereits konkrete Instance- UUIDs haben)

Risiken und Mitigationen

Risiko Impact Mitigation
executeGraph Placeholder-Substitution aendert Graph-Semantik fuer bestehende Workflows hoch Pre-baked Templates haben bereits konkrete UUIDs -- Substitution greift nur bei {{featureInstanceId}}-Literals, die in kopierten Workflows nicht mehr vorkommen. Unit-Test mit beiden Faellen (pre-baked + Placeholder).
Bestand-Migration setzt targetFeatureInstanceId := featureInstanceId (GE-Instanz), aber manche kopierten Trustee-Workflows haben die echte Trustee-Instanz nur in den Graph-Nodes (pre-baked) mittel Fuer Bestand ist das OK: die pre-baked Nodes funktionieren weiterhin, da executeGraph existierende UUIDs nicht ueberschreibt. Nur neue Runs benoetigen korrekte targetFeatureInstanceId. User kann im FlowEditor nachtraeglich aendern.
Neue RBAC-Pruefung (targetFeatureInstanceId) koennte bestehende Execute-Calls brechen wenn User keinen expliziten FeatureAccess auf Ziel-Instanz hat mittel Audit-Query vor Release: alle non-template Workflows pruefen ob ownerId FeatureAccess auf targetFeatureInstanceId hat. Ggf. Soft-Rollout mit Warning statt 403 fuer 1 Sprint.
Pydantic featureInstanceId: str (required) vs DB nullable -- Templates koennten Save-Fehler erzeugen niedrig System-Templates werden im Code erzeugt, nicht via API. Pydantic-Validation wird bei API-Save erzwungen, bei internem createWorkflow umgangen. Bestehendes Verhalten.
  • Audit-Quelle: Subagent-Report + DB-Query 2026-04-29.
  • Code-Cross-Check: Subagent 2026-04-29 (16 Annahmen verifiziert).
  • Wiki: wiki/b-reference/platform-core/workflow.md, wiki/b-reference/platform-core/features/trustee.md.

Abschluss

  • wiki/b-reference/platform-core/workflow.md Abschnitt "targetFeatureInstanceId + Workspace" anlegen
  • wiki/b-reference/platform-core/features/trustee.md Result-UX-Sektion aktualisieren
  • wiki/TOPICS.md ggf. Tab-Beschreibung
  • Dieses Dokument -> 4-done/ verschoben