wiki/c-work/1-plan/2026-04-pwg-pilot-mietzinsbestaetigung-workflow.md

28 KiB
Raw Blame History

PWG-Pilot: Jahresmietzinsbestätigungs-Workflow + Workflow-File-IO

Beschreibung und Kontext

Quelle: Konsolidierter Kundenwünsche-Plan, Abschnitt 1.9c — PWG-Workshop 16.04.2026.

Business Case: PWG verschickt 4 × 800 = 3'200 Jahresmietzinsbestätigungen pro Jahr. Rückantworten (Scans) werden aktuell manuell verarbeitet. Pilot-Ziel: AI-gestützte Verarbeitung mit Antwortvorschlägen, Versand Sommer 2026.

Dieser Plan deckt drei zusammenhängende Themen ab:

  1. Workflow-File-IO — Workflows als File exportieren (in UDB speichern) und aus UDB-File in den Graph-Editor laden. Voraussetzung, damit der Pilot-Workflow als versionierbares Asset im Repo geliefert werden kann.
  2. Agent-Tools Full-CRUD — Der AI-Agent erhält im workflow-Toolbox die vollständigen Operationen createWorkflow, createWorkflowFromFile, exportWorkflowToFile, deleteWorkflow (zusätzlich zu den bestehenden Lese-/Edit-Tools).
  3. Pilot-Workflow als File — Konkrete Lieferung: Workflow-JSON nach Schema, Step-5 AI-Prompt, Datenextraktion aus Trustee-DB.

Risiko bei Nicht-Umsetzung: PWG-Pilot kann nicht termingerecht (Sommer 2026) aufgesetzt werden. Workflows bleiben nicht portabel zwischen Mandanten/Instanzen, was Demo-Vorbereitungen und Customer-Onboarding deutlich verlangsamt.

Abhängigkeiten:

  • Abacus-Testmandant (extern, Patrick koordiniert) — nicht Blocker für Workflow-Bau, nur für End-to-End-Test.
  • Bestehende Komponenten (alle ): Trigger, SharePoint-Nodes, flow.loop, trustee.extractFromFiles, ai.prompt, email.send.

Fokus und kritische Details

  • Trustee-DB hat kein Mieter-/Mietzins-Modell (siehe Codebase-Audit). Stattdessen: Matching-Logik liegt im AI-Prompt von Step 5. Daten werden via Sub-Agent (queryFeatureInstance / aggregateTable auf TrusteeDataContact + TrusteeDataJournalLine) oder via dediziertem Daten-Extract-Node bereitgestellt. Kein neues DB-Schema nötig.
  • Graph-Format-Inkonsistenz: Bootstrap-Templates verwenden Node-Felder x / y (top-level), Agent-Tool addNode schreibt position: {x, y}. Beim Import muss normalisiert werden.
  • Workflow-Envelope-Felder: AutoWorkflow hat zahlreiche optionale Felder (tags, invocations, templateScope, sharedReadOnly, notifyOnFailure). Beim Export müssen Mandanten-spezifische Felder (mandateId, featureInstanceId, id, currentVersionId, eventId) rausgefiltert werden, sonst sind Files nicht portabel.
  • Schema-Versionierung: Wir starten mit $schemaVersion: "1.0". Loader prüft Version und lehnt unbekannte ab oder migriert.
  • UDB-Erkennung: Workflow-Files identifizieren wir per Dateiendung .workflow.json (case-insensitive) und Content-Sniffing (Top-Level-Keys $schemaVersion + graph + nodes).
  • Sicherheit beim Import: Geladene Workflows werden NICHT automatisch ausgeführt. Nutzer muss aktiv via "Speichern + Aktivieren" die invocations aktivieren. active wird beim Import auf false gesetzt.
  • Node-Type-Validierung: Beim Import gegen STATIC_NODE_TYPES validieren. Unbekannte Node-Typen → Fehler mit klarer Meldung (welcher Typ fehlt).

Ziel und Nicht-Ziele

Ziel:

  • Workflows können als File (JSON) aus dem Graph-Editor exportiert und in UDB gespeichert werden.
  • Workflow-Files in UDB können im Graph-Editor wieder geladen werden (neuer Workflow oder Update bestehender).
  • AI-Agent kann Workflows lesen, erstellen, aus File importieren, exportieren und löschen.
  • Der PWG-Pilot-Workflow pwg-mietzinsbestaetigung-pilot.workflow.json liegt im Repo, kann von einer leeren PWG-Demo-Instanz geladen und (mit Test-Daten) ausgeführt werden.
  • Step-5-Prompt liefert pro Scan: Status (bestaetigt / abweichung / unleserlich / keine_unterschrift) und einen Antwortvorschlag bei Abweichung.

Explizit NICHT:

  • Kein neues DB-Schema für Mietzins/Mieter (Matching erfolgt im Prompt gegen bestehende Trustee-Daten).
  • Keine Persistenz der Pilot-Run-Ergebnisse in einer Trustee-Sub-Tabelle (CSV im Mail reicht für Pilot).
  • Keine Auto-Aktivierung importierter Workflows (sicherheitsrelevant).
  • Keine Migration-Logik für $schemaVersion > 1.0 (kommt später).
  • Kein Versions-Branching/Diff von Workflow-Files (späteres Thema).
  • Keine SharePoint-OCR-Verbesserungen (extractFromFiles wird wie bestehend genutzt).

Betroffene Module

  • Gateway:
    • features/graphicalEditor/routeFeatureGraphicalEditor.py — neue Routen POST .../workflows/import und GET .../workflows/{id}/export.
    • features/graphicalEditor/interfaceFeatureGraphicalEditor.py — neue Methoden importWorkflowFromDict, exportWorkflowToDict.
    • features/graphicalEditor/_workflowFileSchema.py (NEU) — Schema-Definition + Validierung + Normalisierung (x/yposition).
    • serviceCenter/services/serviceAgent/workflowTools.py — neue Tools createWorkflow, createWorkflowFromFile, exportWorkflowToFile, deleteWorkflow.
    • serviceCenter/services/serviceAgent/toolboxRegistry.py — Tool-Liste in workflow-Toolbox erweitern.
  • Frontend:
    • components/UnifiedDataBar/FilesTab.tsx — Workflow-File-Erkennung + Action "In Graph-Editor laden".
    • pages/views/workflow/ (Graph-Editor-View) — Buttons "Aus Datei importieren" + "Als Datei exportieren" (Editor-Toolbar).
    • api/workflowApi.ts (oder analog) — neue Endpoint-Wrapper.
  • DB-Migration: nein.
  • Repo-Asset: gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json (NEU).
  • Andere: Step-5-Prompt-Template als Konstante in gateway/modules/features/trustee/promptTemplates/_pwgMietzinsCheck.py oder direkt im Workflow-File (Decision unten).

Entscheidungen

Datum Entscheidung Begründung
2026-04-16 Workflow-File-Format = Envelope + Schema-Version (1.0) Portabel, zukunftssicher, ein Round-Trip ohne Verlust von Metadaten
2026-04-16 Matching-Logik im AI-Prompt von Step 5 (nicht neue DB-Tabelle) Trustee-DB hat kein Mietzins-Modell; Pilot kommt mit AI + bestehende Sub-Agent-Queries aus
2026-04-16 Result-Output = CSV als E-Mail-Anhang (kein DB-Schema) Schlankster Pilot-Pfad; Persistenz später bei Bedarf nachrüstbar
2026-04-16 Agent-Tools = Full-CRUD inkl. deleteWorkflow Agent soll Workflows komplett verwalten können (User-Wunsch)
2026-04-16 File-Endung .workflow.json + Content-Sniffing Klare UDB-Identifikation ohne neuen MIME-Type
2026-04-16 Import setzt active: false; Aktivierung manuell Sicherheits-Default — kein versehentliches Auto-Run nach Import
2026-04-16 Step-5-Prompt im Workflow-File (Parameter von ai.prompt-Node) Das File ist self-contained und im Repo lesbar; keine Code-Änderung beim Tunen
2026-04-16 CSV-Sammlung über bestehende data.aggregate (collect) + data.consolidate (csvJoin) Idiomatisch, bereits implementiert; kein neuer Node nötig
2026-04-16 Neuer Node trustee.queryData ist Pflicht Kein bestehender Node liest Trustee-DB; ai.prompt hat keinen Sub-Agent-Tool-Zugriff (verifiziert in methodAi/actions/process.py) — context-Parameter muss vorher befüllt werden
2026-04-16 E-Mail mit Attachment via Erweiterung von email.draftEmail (neuer optionaler attachments-Parameter), kein neuer Node Minimal-invasiv; email.draftEmail ist bereits gemappt auf methodOutlook.composeAndDraftEmailWithContext und kann erweitert werden. Im Pilot wird ein Draft erstellt (kein Auto-Versand), das passt zur "Sicherheits-Default-keine-Auto-Aktion"-Linie

Architektur

Workflow-File Schema 1.0

{
  "$schemaVersion": "1.0",
  "$exportedAt": "2026-04-16T10:00:00Z",
  "$gatewayVersion": "0.x.y",
  "$kind": "poweron.workflow",
  "label": "PWG Pilot: Jahresmietzinsbestätigung",
  "description": "Verarbeitet gescannte Rückantworten der Mietzinsbestätigungen ...",
  "tags": ["pwg", "pilot", "mietzins"],
  "templateScope": "instance",
  "sharedReadOnly": false,
  "notifyOnFailure": true,
  "graph": {
    "nodes": [
      { "id": "n1", "type": "trigger.manual", "x": 50, "y": 200, "title": "Manueller Start", "parameters": {} }
    ],
    "connections": [
      { "source": "n1", "target": "n2", "sourceOutput": 0, "targetInput": 0 }
    ]
  },
  "invocations": [
    { "type": "schedule", "cronExpression": "0 22 * * *" }
  ]
}

Felder, die NIE im File stehen: id, mandateId, featureInstanceId, currentVersionId, eventId, createdAt, updatedAt, active (wird beim Import auf false gesetzt).

Normalisierung beim Import: Falls Node position: {x, y} enthält → in x/y top-level umwandeln (oder umgekehrt — wir entscheiden uns für x/y top-level als kanonische Form, weil Bootstrap-Templates so aussehen).

API-Endpunkte (neu)

Methode Pfad Zweck
POST /api/workflows/{instanceId}/workflows/import Body: { "fileId": "...", "mode": "create" | "updateGraph", "targetWorkflowId"?: "..." } Lädt File aus UDB, validiert, erstellt neuen Workflow oder ersetzt graph eines bestehenden
GET /api/workflows/{instanceId}/workflows/{workflowId}/export Query: ?asFileId=true&folderId=... Exportiert Workflow als File. Wenn asFileId=true: speichert in UDB und gibt fileId zurück. Sonst: gibt JSON-Body direkt zurück (Browser-Download)

Frontend-Erweiterungen

UDB FilesTab (FilesTab.tsx):

  • Erkennt Workflow-Files (.workflow.json oder Top-Level $kind === "poweron.workflow").
  • Workflow-File-Eintrag erhält Icon (z. B. Workflow/Diagramm) und Context-Menu-Eintrag "In Graph-Editor laden".
  • Bei Klick → Modal: Ziel-Editor-Instanz wählen + Mode (create / updateGraph für aktiven Workflow) → POST /import.

Graph-Editor Toolbar (Editor-View):

  • Button "Importieren" → File-Picker (UDB-Files mit Filter .workflow.json) → POST /import.
  • Button "Exportieren" → Modal: Ziel = Download oder UDB-Folder → GET /export?asFileId=....

AI-Agent Tools (Full-CRUD im workflow-Toolbox)

Erweiterung von workflowTools.py und Toolbox-Registry:

Tool Bestehend? Beschreibung
readWorkflowGraph Graph eines Workflows lesen
addNode, removeNode, connectNodes, setNodeParameter Bestehende Edit-Tools
listAvailableNodeTypes, validateGraph Bestehende Helpers
listWorkflowHistory, readWorkflowMessages Bestehende Read-Tools
createWorkflow NEU Args: label, description?, tags?, graph, invocations?. Ergebnis: { workflowId }
createWorkflowFromFile NEU Args: fileId, mode (default create). Ergebnis: { workflowId, importedNodes, warnings }
exportWorkflowToFile NEU Args: workflowId, targetFolderId?. Ergebnis: { fileId, fileName }
deleteWorkflow NEU Args: workflowId, confirm: true. Sicherheits-Confirm-Flag

Implementierung: alle neuen Tools rufen die neuen Routen / Interface-Methoden auf, kein direkter DB-Zugriff aus den Tools.


Pilot-Workflow: Inhalt

Datei: gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json

Knoten-Übersicht (10 Nodes — basierend auf real verfügbaren Nodes nach Codebase-Audit):

ID Type Title Wichtige Parameter
n1 trigger.manual Manueller Start (alternativ trigger.schedule mit Cron 0 22 * * *)
n2 sharepoint.listFiles Scan-Ordner auflisten connectionReference, sharepointFolder: "PWG/Mietzinsbestaetigungen/Scans-{year}-{quarter}", filter: { extensions: ["pdf", "tif", "jpg"] }
n3 flow.loop Pro Dokument inputArrayPath, itemAlias: "scanFile"
n4 sharepoint.downloadFile Datei laden fileReference: "{{loop.item}}"
n5 trustee.extractFromFiles OCR & Extraktion featureInstanceId, prompt: <ExtractionPrompt für Mietzinsbestätigung — siehe unten>
n6 trustee.queryData ⚠️ NEU Referenzdaten holen featureInstanceId, mode: "lookup", entity: "tenantWithRent", tenantNameRef: "{{n5.output.tenantName}}", tenantAddressRef: "{{n5.output.tenantAddress}}", period: "{{currentYear}}"
n7 ai.prompt Prüfung & Klassifikation aiPrompt: <Step-5-Prompt-Template>, outputFormat: "json", documentList: <Wire von n5>, context: <Wire von n6>
n8 data.aggregate Ergebnisse sammeln (im Loop) mode: "collect" — sammelt n7.output über Loop-Iterationen
n9 data.consolidate CSV bauen (nach Loop) mode: "csvJoin", separator: "\n" — wandelt gesammelte JSON-Items in CSV
n10 email.draftEmail Draft mit Anhang connectionReference, to: "sachbearbeiter@pwg.ch", subject: "Mietzinsbestätigungen Auswertung {{date}}", body: <Zusammenfassung>, attachments: [{ name: "ergebnisse.csv", contentRef: "{{n9.output}}" }] ⚠️ attachments-Param muss in email.draftEmail ergänzt werden

Nicht-existierende Nodes/Params, die als Sub-Aufgabe gebaut werden müssen (siehe Phase 4):

  1. trustee.queryData — neuer Node in nodeDefinitions/trustee.py + Action in methodTrustee/actions/queryData.py. Wrappt FeatureDataProvider.queryTable / aggregateTable. Mode lookup mit Entity tenantWithRent macht intern: Match in TrusteeDataContact (Debitor) → Aggregat über TrusteeDataJournalLine für Mietzins-Konten in der Periode.
  2. email.draftEmail.attachments — optionaler Parameter attachments in nodeDefinitions/email.py ergänzen + im Executor composeAndDraftEmailWithContext Attachment-Handling implementieren.

Datenfluss-Anmerkungen:

  • Der context-Parameter von ai.prompt muss VOR dem Node befüllt werden (verifiziert: methodAi/actions/process.py macht direkten AiCallRequest ohne Sub-Agent-Tools). Daher liegt n6 zwingend vor n7 im Wire-Pfad.
  • data.aggregate (mode collect) sammelt im Loop-Body, data.consolidate (mode csvJoin) führt nach dem Loop zusammen — Standardmuster für CSV-Output aus Loop-Iterationen.
  • helpers/csvProcessing.py (in methodAi) kann von data.consolidate und/oder email.draftEmail-Attachment-Builder wiederverwendet werden.

Extraktionsschema für n5 (extractionSchema: "mietzinsbestaetigung")

Erwartete Felder im OCR-Output:

{
  "tenantName": "string",
  "tenantAddress": "string",
  "objectAddress": "string",
  "confirmedRentAmount": "number|null",
  "currency": "CHF",
  "period": "string (z.B. 2026)",
  "tenantNotes": "string|null",
  "hasSignature": "boolean",
  "documentDate": "string (ISO date)|null",
  "ocrConfidence": "number (0-1)"
}

Step-5-Prompt (Inhalt für n7.parameters.prompt)

Du bist ein Sachbearbeitungs-Assistent der Stiftung PWG. Deine Aufgabe ist es,
eine eingescannte und OCR-extrahierte Jahresmietzinsbestätigung gegen die
Stammdaten der Buchhaltung (Trustee-Feature) abzugleichen.

Eingaben:
1. SCAN_DATEN (extrahiert per OCR aus dem Rückantwort-Dokument):
   {{scan}}

2. REFERENZ_DATEN (aus Trustee-DB für diesen Mieter; ggf. leer wenn nicht
   eindeutig zuordenbar):
   {{reference}}

Vorgehen:
1. Prüfe Identität: Stimmt SCAN_DATEN.tenantName + SCAN_DATEN.tenantAddress mit
   einem Datensatz in REFERENZ_DATEN.contacts überein? (Toleranz: kleine
   Tippfehler, Umlaute, Abkürzungen)
2. Prüfe Mietzinsbetrag: Stimmt SCAN_DATEN.confirmedRentAmount mit dem aus
   REFERENZ_DATEN.journalLines abgeleiteten erwarteten Mietzins überein?
   (Toleranz: ±1 CHF Rundung)
3. Prüfe Unterschrift: hasSignature muss true sein.
4. Prüfe OCR-Qualität: ocrConfidence < 0.6 → "unleserlich".

Klassifiziere in EXAKT EINEN Status:
- "bestaetigt": Identität stimmt, Betrag stimmt, Unterschrift vorhanden.
- "abweichung_betrag": Identität ok, Unterschrift ok, Betrag weicht ab.
- "abweichung_anmerkung": tenantNotes enthält substantielle Anmerkung
   (nicht leer, nicht reine Bestätigung).
- "keine_unterschrift": hasSignature == false.
- "unleserlich": OCR-Qualität ungenügend ODER Pflichtfelder fehlen.
- "kein_match": Mieter nicht in REFERENZ_DATEN auffindbar.

Bei Status != "bestaetigt": Generiere einen kurzen, höflichen
Antwortvorschlag (deutsch, Sie-Form, max. 5 Sätze, PWG-Stil) für die
Sachbearbeitung. Bei "bestaetigt": antwortVorschlag = null.

Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
{
  "tenantName": string,
  "objectAddress": string,
  "status": "bestaetigt" | "abweichung_betrag" | "abweichung_anmerkung"
          | "keine_unterschrift" | "unleserlich" | "kein_match",
  "scanRentAmount": number | null,
  "expectedRentAmount": number | null,
  "delta": number | null,
  "tenantNotes": string | null,
  "antwortVorschlag": string | null,
  "matchConfidence": number,
  "auditEvidence": string
}

outputSchema im Node erzwingt JSON-Form (existierende ai.prompt-Capability nutzen).


Umsetzungs-Checkliste

Phase 1 — Workflow-File-IO Backend

  • Schema-Modul _workflowFileSchema.py mit WORKFLOW_FILE_SCHEMA_VERSION = "1.0", Funktionen _validateFileEnvelope(), _normalizeNodePositions(), _stripPersistenceFields(), _buildFileFromWorkflow().
  • Interface-Methoden in interfaceFeatureGraphicalEditor.py:
    • importWorkflowFromDict(envelope, mandateId, featureInstanceId, mode, targetWorkflowId?) -> workflowId
    • exportWorkflowToDict(workflowId) -> envelope
  • Routen in routeFeatureGraphicalEditor.py:
    • POST /{instanceId}/workflows/import (Body: fileId, mode, targetWorkflowId?).
    • GET /{instanceId}/workflows/{workflowId}/export (Query: asFileId, folderId?).
  • Validierungen:
    • Bekannte Schema-Version, Pflichtfelder, Node-Typen vorhanden in STATIC_NODE_TYPES.
    • Bei Import: active=false erzwingen.
  • Unit-Tests: Round-Trip (Export → Import → erneuter Export, Bytes identisch nach Normalisierung).

Phase 2 — UDB-Erkennung & Frontend-IO

  • FilesTab.tsx:
    • Workflow-File-Detection (Endung + Content-Sniffing über useFiles.isJsonContent).
    • Workflow-Icon, Context-Menu-Eintrag "In Graph-Editor laden" → öffnet Modal.
  • Modal "Workflow importieren": Editor-Instanz-Auswahl, Mode-Wahl (Neu / Bestehenden ersetzen), Submit → API.
  • Graph-Editor-Toolbar: Buttons "Importieren" (Files-Picker) und "Exportieren" (Download-vs-UDB-Modal).
  • api/workflowApi.ts (oder analog): importWorkflowFromFile(fileId, …), exportWorkflowToFile(workflowId, …).

Phase 3 — Agent-Tools Full-CRUD

  • In workflowTools.py neue Funktionen: _createWorkflow, _createWorkflowFromFile, _exportWorkflowToFile, _deleteWorkflow (alle mit _-Prefix gemäss Naming-Konvention).
  • Tool-Definitionen in getWorkflowToolDefinitions() ergänzen.
  • toolboxRegistry.py — Tool-Liste in workflow-Toolbox erweitern.
  • Sicherheits-Confirm: deleteWorkflow verlangt confirm: true.
  • Integration-Test: Agent erstellt Workflow → exportiert → löscht → re-importiert via fileId.

Phase 4 — Fehlende Nodes für Pilot ergänzen (konkretisiert nach Codebase-Audit)

Audit-Ergebnis (siehe auch Tabelle in Abschnitt "Findings" weiter oben):

  • data.aggregate (mode collect) und data.consolidate (mode csvJoin) existieren bereits → CSV-Sammlung ist abgedeckt, kein neuer Daten-Node nötig.
  • Kein Node liest Trustee-DB-Daten → trustee.queryData muss neu gebaut werden.
  • email.draftEmail hat keinen attachments-Parameter → muss erweitert werden.
  • ai.prompt mit outputFormat: "json" und context-Parameter ist passgenau für Step 5.

Sub-Task 4a — Neuer Node trustee.queryData:

  • Definition in gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py ergänzen (Pattern wie trustee.refreshAccountingData).
    • Parameter: featureInstanceId (hidden), mode (select: lookup, aggregate, raw), entity (select: tenantWithRent, contact, journalLines, accounts), tenantNameRef/tenantAddressRef/period (text, optional je nach mode), extraFilter (json, optional).
    • Inputs: 1, Outputs: 1, outputPorts: { 0: { schema: "QueryResult" } }.
    • _method: "trustee", _action: "queryData".
  • Action-Implementierung gateway/modules/workflows/methods/methodTrustee/actions/queryData.py:
    • Mode lookup mit Entity tenantWithRent → fuzzy match in TrusteeDataContact (Debitor-Filter), dann Aggregat in TrusteeDataJournalLine über die für Mietzins relevanten Konten in der Periode.
    • Mode raw → direkter FeatureDataProvider.queryTable mit entity als Tabellenname.
    • Mode aggregateFeatureDataProvider.aggregateTable mit extraFilter.
    • Output-Format: { matched: bool, contacts: [...], journalLines: [...], expectedRentAmount: number|null, matchConfidence: number } — direkt verwendbar als context in ai.prompt.
  • Registrierung in methodTrustee/__init__.py und methodTrustee.py (analog zu existierenden Actions).
  • Unit-Test tests/methods/methodTrustee/test_queryData.py: Mock FeatureDataProvider, prüfe Match-Logik mit Tippfehler-Toleranz und Mietzins-Aggregation.

Sub-Task 4b — Attachment-Support in email.draftEmail:

  • In nodeDefinitions/email.py neuen optionalen Parameter ergänzen:
    {"name": "attachments", "type": "json", "required": False, "frontendType": "attachmentBuilder",
     "description": t("Anhänge (Liste von { name, contentRef | csvFromVariable | base64Content })"),
     "default": []},
    
  • In gateway/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py (oder dem aktuellen Pfad) Attachment-Handling implementieren:
    • contentRef → resolved aus Wire/Variable, als Bytes/String.
    • csvFromVariable → resolved aus Variable (z. B. Output von data.consolidate) und als CSV-Anhang gehängt.
    • base64Content → direkt dekodieren.
    • Hochladen als Outlook-Draft-Attachment via Graph-API (/me/messages/{id}/attachments).
  • Frontend: Attachment-Builder im Property-Panel des Editors (kann minimal sein — JSON-Editor reicht für Pilot).
  • Unit-Test mit gemocktem Outlook-Connector: prüfe dass Attachment korrekt im erstellten Draft enthalten ist.

Sub-Task 4c — Frontend-Anpassungen für neue Nodes:

  • trustee.queryData automatisch in der Node-Palette sichtbar (kommt durch Definition gratis).
  • Property-Panel: Bei mode: "lookup" und entity: "tenantWithRent" die Tenant-Felder anzeigen, sonst ausblenden (dependsOn-Mechanismus wie in sharepointFolder).
  • Falls beide Wege zu aufwändig: Pilot-Workflow auf 7 Nodes vereinfachen — Step 5 macht ALLES (Sub-Agent-Query + Klassifikation + Antwort) in einem ai.prompt-Node mit featureSubAgent-Tool-Zugriff.

Phase 5 — Pilot-Workflow als File

  • Datei gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json erstellen (Inhalt wie oben spezifiziert).
  • Datei via Test in eine PWG-Demo-Instanz importieren (manueller Smoke-Test).
  • Test-Lauf mit 23 fiktiven Scan-PDFs (in gateway/demoData/pwg/scans/ ablegen — Sub-Aufgabe).
  • CSV-Ergebnis prüfen: enthält pro Scan eine Zeile mit allen Feldern aus dem Output-Schema.

Querschnitt

  • API-Endpunkte: ja, 2 neue (Import + Export).
  • DB-Schema / Migration: nein.
  • Frontend-Komponenten: FilesTab-Erweiterung, Graph-Editor-Toolbar-Buttons, Import-Modal.
  • RBAC / Permissions: Import/Export benötigen gleiche Rechte wie update_workflow. deleteWorkflow-Tool nur wenn User-Rolle delete_workflow darf.
  • Neutralisierung betroffen? Indirekt ja: Workflow-Files können sensible Parameter (Connection-Refs, E-Mail-Adressen) enthalten. Doku-Hinweis beim Export-Modal: "Vor Weitergabe Datei prüfen". Keine automatische Neutralisierung im Pilot-Scope.
  • Navigation / Routing: keine Änderung.
  • Billing-Impact: Pilot-Workflow verbraucht Tokens (1 AI-Call pro Scan, ggf. Sub-Agent-Calls). Kalkulation für PWG-Pilot: ~3'200 Schreiben/Jahr × ~3 Calls × ~2k Tokens als Grössenordnung — gehört in PWG-Preismodell-Action-Item AI3.

Akzeptanzkriterien

# Kriterium (Given-When-Then) Prio
1 Given Workflow im Graph-Editor, When User auf "Exportieren → UDB" klickt, Then liegt eine <label>.workflow.json im gewählten UDB-Folder mit Schema-Version 1.0 must
2 Given Workflow-File in UDB, When User in FilesTab "In Graph-Editor laden" wählt + Mode create bestätigt, Then existiert ein neuer Workflow mit identischem Graph und active=false must
3 Given Workflow-File mit unbekanntem Node-Typ, When Import, Then Fehler-Response listet konkret den fehlenden Typ; kein Workflow wird erstellt must
4 Given Workflow A in Editor, When exportWorkflowToFilecreateWorkflowFromFile, Then ist der neu erstellte Workflow nach Normalisierung byte-äquivalent (Round-Trip-Stabilität) should
5 Given AI-Agent mit aktivem workflow-Toolbox, When Agent ruft createWorkflow mit gültigem Graph, Then wird Workflow erstellt und workflowId zurückgegeben must
6 Given AI-Agent, When Agent ruft deleteWorkflow ohne confirm: true, Then Tool antwortet mit Fehler "confirm flag missing" und löscht nichts must
7 Given PWG-Pilot-Workflow geladen + 1 Test-Scan-PDF in SharePoint-Ordner, When manueller Trigger, Then enthält die E-Mail-CSV exakt 1 Zeile mit gefülltem status-Feld must
8 Given Test-Scan ohne Unterschrift, When Workflow läuft, Then status == "keine_unterschrift" und antwortVorschlag ist gefüllt should
9 Given Test-Scan mit korrekten Daten, When Workflow läuft + Trustee-DB enthält passenden Debitor + Journal-Line, Then status == "bestaetigt" und delta == 0 should
10 Given importierter Workflow, When User versucht ihn ohne weitere Aktion zu schedulen, Then schlägt es fehl bzw. active ist false und User muss explizit aktivieren must

Testplan

ID AC Art Automatisiert Repo-Pfad Status
T1 1, 4 unit ja gateway/tests/unit/graphicalEditor/test_workflow_file_io.py pending
T2 2, 3, 10 api ja gateway/tests/integration/graphicalEditor/test_workflow_import.py pending
T3 5, 6 unit ja gateway/tests/unit/serviceAgent/test_workflow_tools_crud.py pending
T4 7, 8, 9 e2e manuell PWG-Demo-Instanz mit 3 Test-Scans pending
T5 1, 2 manuell UI nein Frontend FilesTab + Graph-Editor in lokaler Dev-Umgebung pending
  • Quellplan (0-ideas): wiki/c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md (Abschnitt 1.9c)

  • PWG-Workshop-Inputs: pamocreate/projects/poweron/customer-pwg/20260415-inputs-pwg.txt

  • Graph-Editor Models: gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py

  • Graph-Editor Routes: gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py

  • System-Templates Bootstrap: gateway/modules/interfaces/interfaceBootstrap.py (_buildSystemTemplates)

  • Agent Workflow-Tools: gateway/modules/serviceCenter/services/serviceAgent/workflowTools.py

  • Toolbox-Registry: gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py

  • UDB Files-Tab: frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx

  • File-Upload-Route: gateway/modules/routes/routeDataFiles.py

  • Trustee-Modelle: gateway/modules/features/trustee/datamodelFeatureTrustee.py

  • Abacus-Connector: gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py

  • Feature-Sub-Agent: gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py

  • PR: ...

  • Issue: ...

Abschluss

  • b-reference/gateway/architecture.md ergänzen (Workflow-File-IO Sektion)
  • b-reference/frontend-nyla/architecture.md ergänzen (FilesTab Workflow-Handling)
  • TOPICS.md ergänzen (neues Thema "Workflow Portability")
  • PWG-Pilot-Workflow-Datei in gateway/demoData/workflows/ committed und im Demo-Config (pwgDemo2026.py) referenziert
  • Dieses Dokument → c-work/2-build/ verschieben sobald Phase 1 startet