wiki/c-work/1-plan/2026-04-customer-trustee-tooling-and-demo-prep.md
2026-04-11 19:45:08 +02:00

229 lines
17 KiB
Markdown

<!-- status: plan -->
<!-- started: 2026-04-07 -->
<!-- component: gateway -->
# Trustee Tooling Overhaul & PWG Demo Preparation
## Beschreibung und Kontext
Für den PWG-Inspirationsworkshop (16. April 2026) werden drei Use Cases in PORTA demonstriert. Use Case 1 (Belegverarbeitung + Budgetkontrolle) und Use Case 3 (Datenneutralisierung) erfordern Code-Anpassungen im Trustee-Feature und im Agent-Tooling.
**Business-Treiber:** PWG AG (gemeinnützige Wohnungsstiftung Zürich, 200+ Liegenschaften, Abacus als Hauptsystem) evaluiert PORTA. Der Workshop ist die erste Live-Demo — Plattform-Tiefgang und funktionierende Schnittstellen sind entscheidend.
**Risiko bei Nicht-Umsetzung:** Demo scheitert an fehlenden Tools (Agent kann keine Buchhaltungsdaten lesen), langsamer Performance (jede Query startet neuen Sub-Agent-Loop) oder fehlendem Workflow im Graphical Editor.
Parallel zur Demo-Vorbereitung wird das Trustee-Tooling grundlegend überarbeitet. Die aktuelle Architektur hat strukturelle Schwächen, die auch im Produktivbetrieb problematisch sind.
**Hinweis:** Die Automation Unification (v1/v2 → Graphical Editor) ist abgeschlossen (siehe `c-work/3-validate/2026-04-automation-unification.md`, Status: done). Dieses Dokument baut auf dem konsolidierten System auf: Feature `graphicalEditor`, DB `poweron_graphicaleditor`, konsolidierter Scheduler.
## Fokus und kritische Details
### Ist-Zustand Trustee-Tooling (Analyse)
| Fähigkeit | Status | Problem |
|-----------|--------|---------|
| **Daten lesen (Agent)** | `queryFeatureInstance` → Sub-Agent mit `browseTable`/`queryTable` | Jeder Call öffnet neue DB-Connection + startet 5-Runden-Agent-Loop mit AI-Calls. Kein Caching. Langsam (~5-15s pro Query). |
| **Daten aus Buchhaltung importieren** | `AccountingDataSync.importData()` via REST-Endpoint | Full-clear + Full-write bei jedem Import. Kein inkrementeller Sync. Kein Agent-Zugriff (nur REST). |
| **Daten schreiben (Agent)** | Nicht vorhanden | Agent kann keine Trustee-Positionen erstellen oder ändern. |
| **Daten aggregieren** | Nicht vorhanden | Sub-Agent hat nur row-level Tools. Keine SQL-Aggregationen (SUM, GROUP BY). Für Budgetvergleiche muss der Agent alle Rows laden und selbst rechnen. |
| **Chart of Accounts** | `AccountingBridge.getChartOfAccounts()` mit Cache auf `TrusteeAccountingConfig` | Funktioniert, aber nur für Bridge-interne Nutzung. Agent hat keinen direkten Zugriff. |
| **Graph-Editor Nodes (Trustee)** | 3 Nodes in `nodeDefinitions/trustee.py`: `extractFromFiles`, `processDocuments`, `syncToAccounting` | Alle `dynamicMode=False` — nicht als Agent-Tools verfügbar. Für Graph-Editor nutzbar. Kein Node für `refreshAccountingData` / Datenimport. |
| **Graph-Editor Nodes (SharePoint)** | 6 Nodes in `nodeDefinitions/sharepoint.py`: findFile, readFile, uploadFile, listFiles, downloadFile, copyFile | Vorhanden und funktional. `listFiles` + `downloadFile` reichen für den Demo-Flow. |
| **Graph-Editor Nodes (Flow)** | 5 Nodes: ifElse, switch, loop, merge, delay | Loop-Node vorhanden (`flow.loop`). Nötig für "für jede Datei aus SharePoint → Trustee-Pipeline". |
| **Node-Kategorie `trustee`** | Nodes nutzen `category: "trustee"` | **Fehlt in `nodeRegistry.getNodeTypesForApi()` Categories-Liste** (Zeile 63-73) — Trustee-Nodes werden im Editor nicht unter eigener Kategorie angezeigt. |
| **Toolbox `trustee`** | Nicht vorhanden | Die Toolbox Registry (`toolboxRegistry.py`) hat Toolboxes für email, sharepoint, clickup, jira, workflow — aber keine für Trustee. Für den Agent-Zugriff auf Trustee-Actions (`dynamicMode=True`) wäre eine Toolbox sinnvoll. |
### Performance-Problem `queryFeatureInstance`
Der Hauptgrund für die langsame Query-Performance:
1. **Neuer Sub-Agent pro Call**`runFeatureDataAgent` startet einen eigenen Agent-Loop (max 5 Runden, je ein AI-Call) für jede Frage. Das bedeutet: Main-Agent stellt Frage → Sub-Agent macht 1-3 AI-Calls um SQL zu generieren → Sub-Agent antwortet → Main-Agent verarbeitet.
2. **Neue DB-Connection pro Call**`DatabaseConnector` wird jedes Mal neu instanziiert und geschlossen.
3. **Kein Result-Cache** — Identische Fragen werden jedes Mal neu beantwortet.
## Ziel und Nicht-Ziele
**Ziel:**
- Agent kann Trustee-Buchhaltungsdaten lesen (gecacht oder frisch vom externen System)
- Agent kann Aggregationen auf Trustee-Daten ausführen (SUM, GROUP BY für Budgetvergleiche)
- Graphical-Editor-Workflow für Belegverarbeitung (SharePoint → Trustee Import+Sync) funktioniert
- Performance von Feature-Data-Queries deutlich verbessert
- Demo für PWG-Workshop läuft stabil end-to-end
**Explizit NICHT:**
- Kein vollständiger Umbau des Sub-Agent-Patterns
- Keine neuen Abacus-API-Endpoints (nutzen bestehenden Connector)
- Keine Frontend-Änderungen am Trustee-UI
## Betroffene Module
- Gateway: `features/trustee/`, `serviceCenter/services/serviceAgent/` (inkl. `toolboxRegistry.py`), `workflows/methods/methodTrustee/`, `features/graphicalEditor/nodeDefinitions/`, `features/graphicalEditor/nodeRegistry.py`
- Frontend: keine Änderungen
- DB-Migration: nein (nutzt bestehende `TrusteeData*`-Tabellen in Feature-DB `poweron_trustee`)
- Graphical Editor: Node-Definitionen + Kategorie-Registry + Workflow-Konfiguration für Demo
## Entscheidungen
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
| 2026-04-07 | Neues Tool `refreshTrusteeData` statt Erweiterung von `queryFeatureInstance` | Separation of Concerns: Sync ist eine schreibende Operation, Query ist lesend. Agent entscheidet selbst, ob er zuerst refreshen muss. |
| 2026-04-07 | `aggregateTable`-Tool im Sub-Agent statt SQL in `queryTable` | Saubere Trennung: row-level vs. aggregate. Verhindert SQL-Injection-Risiko bei freien GROUP BY-Ausdrücken. |
| 2026-04-07 | DB-Connection-Pooling für Feature-Data-Agent statt Connection-per-Call | Grösster Performance-Hebel. Connection-Aufbau ist teuer (~200ms), Pool eliminiert das. |
| 2026-04-07 | Result-Cache auf WorkflowMemory-Ebene | Nutzt bestehendes Konzept (WorkflowMemory mit Embedding). Agent kann gecachte Ergebnisse aus früheren Runden wiederverwenden. |
## Umsetzungs-Checkliste
### Phase 1: Trustee Agent-Tools (Prio: hoch — Blocker für Demo UC1 Teil B)
- [x] **`refreshTrusteeData`** — Neue Workflow-Action `trustee.refreshAccountingData` mit `dynamicMode=True`
- Prüft `TrusteeAccountingConfig.lastSyncAt` — wenn älter als Schwellwert (z.B. 1h) oder Daten leer → triggert `AccountingDataSync.importData()`
- Parameter: `featureInstanceId` (required), `forceRefresh` (optional, default false), `dateFrom`/`dateTo` (optional)
- Rückgabe: Summary (Anzahl Records pro Tabelle, Sync-Dauer, ob frisch oder gecacht)
- Registrierung in `MethodTrustee.__init__` analog zu bestehenden Actions
- [x] **`aggregateTable`** — Neues Tool im Feature-Data-Sub-Agent (`featureDataAgent.py`)
- SQL-Aggregationen: `SUM`, `COUNT`, `AVG`, `MIN`, `MAX`
- `GROUP BY` auf vordefinierte Felder (Whitelist pro Tabelle)
- Scope-Filter wie bei `queryTable` (featureInstanceId + mandateId)
- Beispiel: `aggregateTable(tableName="TrusteeDataJournalLine", aggregate="SUM", field="debitAmount", groupBy="costCenter")`
### Phase 2: Graphical-Editor Node-Definitionen (Prio: hoch — Blocker für Demo UC1 Teil A)
**Ist-Zustand Node-Registry (`features/graphicalEditor/nodeDefinitions/`):**
| Datei | Nodes | Status |
|-------|-------|--------|
| `trustee.py` | `extractFromFiles`, `processDocuments`, `syncToAccounting` | Vorhanden, aber kein Node für Datenimport/Refresh |
| `sharepoint.py` | `findFile`, `readFile`, `uploadFile`, `listFiles`, `downloadFile`, `copyFile` | Vorhanden, ausreichend für Demo |
| `flow.py` | `ifElse`, `switch`, `loop`, `merge`, `delay` | Vorhanden, Loop-Node nötig für Demo |
**Anpassungen:**
- [x] **Kategorie `trustee` in `nodeRegistry.py` ergänzen**
- In `getNodeTypesForApi()``categories`-Liste (Zeile 63-73) fehlt `{"id": "trustee", "label": {"en": "Trustee", "de": "Treuhand", "fr": "Fiduciaire"}}`
- Ohne diese Kategorie werden die Trustee-Nodes in der Node-Palette des Graphical Editors nicht unter einer eigenen Gruppe angezeigt
- [x] **Neuer Node `trustee.refreshAccountingData`** in `nodeDefinitions/trustee.py`
- Mapped auf neue Workflow-Action `trustee.refreshAccountingData` (Phase 1)
- Parameter: `featureInstanceId` (required), `forceRefresh` (optional), `dateFrom`/`dateTo` (optional)
- Kategorie: `trustee`, Icon: `mdi-database-refresh`, Color: `#4CAF50`
- Damit kann der Datenimport auch als Flow-Node genutzt werden (z.B. "Jeden Morgen Daten aus Abacus importieren")
- [~] **Neuer Node `trustee.importAndProcess`** in `nodeDefinitions/trustee.py` (optional, Convenience) — **übersprungen**: bestehende 3 Nodes funktionieren dank Output-Chaining-Fix (s.u.)
- Kombiniert die Pipeline `extractFromFiles``processDocuments``syncToAccounting` in einem einzigen Node
- Vereinfacht den Demo-Flow auf 2 Nodes statt 4 (SharePoint Download → Trustee Import+Process+Sync)
- Parameter: `connectionId`, `sharepointFolder`, `featureInstanceId`, `prompt`
- Falls zu aufwändig: bestehende 3 Nodes einzeln im Flow verketten (funktioniert, ist aber visuell weniger eindrucksvoll)
- [x] **Toolbox `trustee` in `toolboxRegistry.py` registrieren** (für Agent-Zugriff)
- Analog zu `sharepoint`, `email`, `clickup` — Toolbox mit `requiresConnection: false` (Trustee hat eigene Config)
- Enthält `refreshTrusteeData` (Phase 1) und ggf. weitere Trustee-Actions wenn `dynamicMode=True`
- Ermöglicht dem Agent, Trustee-Tools via `requestToolbox("trustee")` zu aktivieren
- [x] **Bestehende Trustee-Nodes prüfen und angepasst**
- `trustee.extractFromFiles`: `_paramMap` korrekt (`connectionId` → `connectionReference`), Output = `ActionDocument`-Liste → wird via `model_dump()` serialisiert
- `trustee.processDocuments`: **Fix implementiert** — neue `_resolveDocumentList()` Funktion erkennt sowohl Graph-Editor-Output (Liste von Dicts mit `documentData`) als auch Chat-Referenzen (Fallback). Kein Chat-Service im Graph-Editor nötig.
- `trustee.syncToAccounting`: **Fix implementiert** — neue `_resolveFirstDocument()` Funktion mit gleicher Dual-Path-Logik
- [x] **Output-Chaining verifiziert und gefixt:**
- `actionNodeExecutor.py` Zeile 828: `ActionDocument``model_dump()` → Dict mit `documentName`, `documentData`, `mimeType`
- `actionNodeExecutor.py` Zeile 836-837: Output enthält `documents` + `documentList` (identisch)
- `_getDocumentsFromUpstream()` (Zeile 237) liest `documents` oder `documentList` aus dem Output-Dict
- Zeile 569: `resolvedParams.setdefault("documentList", docs)` mergt die Dicts in den nächsten Node
- **Problem war:** `processDocuments` und `syncToAccounting` nutzten `DocumentReferenceList.from_string_list()` + `chat.getChatDocumentsFromDocumentList()` — funktioniert nur im Chat-Kontext, nicht im Graph-Editor
- **Lösung:** Beide Actions erkennen jetzt direkt übergebene Dicts (Graph-Editor-Pfad) und nutzen Chat nur als Fallback — **manuell testen**
### Phase 3: Performance (Prio: hoch — spürbar in jeder Demo)
- [x] **DB-Connection-Pooling** für Feature-Data-Agent
- Singleton `DatabaseConnector` pro Feature-DB (z.B. `poweron_trustee`) statt Connection-per-Call
- Pool in `_featureSubAgentTools.py` oder zentral im ServiceCenter
- Connection-Reuse über `featureDbConnPool[featureDbName]`
- [x] **Sub-Agent Result-Caching**
- Cache-Key: `(featureInstanceId, question_hash, lastSyncAt)`
- Invalidierung bei neuem Sync (`lastSyncAt` ändert sich)
- TTL: 5 Minuten (konfigurierbar)
- Speicherort: In-Memory Dict im Agent-Kontext (pro Workflow-Session)
### Phase 4: Graphical-Editor Workflow für Demo (Prio: hoch — nötig für UC1 Teil A)
- [ ] **Workflow im Graphical Editor bauen:** SharePoint Read Files Loop → Trustee Import+Sync
- Trigger: `trigger.manual` (mit Hinweis "könnte automatisch laufen")
- Node 1: `sharepoint.listFiles` → Ordner mit Belegen
- Node 2: `flow.loop` über die Dateiliste
- Node 3 (im Loop): `sharepoint.downloadFile` → PDF herunterladen
- Node 4 (im Loop): `trustee.extractFromFiles` → Belege extrahieren
- Node 5 (im Loop): `trustee.processDocuments` → Buchungen erstellen
- Node 6 (nach Loop): `trustee.syncToAccounting` → Sync mit Abacus
- Alternativ: `trustee.importAndProcess` Convenience-Node (Phase 2) statt Nodes 4-6
- Testen mit 3-4 Musterbelegen
- Workflow als System-Template speichern (`templateScope: system`)
- [ ] **Musterbelege erstellen:** Handwerkerrechnung, Nebenkostenabrechnung, Bankbeleg, Versicherungsbeleg (PDFs)
### Phase 5: Demo-Daten & Testläufe (Prio: mittel)
- [ ] Budget-Excel erstellen (Soll-Werte 2026 pro Kostenstelle/Liegenschaft)
- [ ] Demo-Prompt für Budgetkontrolle vorbereiten und testen
- [ ] CommCoach-Personas für Immobilien-Kontext erstellen
- [ ] Neutralisierungs-Demo mit fiktivem Mieterdossier testen
- [ ] Demo-Mandant "PWG Demo" sauber aufsetzen
- [ ] Alle 3 Use Cases end-to-end durchspielen
## Akzeptanzkriterien
| # | Kriterium (Given-When-Then) | Prio |
|---|---------------------------|------|
| 1 | Given Trustee-Instanz mit Abacus-Config, When Agent `refreshTrusteeData` aufruft, Then werden Daten aus Abacus in `TrusteeData*`-Tabellen importiert und Summary zurückgegeben | must |
| 2 | Given gecachte Daten (lastSyncAt < 1h), When Agent `refreshTrusteeData` ohne `forceRefresh` aufruft, Then wird kein externer Sync ausgelöst und gecachte Counts zurückgegeben | must |
| 3 | Given Trustee-Daten in DB, When Sub-Agent `aggregateTable` mit SUM/GROUP BY aufruft, Then kommen korrekte Aggregationen zurück (verifiziert gegen manuelle Berechnung) | must |
| 4 | Given identische Query innerhalb 5 Min, When `queryFeatureInstance` erneut aufgerufen wird, Then wird gecachtes Ergebnis zurückgegeben (kein neuer Sub-Agent-Loop) | should |
| 5 | Given Graphical Editor geöffnet, When Node-Palette geladen wird, Then erscheint Kategorie "Treuhand" mit allen Trustee-Nodes (inkl. neuem `refreshAccountingData`) | must |
| 6 | Given Workflow im Graphical Editor mit trigger.manual sharepoint.listFiles flow.loop trustee.extractFromFiles processDocuments syncToAccounting, When Workflow manuell gestartet wird, Then werden PDFs aus SharePoint geladen, extrahiert und als Positionen mit Sync-Status im Trustee angezeigt | must |
| 7 | Given Trustee-Pipeline im Flow (extract process sync), When Node A Output an Node B weitergereicht wird, Then wird `documentList`-Referenz korrekt aufgelöst (Output-Chaining funktioniert) | must |
| 8 | Given Budget-Excel im Workspace + Trustee-Daten, When Budgetkontrolle-Prompt ausgeführt wird, Then erstellt Agent Soll/Ist-Vergleich mit Charts und sendet per Mail | must |
## Testplan
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | nein (manuell mit Abacus-Sandbox) | | pending |
| T2 | 2 | api | ja | gateway/tests/features/trustee/test_refresh_tool.py | pending |
| T3 | 3 | api | ja | gateway/tests/features/trustee/test_aggregate_table.py | pending |
| T4 | 4 | api | ja | gateway/tests/serviceAgent/test_feature_data_cache.py | pending |
| T5 | 5 | ui | nein (manuell) | | pending |
| T6 | 6 | e2e | nein (manuell) | | pending |
| T7 | 7 | api | ja | gateway/tests/workflows/graphicalEditor/test_node_chaining.py | pending |
| T8 | 8 | e2e | nein (manuell) | | pending |
## Links
- Use Cases: `pamocreate/projects/poweron/customer-pwg/20260407 use-cases-workshop.md`
- Automation Unification (done): `wiki/c-work/3-validate/2026-04-automation-unification.md`
- Trustee Accounting Bridge: `gateway/modules/features/trustee/accounting/accountingBridge.py`
- Accounting Data Sync: `gateway/modules/features/trustee/accounting/accountingDataSync.py`
- Feature Data Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Feature Data Provider: `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py`
- Feature Sub-Agent Tool: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py`
- Toolbox Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- Abacus Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Node Registry: `gateway/modules/features/graphicalEditor/nodeRegistry.py`
- Trustee Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- SharePoint Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- Flow Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/flow.py`
- Action Node Executor: `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py`
- Execution Engine: `gateway/modules/workflows/automation2/executionEngine.py`
- Scheduler: `gateway/modules/workflows/scheduler/mainScheduler.py`
- Trustee Workflow Method: `gateway/modules/workflows/methods/methodTrustee/methodTrustee.py`
- Graphical Editor Feature: `gateway/modules/features/graphicalEditor/mainGraphicalEditor.py`
- Graphical Editor Datenmodell: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
## Abschluss
- [x] b-reference/gateway/workflow.md aktualisiert (neue Action `trustee.refreshAccountingData`)
- [x] b-reference/gateway/ai-agent.md aktualisiert (`aggregateTable` Tool im Sub-Agent, Trustee-Toolbox)
- [x] b-reference/gateway/automation.md aktualisiert (neue Trustee-Nodes + Kategorie in Node-Palette)
- [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument z-archive/ verschoben