diff --git a/TOPICS.md b/TOPICS.md index 87e647f..0570598 100644 --- a/TOPICS.md +++ b/TOPICS.md @@ -1,5 +1,5 @@  - + # Themen-Index für AI-Kontext @@ -33,7 +33,7 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en). |-------|-------|------------| | Neutralisierung | b-reference/platform/neutralization.md | Datenschutz, AI-Call-Pipeline, Failsafe | | RBAC | b-reference/platform/rbac.md | 4-Stufen-Modell, Template-Rollen, Resolution, Datenmodell | -| Datenbank-Architektur | b-reference/platform/database-architecture.md | Interface-Pattern, Connector, Auto-Init, DB-Liste | +| Datenbank-Architektur | b-reference/platform/database-architecture.md | Interface-Pattern, Connector, Auto-Init, DB-Liste, Database Health, Orphan-Scanner | | Navigation | b-reference/platform/navigation.md | Menü-Struktur, Admin-Seiten, API | | Compliance & AI-Audit | b-reference/platform/audit.md | AI-Datenfluss-Log, Security-Audit, Statistiken, RBAC | | i18n / Mehrsprachigkeit | b-reference/gateway/architecture.md (Abschnitt i18n), d-guides/coding-conventions.md (Backend i18n), b-reference/frontend-nyla/architecture.md (Routing/i18n) | `t()`, `@i18nModel`, UiLanguageSet, TextMultilingual, AI-Uebersetzung, Boot-Sync | @@ -50,7 +50,9 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en). | Gateway i18n Phase 7 (done) | c-work/3-validate/2026-04-gateway-i18n-phase-7-implementation.md | RBAC-Keys (rbac.*) im xx-Set, `translate-field` API, FormGenerator KI-Button | | Gateway Duplicate Class Names (done) | c-work/3-validate/2026-04-gateway-duplicate-class-names.md | TaskResult, AiResponse, TableData, Token Umbenennungen | | Generic Graph Editor (Typed Nodes, done) | c-work/3-validate/2026-04-generic-graph-editor.md | Port-Typen, Extraktoren, FrontendType-Renderer, System-Variablen | +| Unified Document Model (UDM) & Workflows (done) | z-archive/2026-04-unified-document-model.md, b-reference/gateway/workflow.md (Abschnitt UDM) | UDM-Baum, Extract-Node, Loop/Consolidate, Agent-UDM-Tools | | i18n Static Text Elimination (Ph. 1–2 done) | c-work/2-build/2026-04-i18n-static-text-elimination.md | Gateway Feature+Nodes: Dicts → de-Keys; Ph. 3–5 offen | +| Database Health & Data Cleanup (done) | z-archive/2026-04-database-health-and-data-cleanup.md | DB-Registry, FK-Discovery, Orphan-Scanner, Admin-Seite | ## Prozess & Betrieb diff --git a/b-reference/gateway/ai-agent.md b/b-reference/gateway/ai-agent.md index c1140e9..2a56c28 100644 --- a/b-reference/gateway/ai-agent.md +++ b/b-reference/gateway/ai-agent.md @@ -1,5 +1,5 @@ - + # AI Agent & Knowledge Store @@ -92,7 +92,7 @@ Zusätzlich zu den unten genannten **Kern-Tools** existieren **dynamische Tools* **Toolbox-Zuordnung:** Kern-Tools sind den Toolboxes `core`, `ai` und `datasources` zugeordnet (siehe Toolbox Registry oben). Connection-abhaengige Tools (`email`, `sharepoint`, `clickup`, `jira`) werden nur aktiviert, wenn der User eine passende Connection hat. Workflow-Editing-Tools (`workflow` Toolbox) werden separat via `workflowTools.py` registriert. -### Kern-Tools (registriert via `registerCoreTools` → `coreTools/`, 40 Stück) +### Kern-Tools (registriert via `registerCoreTools` → `coreTools/`; Stand 2026-04 inkl. UDM-Helfer) **Workspace / Dateien** @@ -149,6 +149,9 @@ Zusätzlich zu den unten genannten **Kern-Tools** existieren **dynamische Tools* | `readContentObjects` | Gezielt Content-Objekte lesen | | `extractContainerItem` | Element aus Container extrahieren | | `summarizeContent` | KI-Zusammenfassung | +| `getUdmStructure` | UDM-JSON: Überblick (Knoten, Struktur, Block-Zahlen); `udmJson` als stringifiziertes Objekt | +| `walkUdmBlocks` | UDM traversieren: alle `ContentBlock`-Knoten mit Pfad und Kurz-Preview | +| `filterUdmByType` | UDM: alle Blöcke mit gegebenem `contentType` (z. B. `table`, `image`) | | `describeImage` | Vision-Analyse | | `renderDocument` | Dokument rendern | | `generateImage` | Bildgenerierung | diff --git a/b-reference/gateway/workflow.md b/b-reference/gateway/workflow.md index 7eaf788..fdb3571 100644 --- a/b-reference/gateway/workflow.md +++ b/b-reference/gateway/workflow.md @@ -1,5 +1,5 @@ - + # Workflow-Engine @@ -50,7 +50,7 @@ Methoden sind Python-Klassen unter `gateway/modules/workflows/methods/`; der **M | Method (`self.name`) | Actions (Registry-Keys) | |---------------------|-------------------------| | `context` | `getDocumentIndex`, `extractContent`, `neutralizeData`, `triggerPreprocessingServer` | -| `ai` | `process`, `webResearch`, `summarizeDocument`, `translateDocument`, `convertDocument`, `generateDocument`, `generateCode` | +| `ai` | `process`, `webResearch`, `summarizeDocument`, `translateDocument`, `convertDocument`, `generateDocument`, `generateCode`, `consolidate` (KI-Konsolidierung aggregierter Ergebnisse) | | `outlook` | `readEmails`, `searchEmails`, `composeAndDraftEmailWithContext`, `sendDraftEmail` | | `sharepoint` | `findDocumentPath`, `readDocuments`, `uploadDocument`, `listDocuments`, `analyzeFolderUsage`, `findSiteByUrl`, `downloadFileByPath`, `copyFile`, `uploadFile` | | `clickup` | `listTasks`, `searchTasks`, `getTask`, `createTask`, `updateTask`, `uploadAttachment` | @@ -61,6 +61,12 @@ Methoden sind Python-Klassen unter `gateway/modules/workflows/methods/`; der **M *Hinweis:* Ältere Kontext-Dokumente nennen für `context` u. a. `saveContent` / `transformContent`; der aktuelle Gateway-Stand listet die obigen Aktionen (Stand Abgleich Code / Review 2026-04-05). +### Graphical Editor — UDM, Loop, KI-Badge + +- **Unified Document Model (UDM):** Extraktion kann ein hierarchisches JSON (`Document` → `StructuralNode` → `ContentBlock`) liefern; Port-Typen `UdmDocument`, `UdmNodeList`, `ConsolidateResult` im Typed-Port-System (`portTypes.py`). +- **Nodes:** u. a. `context.extractContent` (ohne KI), `data.consolidate` (deterministisch), `ai.consolidate` (LLM), `flow.loop` mit Parametern `level` (UDM-Ebene) und `concurrency` (parallele Iterationen). +- **Kosten-Transparenz:** Jede Node-Definition trägt `meta.usesAi` (`true` | `false`). Das Frontend (`FlowCanvas`, Node-Palette) zeigt ein **AI-Badge** nur bei `usesAi: true`. + --- ## Aktionen diff --git a/b-reference/platform/database-architecture.md b/b-reference/platform/database-architecture.md index a08a837..1a02fdf 100644 --- a/b-reference/platform/database-architecture.md +++ b/b-reference/platform/database-architecture.md @@ -239,16 +239,84 @@ Felder mit fuehrendem `_` sind fuer Anwendungs-CUD geschuetzt -- der Connector e ## Feature-DB-Registrierung -Features registrieren sich **nicht** in einer zentralen DB-Liste. Stattdessen: +Jedes Interface registriert seine Datenbank ueber `registerDatabase()` aus `dbRegistry.py`: -1. `registry.py` → `registerAllFeaturesInCatalog()` laedt Feature-Main-Module -2. Jedes Feature-Main definiert seinen `FEATURE_CODE` und `dbDatabase` -3. Der Datenbank-Name wird in `_initializeDatabase()` des Feature-Interfaces gesetzt -4. Der `DatabaseConnector` erzeugt die DB automatisch beim ersten Zugriff +1. Jedes `interfaceDb*.py` / `interfaceFeature*.py` definiert eine Modul-Konstante (z.B. `appDatabase = "poweron_app"`) +2. Auf Modul-Ebene wird `registerDatabase(appDatabase)` aufgerufen — damit ist die DB im zentralen Registry +3. Der `DatabaseConnector` erzeugt die DB automatisch beim ersten Zugriff +4. Neue DBs werden automatisch erkannt, entfernte DBs verschwinden -### Admin-Sicht +--- -Die Admin-DB-Listing-API (`routeSecurityAdmin.py`) wurde am 2026-04-12 entfernt. Datenbank-Diagnostik erfolgt direkt ueber PostgreSQL-Tools oder das System-Dashboard. +## Database Health und Orphan-Scanner + +### Ueberblick + +SysAdmin-Seite unter **Admin > System > Datenbank-Gesundheit** mit zwei Funktionen: + +1. **Tabellenstatistiken** — Row Count, Size, Index Size, Last Vacuum/Analyze fuer alle Tabellen +2. **Orphan Cleanup** — Generische Erkennung verwaister Datensaetze mit Clean-Buttons + +### Dynamische DB-Registry (`modules/shared/dbRegistry.py`) + +- `registerDatabase(dbName, configPrefix)` — oeffentliche API, aufgerufen in jedem Interface +- `_getRegisteredDatabases()` — alle registrierten DBs +- `_getConnectorForDb(dbName)` — Factory fuer read-only Connector + +### Model-Registry (`modules/datamodels/datamodelBase.py`) + +- `_MODEL_REGISTRY: Dict[str, Type[PowerOnModel]]` — automatisch via `__init_subclass__` +- Jede `PowerOnModel`-Subklasse registriert sich beim Import (Tabellenname = Klassenname) + +### FK-Discovery (`modules/shared/fkRegistry.py`) + +- Scannt alle PowerOnModel-Subklassen nach `fk_target` in `json_schema_extra` +- Baut automatisch `{tableName → dbName}` Mapping aus den Annotationen +- Fallback: Catalog-Query (`information_schema.tables`) fuer unmapped Tables +- Cached nach erstem Scan +- `FkRelationship` Dataclass: `sourceDb, sourceTable, sourceColumn, targetDb, targetTable, targetColumn` + +### FK-Annotationen (`fk_target`) + +Jedes `*Id`-Feld das eine echte FK-Beziehung darstellt, hat `fk_target` in `json_schema_extra`: + +```python +mandateId: str = Field( + ..., + json_schema_extra={ + ..., + "fk_target": {"db": "poweron_app", "table": "Mandate"}, + }, +) +``` + +- Standard `targetColumn` ist `"id"`, Sonderfall `Feature.code` nutzt `"column": "code"` +- Felder ohne DB-FK (Stripe-IDs, Graph-Node-IDs, polymorphe referenceId) haben kein `fk_target` +- `fk_target` ist rein fuer Backend-Orphan-Detection, `fk_model`/`frontend_fk_*` bleiben fuer das UI + +### Orphan-Scanner (`modules/system/databaseHealth.py`) + +- `_getTableStats(dbFilter)` — `pg_stat_user_tables` + `pg_total_relation_size` +- `_scanOrphans(dbFilter)` — Same-DB: `NOT EXISTS`, Cross-DB: Parent-IDs laden + `NOT IN` +- `_cleanOrphans(db, table, column)` — loescht Orphans, gibt Count zurueck +- `_cleanAllOrphans()` — alle Orphans bereinigen +- 5-Minuten-Cache fuer Orphan-Ergebnisse + +### API (`modules/routes/routeAdminDatabaseHealth.py`) + +| Methode | Pfad | Beschreibung | +|---------|------|-------------| +| GET | `/api/admin/database-health/stats` | Tabellenstatistiken (optional `?db=...`) | +| GET | `/api/admin/database-health/orphans` | Orphan-Scan (optional `?db=...`) | +| POST | `/api/admin/database-health/orphans/clean` | Einzeln-Cleanup `{"db","table","column"}` | +| POST | `/api/admin/database-health/orphans/clean-all` | Batch-Cleanup aller Orphans | + +Alle Endpunkte: SysAdmin-only via `requireSysAdminRole`. + +### Frontend (`AdminDatabaseHealthPage.tsx`) + +- Tab "Statistiken": Sortierbare Tabelle mit DB-Filter und Summary-Leiste +- Tab "Orphan Cleanup": Tabelle mit Clean-Button pro Zeile + "Alle bereinigen" --- @@ -257,6 +325,10 @@ Die Admin-DB-Listing-API (`routeSecurityAdmin.py`) wurde am 2026-04-12 entfernt. | Thema | Pfad | |-------|------| | PostgreSQL Connector | `gateway/modules/connectors/connectorDbPostgre.py` | +| DB-Registry | `gateway/modules/shared/dbRegistry.py` | +| FK-Registry | `gateway/modules/shared/fkRegistry.py` | +| Database Health | `gateway/modules/system/databaseHealth.py` | +| Health API Route | `gateway/modules/routes/routeAdminDatabaseHealth.py` | | App-DB Interface | `gateway/modules/interfaces/interfaceDbApp.py` | | Chat-DB Interface | `gateway/modules/interfaces/interfaceDbChat.py` | | Management-DB Interface | `gateway/modules/interfaces/interfaceDbManagement.py` | @@ -268,3 +340,4 @@ Die Admin-DB-Listing-API (`routeSecurityAdmin.py`) wurde am 2026-04-12 entfernt. | Bootstrap / DB-Seed | `gateway/modules/interfaces/interfaceBootstrap.py` | | DB-Migration Script | `gateway/scripts/script_db_export_migration.py` | | Datenmodelle (Pydantic) | `gateway/modules/datamodels/` | +| Frontend Health Page | `frontend_nyla/src/pages/admin/AdminDatabaseHealthPage.tsx` | diff --git a/b-reference/platform/neutralization.md b/b-reference/platform/neutralization.md index 732cdd3..64060e8 100644 --- a/b-reference/platform/neutralization.md +++ b/b-reference/platform/neutralization.md @@ -1,6 +1,6 @@ - - + + # Neutralisierungs-System @@ -26,7 +26,7 @@ Orthogonal dazu (kein Ersatz des Gates, sondern Data-at-rest bzw. Workflow): 2. **Chat-/Session-Level:** `ServiceCenterContext.requireNeutralization` (z. B. Workspace, Automation). 3. **Pro Request:** `AiCallRequest.requireNeutralization` — expliziter Override auf dem Call. -**Quellen gesamt (OR-Logik):** Ist irgendwo Neutralisierung erforderlich (Feature-Instanz, Workflow/Session, konkretes Objekt mit `FileItem.neutralize` / `DataSource.neutralize` / `FeatureDataSource.neutralize`), wird entsprechend verarbeitet. Dokumentierte Produktregel: **Kein `False` von einer Quelle hebt ein `True` einer anderen auf.** +**Quellen gesamt (OR-Logik):** Ist irgendwo Neutralisierung erforderlich (Feature-Instanz, Workflow/Session, konkretes Objekt mit `FileItem.neutralize` / `FileFolder.neutralize` / `DataSource.neutralize` / `FeatureDataSource.neutralize` / `FeatureDataSource.neutralizeFields`), wird entsprechend verarbeitet. Dokumentierte Produktregel: **Kein `False` von einer Quelle hebt ein `True` einer anderen auf.** ## Was neutralisiert wird @@ -45,11 +45,13 @@ Im zentralen AI-Gate (`_neutralizeRequest`): ## Failsafe-Kette 1. **Toggle `FileItem.neutralize`:** Index und Chunks werden synchron gelöscht; Re-Index im Hintergrund verhindert Leaks bei Fehlern in der Nachindexierung. -2. **Indexierung:** `indexFile()` neutralisiert Text-Chunks bei `FileItem.neutralize=True` → Data-at-rest abgesichert. -3. **DataSource-Download:** `neutralize`-Flag wird auf erzeugte `FileItem`s vererbt. -4. **FeatureDataSource:** `_queryFeatureInstance()` setzt bei `neutralize=True` u. a. `requireNeutralization=True` für Sub-Agent-AI-Calls. -5. **AI-Call:** Bei erzwungener Neutralisierung (`requireNeutralization=True`) schlägt fehlgeschlagene Neutralisierung hart fehl (`RuntimeError` / Blockierung bzw. Entfernen betroffener Message-Teile — kein Durchleiten im Rohzustand). -6. **`_rehydrateResponse()`:** Als Hilfsmethode vorhanden; automatische Rückübersetzung der Modellantwort ist nicht mehr der Standardpfad. +2. **Toggle `FileFolder.neutralize`:** Propagiert `neutralize` rekursiv auf alle Dateien im Ordner; Index/Chunks werden pro Datei synchron gelöscht, Re-Index im Hintergrund. Neue/verschobene Dateien erben das Flag des Ziel-Ordners. +3. **Indexierung:** `indexFile()` neutralisiert Text-Chunks bei `FileItem.neutralize=True` → Data-at-rest abgesichert. +4. **DataSource-Download:** `neutralize`-Flag wird auf erzeugte `FileItem`s vererbt. +5. **FeatureDataSource (Tabellen-Level):** `_queryFeatureInstance()` setzt bei `neutralize=True` u. a. `requireNeutralization=True` für Sub-Agent-AI-Calls. +6. **FeatureDataSource (Feld-Level):** `neutralizeFields` definiert Spalten, deren Werte in `FeatureDataProvider` mit deterministischen Platzhaltern `[NEUT..]` ersetzt werden, bevor Daten den Sub-Agent erreichen. Gleichheits-Vergleiche bleiben möglich (stabiler Hash). +7. **AI-Call:** Bei erzwungener Neutralisierung (`requireNeutralization=True`) schlägt fehlgeschlagene Neutralisierung hart fehl (`RuntimeError` / Blockierung bzw. Entfernen betroffener Message-Teile — kein Durchleiten im Rohzustand). +8. **`_rehydrateResponse()`:** Als Hilfsmethode vorhanden; automatische Rückübersetzung der Modellantwort ist nicht mehr der Standardpfad. **Engine-Failsafe (Spezifikation):** Neutralisierung verlangt, Engine nicht verfügbar → nicht weiterverarbeiten; Teilfehler → Teil entfernen, nicht roh weitergeben; fehlendes internes Medienmodell → Medien-Part entfernen. @@ -66,10 +68,12 @@ Im zentralen AI-Gate (`_neutralizeRequest`): | **Feature-Config / DB** | `features/neutralization/datamodelFeatureNeutralizer.py`, `interfaceFeatureNeutralizer.py` | | **RAG-Index** | `serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | | **Agent / Quellen** | `serviceCenter/services/serviceAgent/mainServiceAgent.py` (`_resolveDataSource`, `_downloadFromDataSource`, `_queryFeatureInstance`) | +| **Feld-Neutralisierung (DB)** | `serviceCenter/services/serviceAgent/featureDataProvider.py` — `_neutralizeRowFields`, `_applyFieldNeutralization` | | **Datei-Toggle / Index** | `routes/routeDataFiles.py` — `PATCH /{fileId}/neutralize` | +| **Ordner-Toggle / Index** | `routes/routeDataFiles.py` — `PATCH /folders/{folderId}/neutralize` (rekursive Propagierung) | | **Workflow-Aktion** | `workflows/methods/methodContext/actions/neutralizeData.py` | | **Kontext** | `serviceCenter/context.py` — `requireNeutralization` | -| **Flags (Modelle)** | `datamodels/datamodelFiles.py` (`FileItem.neutralize`), `datamodelDataSource.py`, `datamodelFeatureDataSource.py` | +| **Flags (Modelle)** | `datamodels/datamodelFiles.py` (`FileItem.neutralize`), `datamodelFileFolder.py` (`FileFolder.neutralize`), `datamodelDataSource.py`, `datamodelFeatureDataSource.py` (`neutralize`, `neutralizeFields`) | | **AI-Operationen / Enums** | `datamodels/datamodelAi.py`, `aicore/aicorePluginPrivateLlm.py` | ## Regeln / Invarianten diff --git a/c-work/1-plan/2026-04-consolidated-customer-requirements.md b/c-work/1-plan/2026-04-consolidated-customer-requirements.md new file mode 100644 index 0000000..f62bb0a --- /dev/null +++ b/c-work/1-plan/2026-04-consolidated-customer-requirements.md @@ -0,0 +1,572 @@ + + + + + +# Konsolidierter Kundenwünsche-Plan — PORTA Umsetzung + +> **Stand:** 16. April 2026 (aktualisiert mit PWG-Workshop-Ergebnissen) +> **Zweck:** Einheitliche Übersicht aller Kundenwünsche, priorisiert und gegen die Codebase abgeglichen. +> **Ersetzt:** `local/notes/demo-tue-use-cases-inputs-customers.md`, `c-work/1-plan/2026-04-demo2-merged-customer-trustee-plan.md`, `c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md` + +--- + +## Kunden-Übersicht + +| Kunde | Branche | Kontakte | Hauptinteresse | Status | +|-------|---------|----------|----------------|--------| +| **Bling** | Treuhandbüro | KJS | Belegverarbeitung, Budget, Dashboards, Mandantenmanagement | Trial geplant | +| **PWG** (Stiftung) | Immobilien/Wohnen (~300 Liegenschaften, 7–8 Pers.) | MB | **Pilot: Jahresmietzinsbestätigungen** (3'200/Jahr), Belegverarbeitung Abacus, CommCoach, Neutralisierung, Knowledge-Retrieval | Workshop 16.04.2026 ✅ — Pilot bestätigt, Versand Sommer 2026 | +| **Quid / ServiceHunter** | SaaS/Dienstleistung | DC | KPI-Dashboard, Zeiterfassung, Prognosen, Konsolidierung | Follow-up geplant | + +--- + +## Legende Codebase-Status + +| Symbol | Bedeutung | +|--------|-----------| +| ✅ | Im Code vorhanden und funktional | +| 🔧 | Grundstruktur vorhanden, Anpassung/Ergänzung nötig | +| ❌ | Noch nicht umgesetzt | +| ⏸️ | Bewusst zurückgestellt (wartet auf Input/Entscheid) | + +--- + +## Teil 1: Feature-Anforderungen (Kunden-Use-Cases) + +### 1.1 Automatisierte Belegverarbeitung & Spesenverwaltung + +**Kunden:** Bling (Prio hoch), PWG, Quid (Spesen) + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.1.1 | Spesenbelege per Foto → automatische Klassifikation (Rechnung, Spesenbeleg, Bankauszug) | ✅ | `methodTrustee/actions/extractFromFiles.py` + `processDocuments.py` — Pipeline extrahiert, klassifiziert, verbucht | +| 1.1.2 | SharePoint-Synchronisation (automatisch, z.B. täglich 22:00) | ✅ | `nodeDefinitions/sharepoint.py` — 6 Nodes; `automation2/scheduleCron.py` für Zeitsteuerung; System-Template "Treuhand: PDF-Klassifizierung & Trustee-Import" in `interfaceBootstrap.py` | +| 1.1.3 | Automatische Kontierung basierend auf Kontoplan | ✅ | In `processDocuments.py` — AI-gestützte Kontierung gegen Feature-Daten (Kontoplan via Accounting-Bridge) | +| 1.1.4 | Firmen-Mapping zu Kunden/Lieferanten | 🔧 | Grundstruktur in Accounting-Bridge; kein dediziertes Mapping-UI oder regelbasiertes Matching | +| 1.1.5 | Optionales Tagging (z.B. "Fuel Station") | 🔧 | Tags auf Dokument-Ebene möglich; kein Beleg-spezifisches Tag-System | +| 1.1.6 | Buchungsregeln für wiederkehrende Belege | ❌ | Kein regelbasiertes Booking-Template-System | +| 1.1.7 | Vorsteuer automatisch hinterlegen und auslesen | 🔧 | Accounting-Connectors liefern Steuerdaten; automatische MWST-Zuordnung bei Belegverarbeitung nicht explizit | +| 1.1.8 | Integration RunMyAccounts | ✅ | `accountingConnectorRma.py` | +| 1.1.9 | Integration Bexio | ✅ | `accountingConnectorBexio.py` | +| 1.1.10 | Integration Abacus | ✅ | `accountingConnectorAbacus.py` | +| 1.1.11 | Integration Xero | ❌ | Kein `accountingConnectorXero.py` — kein Code vorhanden | +| 1.1.12 | PDF/Excel/Word/Zip Verarbeitung | ✅ | Extraktoren vorhanden; UDM-Konzept in `0-ideas/unified-document-model.md` | + +### 1.2 Budget / Soll-Ist-Vergleich + +**Kunden:** Bling (Prio hoch), Quid (KPI-Kontext) + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.2.1 | Budget-Excel hochladen und gegen Live-Daten prüfen | 🔧 | Prompt-Template "Budget-Vergleich" in `mainTrustee.py` (Quick Action + Template Workflow); Frontend `TrusteeAnalyseView.tsx` hat Budget-Tab mit Upload; **aber kein Demo-Budget-Excel vorhanden** | +| 1.2.2 | Vergleiche über Perioden (Q1 aktuell vs. Vorjahr vs. Budget) | ✅ | Im Prompt-Template als Anweisung an AI-Agent enthalten | +| 1.2.3 | Automatische Diagramm-Erstellung | ✅ | Agent erzeugt Charts via `aggregateTable` + AI-Prompt | +| 1.2.4 | Live-Daten via API (kein PDF-Export nötig) | ✅ | `refreshAccountingData` Action synct Live-Daten; API-basiert | +| 1.2.5 | Caching konfigurierbar | ✅ | `_featureQueryCache` mit TTL 300s in `_featureSubAgentTools.py` | +| 1.2.6 | Abweichungen mit Begründung | ✅ | Im Prompt-Template: Agent soll Abweichungen erklären | +| 1.2.7 | Vorausschauende Prognosen | ✅ | Separates Prompt-Template "Prognose/Trend-Analyse" | + +### 1.3 Cashflow-Rechnung + +**Kunden:** Bling + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.3.1 | Plausibilisierung und Erstellung Cashflow-Rechnung | ✅ | Prompt-Template "Cashflow-Rechnung" in `mainTrustee.py` | +| 1.3.2 | Nicht-relevante Positionen berücksichtigen | ✅ | Im Prompt-Template als Anweisung | +| 1.3.3 | Warnungen bei kritischen Werten | ✅ | Im Prompt-Template | + +### 1.4 Dashboard — Bilanz- & Erfolgsrechnungsanalyse + +**Kunden:** Bling, Quid + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.4.1 | KPI-Dashboard (Bruttogewinn, ROI, Gewinn etc.) | ✅ | Prompt-Template "KPI-Dashboard" + Quick Action + `TrusteeAnalyseView.tsx` KPI-Tab | +| 1.4.2 | Check hälftiger Kapitalverlust | ✅ | Im Jahresabschluss-Prompt enthalten | +| 1.4.3 | Überschuldungs-Check | ✅ | Im Jahresabschluss-Prompt enthalten | +| 1.4.4 | Durchschnittliche Zahlungsfrist | 🔧 | Nicht als dedizierter KPI; Agent kann es berechnen wenn Daten vorhanden | + +### 1.5 Liquiditätsplanung + +**Kunden:** Bling + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.5.1 | Liquiditätsplanung analog Budgetplanung | 🔧 | Kein dediziertes Prompt-Template; über Prognose-Template teilweise abdeckbar | +| 1.5.2 | Automatische Erstellung aus Vergangenheit | 🔧 | Agent kann historische Daten analysieren; kein dedizierter Workflow | +| 1.5.3 | Zusätzliche Inputs (z.B. ausserordentliche Dividende) | ❌ | Kein Mechanismus für manuelle Zusatz-Inputs in Prognose | + +### 1.6 Gastro-Use-Case — Echtzeit-Rentabilitätsanalyse + +**Kunden:** Bling (Prio hoch, bestes Beispiel für Kunden-Mehrwert) + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.6.1 | Integration Kassensystem + Lohndaten + Buchhaltung | ⏸️ | **Wartet auf Kevin-Input** — kein Connector für Kassensysteme/Virux | +| 1.6.2 | Tagesumsatz vs. Personalkosten vs. Wareneinsatz | ⏸️ | Konzeptionell über generischen Data-Import möglich | + +### 1.7 Abschlussunterstützung + +**Kunden:** Bling, allgemein Treuhand + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.7.1 | Jahresabschluss-Checks | ✅ | Prompt-Template "Jahresabschluss prüfen" in `mainTrustee.py` | +| 1.7.2 | Abgrenzungsbuchungen vorbereiten | 🔧 | Im Prompt adressiert; keine dedizierte Automation | +| 1.7.3 | Bilanzkonti prüfen / Saldovalidierung | ✅ | Im Jahresabschluss-Prompt | +| 1.7.4 | Vorjahresvergleiche | ✅ | In mehreren Prompt-Templates | + +### 1.8 Zentrales Mandantenmanagement + +**Kunden:** Bling (verschiedene Systeme über eine Schaltzentrale) + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.8.1 | Verschiedene Kunden auf verschiedenen Systemen verwalten | ✅ | Multi-Tenant-Plattform ist Kernarchitektur; `accountingRegistry.py` unterstützt verschiedene Connectors pro Mandant | +| 1.8.2 | Ein Login, alle Mandanten | ✅ | Plattform-Feature: Mandantenwechsel im UI | +| 1.8.3 | Strikte Datentrennung | ✅ | Mandantenisolation auf DB- und API-Ebene | + +--- + +### 1.9 PWG — Stiftung für preisgünstiges Wohnen + +**Kontext:** ~300 Liegenschaften, Team 7–8 Personen. IT-Leiter Markus Brütsch (seit 2+ Jahren). Neue Rolle "Organella" für Digitalisierung (Schnittstelle Technologie/Betrieb, kein IT-Hintergrund). PWG evaluiert AI-Lösungen offen, noch keine Entscheidung getroffen. Workshop 16.04.2026 durchgeführt. + +**Pilotprojekt bestätigt:** Jahresmietzinsbestätigungen (siehe 1.9.9). + +#### 1.9a Plattform-Features (bestehend) + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.9.1 | Automatisierte Belegverarbeitung mit Abacus | ✅ | `accountingConnectorAbacus.py` + Trustee-Pipeline | +| 1.9.2 | Kommunikations-Coach für Mietergespräche | ✅ | `features/commcoach/` — komplett inkl. 10+ Personas | +| 1.9.3 | Immobilien-Personas (Zahlungsrückstand, Nebenkosten, Einzug, Lärm) | ✅ | 4 PWG-Personas in `BUILTIN_PERSONAS` + Seeding | +| 1.9.4 | KI-Arbeitsplatz mit Datenneutralisierung | ✅ | `features/neutralization/` — PII-Masking, Playground, Private-LLM; Daten-Residency Schweiz | +| 1.9.5 | PWG-Agent (Stiftungsstil, öffentliche PDFs als Futter) | 🔧 | Knowledge-Base-Feature vorhanden; kein PWG-spezifisches Knowledge-Set (Geschäftsberichte, Vermietungsreglement, Führungshandbuch etc.) | +| 1.9.6 | M365-Anbindung (SharePoint, Outlook, OneDrive, Teams) | ✅ | SharePoint-Nodes + Outlook-Methode in Workflows; nutzt nativen SharePoint-Index | +| 1.9.7 | KI-Auswertung Abacus-Daten/Reports | ✅ | Über Trustee-Feature + `aggregateTable` + AI-Prompts; Read/Write via Abacus-API | +| 1.9.8 | Grundstücksanalyse (öffentliche Daten: GIS, Maps, Grundbuch) | ❌ | Kein Connector/Workflow für öffentliche Geodaten | + +#### 1.9b Neue Anforderungen aus Workshop 16.04.2026 + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.9.9 | **Pilotprojekt: Jahresmietzinsbestätigungen** (ca. 700–800 Schreiben/Quartal, Versand Sommer 2026) | ❌ | Kein dedizierter Workflow — siehe Workflow-Design unten | +| 1.9.10 | FileMaker-Integration (Portfolio, Liegenschaften, Erneuerungsplanung, Bauprojekte, Akquisition) | ❌ | Kein FileMaker-Connector; Datenmenge/-qualität muss geprüft werden | +| 1.9.11 | Template-basierte Dokumentenerstellung (HTML-Templates → Word mit Corporate Design) | 🔧 | Code-Editor mit Claude vorhanden; kein Template-to-Word-Pipeline | +| 1.9.12 | Notification-System (reagiert auf DB-Änderungen, Berichte per E-Mail, Workflow-Trigger) | 🔧 | E-Mail-Versand in Workflows vorhanden (`methodOutlook`); kein generisches DB-Change-Detection-System | +| 1.9.13 | Information Retrieval über diverse Wissensquellen (Guidelines, Handbücher, SharePoint) | 🔧 | Knowledge-Base + SharePoint-Index vorhanden; kein PWG-spezifisches Datenset geladen | +| 1.9.14 | Datenvalidierung als Erst-Schritt (welche Daten korrekt/aktuell?) | ❌ | Kein Daten-Audit-Workflow | +| 1.9.15 | Compliance & Audit: vollständiges Tracking aller AI-Transaktionen | ✅ | `ComplianceAuditPage.tsx` + Gateway-Logging; jede Anfrage protokolliert | +| 1.9.16 | Granulare Neutralisierungs-Kontrolle pro Datenquelle | ✅ | In Neutralisierungs-Feature konfigurierbar pro Source | + +#### 1.9c Pilot-Workflow: Jahresmietzinsbestätigungen + +**Business Case:** 4 × 800 Schreiben/Jahr = 3'200 Schreiben. Aktuell: Serienbrief → manueller Versand → Scan der Rückantworten → manuelle Verarbeitung. Ziel: AI-gestützte Verarbeitung der gescannten Rückantworten mit Antwortvorschlägen. + +**Workflow-Design (6–7 Schritte, davon 1 mit AI):** + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ PWG Pilot: Jahresmietzinsbestätigungen │ +│ │ +│ Phase 1: Generierung (bestehend bei PWG) │ +│ ┌──────────────────────────────────────┐ │ +│ │ System generiert Serienbrief │ (PWG-internes System) │ +│ │ mit aktuellen Mietdaten │ │ +│ └──────────┬───────────────────────────┘ │ +│ ▼ │ +│ Phase 2: Versand & Rücklauf (manuell) │ +│ ┌──────────────────────────────────────┐ │ +│ │ Manueller Versand + Scan der │ │ +│ │ Rückantworten → SharePoint-Ordner │ │ +│ └──────────┬───────────────────────────┘ │ +│ ▼ │ +│ Phase 3: PowerOn-Workflow (automatisiert) │ +│ │ +│ Step 1: trigger.schedule (täglich oder on-demand) │ +│ ▼ │ +│ Step 2: sharepoint.listFiles (Scan-Ordner, neue Dokumente) │ +│ ▼ │ +│ Step 3: flow.loop (für jedes gescannte Dokument) │ +│ ▼ │ +│ Step 4: sharepoint.downloadFile + trustee.extractFromFiles │ +│ → OCR/Extraktion: Mietername, Adresse, Bestätigung, │ +│ Anmerkungen, Unterschrift ja/nein │ +│ ▼ │ +│ Step 5: ai.prompt ← EINZIGER AI-SCHRITT │ +│ → Gescannte Daten gegen Originaldaten prüfen │ +│ → Status klassifizieren (bestätigt / Abweichung / │ +│ fehlende Unterschrift / unleserlich) │ +│ → Antwortvorschlag generieren bei Abweichung │ +│ ▼ │ +│ Step 6: data.writeToTable (Ergebnis in Übersichtstabelle) │ +│ ▼ │ +│ Step 7: email.send (Zusammenfassung an Sachbearbeiter) │ +│ → Audit-Log für jeden Verarbeitungsschritt │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Benötigte Komponenten für den Pilot-Workflow:** + +| # | Komponente | Codebase-Status | Was zu tun ist | +|---|-----------|-----------------|----------------| +| W1 | `trigger.schedule` oder `trigger.manual` | ✅ | Vorhanden in `nodeDefinitions/triggers.py` | +| W2 | `sharepoint.listFiles` + `sharepoint.downloadFile` | ✅ | Vorhanden in `nodeDefinitions/sharepoint.py` | +| W3 | `flow.loop` | ✅ | Vorhanden in `nodeDefinitions/flow.py` | +| W4 | `trustee.extractFromFiles` (OCR/Extraktion gescannter Dokumente) | ✅ | Vorhanden; OCR für einseitige Scans unterstützt | +| W5 | `ai.prompt` — Prompt-Template "Mietzinsbestätigung prüfen" | ❌ | **Neues Prompt-Template** nötig: Scan-Daten gegen Originaldaten abgleichen, Status klassifizieren, Antwortvorschlag generieren | +| W6 | Ergebnis-Tabelle / Übersichtsliste (verarbeitete Bestätigungen) | 🔧 | `data`-Nodes existieren; kein dedizierter "Mietzinsbestätigungs-Report"-Output | +| W7 | `email.send` (Zusammenfassung an Sachbearbeiter) | ✅ | Vorhanden via `methodOutlook` | +| W8 | Abacus-Referenzdaten (Original-Mietzinsdaten für Abgleich) | 🔧 | Abacus-Connector vorhanden; Abfrage der Mietzins-Stammdaten muss konfiguriert werden | +| W9 | Audit-Logging für gesamten Prozess | ✅ | Plattform-Feature: alle AI-Transaktionen geloggt | +| W10 | Graph-Editor Workflow als Template speichern | ❌ | Workflow muss im Editor gebaut und als System-Template gespeichert werden | + +**Voraussetzungen (Action Items aus Workshop):** + +| # | Action Item | Verantwortlich | Status | +|---|------------|----------------|--------| +| AI1 | API-Zugang zu Abacus-Testmandant einrichten | Patrick Motsch | ❌ offen — Patrick koordiniert mit Abacus | +| AI2 | PWG muss Zugriff auf Testmandant bestätigen | PWG (Markus) | ❌ offen | +| AI3 | Preismodell bereitstellen (Grundgebühr/User/Monat + Token-Gebühr) | PowerOn | ❌ offen | +| AI4 | Datenschutzanforderungen und Vertragsklauseln für Lieferanten prüfen | PWG | ❌ offen | +| AI5 | Prozessschritte Pilot ausarbeiten und Kalkulation erstellen | PowerOn | 🔧 Workflow-Design in diesem Dokument; Kalkulation offen | +| AI6 | FileMaker-Datenmenge und -qualität prüfen (potenzielle Integration) | PWG + PowerOn | ❌ offen | + +--- + +### 1.10 Quid / ServiceHunter Use Cases + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 1.10.1 | KPI-Dashboard (Kundenmargen, ACV, Lifetime Value, Produktionsmarge) | 🔧 | Generisches KPI-Prompt-Template vorhanden; kundenspezifische KPIs brauchen Daten-Import | +| 1.10.2 | Zeiterfassung & Support-Analyse (Zendesk-Verknüpfung) | ⏸️ | **Kein Zendesk-Connector** — bewusst CSV-Upload-Workaround | +| 1.10.3 | Prognosen & Proaktive Steuerung | ✅ | Prognose-Prompt-Template vorhanden | +| 1.10.4 | Konsolidierung international (CH, DE, UK) | ⏸️ | **Wartet auf Lars-Meeting** — hohe Komplexität | +| 1.10.5 | Spesen-Automatisierung (SharePoint/Drive → verbuchen) | ✅ | SharePoint-Pipeline + Trustee-Import vorhanden | + +--- + +## Teil 2: UI/UX-Anforderungen (aus Team-Meeting / Nutzertests) + +### 2.1 AI-Workspace Usability + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 2.1.1 | Primäre Prompt-Zeile dominant sichtbar (kein "Wo tippe ich?") | 🔧 | `WorkspaceInput.tsx` funktional komplett; **Placeholder auf Englisch**, keine Hero-Eingabe, sekundäre Aktionen in einer Zeile | +| 2.1.2 | Empty State im Chat (Orientierung für Erstnutzer) | ❌ | `ChatStream.tsx` zeigt blank area wenn `messages.length === 0` — **kein Welcome/Empty-State** | +| 2.1.3 | "Neuer Chat" sichtbar ohne UDB-Sidebar | ❌ | Nur `+` in `ChatsTab` Toolbar; kein zentraler CTA | +| 2.1.4 | Datei-Drop Entdeckbarkeit | 🔧 | Vollflächen-Drop existiert in `WorkspacePage.tsx`; kein dauerhafter Hinweis im leeren Chat | +| 2.1.5 | DE-Placeholder und i18n | ❌ | Placeholder noch auf Englisch (`Type a message...`) | + +### 2.2 Responsive Layout & Breakpoints + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 2.2.1 | Zwischen-Breakpoint (1025–1280px): Sidebars auto-einklappen | ❌ | `isMobile` nur bei `≤1024px`; schmale Desktop-Fenster → Mittelspalte zu schmal | +| 2.2.2 | Visuelle Hierarchie Prompt (Schatten/Rand, minHeight) | ❌ | `WorkspaceInput.tsx` ohne besondere Hervorhebung | +| 2.2.3 | Viewport-Testmatrix (1100/1200/1280/1440) | ❌ | Kein Test-Setup dafür | + +### 2.3 Vertrauen & Marketing-UI + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 2.3.1 | Trust-Badges (Daten hosted in der Schweiz, Anbieter/Standort) | ❌ | Login: **kein** Hosting-Hinweis; keine `TrustFooter`/`TrustStrip` Komponente | +| 2.3.2 | "Recommended by" Partner-Strip (Valion, PamoCreate, Swiss AI Association etc.) | ❌ | Keine Partner-Logos/Links | +| 2.3.3 | Swiss ® am Logo | ❌ | Nur im Bildasset, nicht in UI sichtbar (Legal klären) | +| 2.3.4 | Sicherheits-Banner in SourcesTab ("Verbindung ist read-only") | ❌ | `SourcesTab.tsx` ohne Info-Banner | + +### 2.4 Billing & Pricing Auffindbarkeit + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 2.4.1 | Billing-Funktionalität (komplett) | ✅ | `BillingDataView.tsx` mit Tabs, Balance Cards, Transaktionen | +| 2.4.2 | Einstieg Billing nach Login (Teaser/Banner) | ❌ | Kein Dashboard-Teaser; Zugang nur via Nav-Baum + User-Menü | +| 2.4.3 | Balance im UserSection (neben Avatar) | ❌ | Nur Menü-Eintrag "Guthaben" | +| 2.4.4 | Billing-Copy für Nicht-Admins | ❌ | Kein Hinweis "Frag deinen Admin" | + +### 2.5 Onboarding & Erstnutzung + +| # | Anforderung | Codebase-Status | Evidenz / Bemerkung | +|---|-------------|-----------------|---------------------| +| 2.5.1 | Connector-Onboarding ("sicher verbinden, nichts kaputt") | ❌ | Keine Microcopy in SourcesTab | +| 2.5.2 | Progressive Offenlegung (weniger gleichzeitig auf Startscreens) | ❌ | Workspace zeigt alles parallel | + +--- + +## Teil 3: Infrastruktur & Demo-Vorbereitung + +### 3.1 Demo-Konfigurationen + +| # | Item | Codebase-Status | Evidenz / Bemerkung | +|---|------|-----------------|---------------------| +| 3.1.1 | Demo-Config-Infrastruktur (Base + Admin API) | ✅ | `_baseDemoConfig.py`, `routeAdminDemoConfig.py` | +| 3.1.2 | Referenz: `investorDemo2026.py` | ✅ | Vollständiges Muster mit Mandant, User, Features, Billing | +| 3.1.3 | Demo-Mandant "Bling Demo" | ❌ | Kein `blingDemo2026.py` | +| 3.1.4 | Demo-Mandant "PWG Demo" | ❌ | Kein `pwgDemo2026.py` | +| 3.1.5 | Demo-Mandant "Quid Demo" | ❌ | Kein `quidDemo2026.py` | + +### 3.2 Testdaten + +| # | Item | Codebase-Status | Evidenz / Bemerkung | +|---|------|-----------------|---------------------| +| 3.2.1 | Fiktives Mieterdossier (Neutralisierung) | ✅ | `demoData/neutralizer/tenant-dossier.pdf` + Generator | +| 3.2.2 | Knowledge-Base Demo-Dateien | ✅ | `demoData/knowledge-base/` — 4 Dateien | +| 3.2.3 | Budget-Excel (Soll-Werte) | ❌ | Kein `.xlsx` im Repo | +| 3.2.4 | Musterbelege (Rechnung, Spesen, Bank, Versicherung) | ❌ | Keine Demo-Belege | +| 3.2.5 | Quid-Testdaten (CSV: Umsatz, Kunden, Support) | ❌ | Keine kundenspezifischen Testdaten | +| 3.2.6 | Bling-Testdaten (Bexio-kompatibel) | ❌ | Keine Bexio-Testdaten | +| 3.2.7 | PWG-Testdaten (Abacus-kompatibel) | ❌ | Keine Abacus-Testdaten | + +### 3.3 Demo-Workflows & Skripte + +| # | Item | Codebase-Status | Evidenz / Bemerkung | +|---|------|-----------------|---------------------| +| 3.3.1 | System-Template "Treuhand: PDF-Klassifizierung" | ✅ | In `interfaceBootstrap.py` | +| 3.3.2 | Demo-Workflow (manual trigger → SharePoint → Trustee Pipeline) | ❌ | System-Template existiert, aber kein dedizierter Demo-Workflow | +| 3.3.3 | Demo-Skript Bling | ❌ | | +| 3.3.4 | Demo-Skript PWG | ❌ | | +| 3.3.5 | Demo-Skript Quid | ❌ | | +| 3.3.6 | Neutralisierungs-Demo-Flow (Schritt-für-Schritt) | ❌ | Kein Skript | + +--- + +## Teil 4: Allgemeine Treuhand-Use-Cases (Prozessdokumentation) + +Diese Use Cases stammen aus der allgemeinen Treuhand-Prozessdokumentation und sind für **alle** Kunden relevant. + +### 4.1 Datenerfassung — Kleine Unternehmen + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.1.1 | Belege sortieren & mit Banktransaktionen referenzieren | 🔧 — Belegverarbeitung vorhanden; kein Bank-Statement-Matching | +| 4.1.2 | Import Banktransaktionen via Excel/CSV | 🔧 — File-Upload + Extraktion vorhanden; kein dedizierter Bank-Import | +| 4.1.3 | Automatisierte Rückfragen an Kunden bei fehlenden Belegen | ❌ | + +### 4.2 Lohnbuchhaltung + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.2.1 | Überleitung Lohnaufwand (Fibu vs. Lohnbuchhaltung) | ❌ — Kein Lohn-Feature | +| 4.2.2 | Nicht-lohnwirksame Buchungen identifizieren | ❌ | +| 4.2.3 | Fehlende Lohnmeldungen erkennen | ❌ | + +### 4.3 Steuererklärung + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.3.1 | Belege nach Kategorien ordnen | 🔧 — Klassifikation vorhanden | +| 4.3.2 | Steuererklärung erstellen | ❌ — Kein Steuer-Feature | +| 4.3.3 | Vorjahresvergleich und Plausibilisierung | ✅ — In Analyse-Prompts | + +### 4.4 Jahresabschluss (Mittlere/Grosse Unternehmen) + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.4.1 | Banksalden abgleichen (Buchhaltung vs. Bank) | 🔧 — Konzeptionell via Agent; kein dedizierter Check | +| 4.4.2 | PayPal, Revolut, ausländische Konten nachbuchen | ❌ | +| 4.4.3 | Wertschriftendepot nachbuchen | ❌ | +| 4.4.4 | Fehlerkonto-Transaktionen bereinigen | ❌ | +| 4.4.5 | Kreditkartenkonto abstimmen | ❌ | +| 4.4.6 | Zahlungsanbieter prüfen (Stripe, Amex) | ❌ | +| 4.4.7 | Nebenbücher mit Fibu abstimmen | ❌ | +| 4.4.8 | Skonto-Differenzen ausbuchen | ❌ | +| 4.4.9 | Konzerninterne Abstimmung | ❌ | +| 4.4.10 | Darlehenskonten abgleichen, Zinsen berechnen | ❌ | +| 4.4.11 | Fremdwährungsbewertung gemäss ESTV | ❌ | +| 4.4.12 | Eigenkapitalveränderungen mit HR abgleichen | ❌ | +| 4.4.13 | Umsatz-/Aufwandsplausibilisierung | ✅ — Im Jahresabschluss-Prompt | +| 4.4.14 | Rechnungsabgrenzungen (aktiv/passiv) | 🔧 — Im Prompt adressiert | +| 4.4.15 | Abschreibungen erfassen | ❌ | +| 4.4.16 | MWST-Jahresabstimmung | ❌ | +| 4.4.17 | Steueraufwand-Rückstellungen berechnen | ❌ | +| 4.4.18 | Bilanz und ER plausibilisieren | ✅ — Im Jahresabschluss-Prompt | +| 4.4.19 | Analyse gesetzliche Bestimmungen (Kapitalverlust, Überschuldung) | ✅ — Im Jahresabschluss-Prompt | + +### 4.5 Finanzielle Führung & Controlling + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.5.1 | Businessplan → Absatzplanung → Ertragsplanung | ❌ | +| 4.5.2 | Investitionsplan und Finanzplan | ❌ | +| 4.5.3 | Budget mit Szenarien | 🔧 — Budget-Prompt vorhanden; Szenarien via Chat | +| 4.5.4 | Soll/Ist-Vergleich mit Abweichungsanalyse | ✅ — Budget-Vergleich Prompt-Template | +| 4.5.5 | Deckungsbeitragsrechnung | ❌ | +| 4.5.6 | Projekt-Controlling | ❌ | +| 4.5.7 | Benchmarkanalyse | ❌ | +| 4.5.8 | KPI-Monitoring mit proaktiver Benachrichtigung | 🔧 — KPIs via Agent; kein proaktives Alert-System | + +### 4.6 Revisionen + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.6.1 | Ordentliche Revisionen unterstützen | ❌ — Kein Revisions-Feature | + +### 4.7 Steueroptimierung & Simulationen + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.7.1 | Jahresrechnung auf steuerliche Probleme prüfen | ❌ | +| 4.7.2 | Simulationen (Lohn vs. Dividende, Umzug, 3. Säule, BVG) | ❌ | +| 4.7.3 | MWST-Prüfung, VST-Korrekturen | ❌ | +| 4.7.4 | Steuerausscheidungen auf verschiedene Kantone | ❌ | + +### 4.8 Interdisziplinäre Themen + +| # | Anforderung | Codebase-Status | +|---|-------------|-----------------| +| 4.8.1 | Umstrukturierungen | ❌ | +| 4.8.2 | Steuer-/Vorsorgestrategien | ❌ | +| 4.8.3 | Nachfolgeplanung | ❌ | +| 4.8.4 | Unternehmensbewertungen | ❌ | + +--- + +## Zusammenfassung: Status-Überblick + +### Fertig (✅) — Kernplattform funktioniert + +| Bereich | Was steht | +|---------|-----------| +| **Trustee Agent-Tools** | `refreshTrusteeData`, `aggregateTable`, Connection-Pooling, Result-Caching | +| **Graph-Editor** | Trustee-Kategorie + 4 Nodes, SharePoint-Nodes, Flow-Nodes (Loop, If/Else, Switch, Merge) | +| **Prompt-Templates** | 5 Analyse-Typen (Budget, KPI, Cashflow, Prognose, Jahresabschluss) als Quick Actions + Template Workflows | +| **Accounting-Connectors** | Bexio, Abacus, RunMyAccounts | +| **Belegverarbeitung** | Extraktion → Klassifikation → Kontierung → Sync (end-to-end) | +| **CommCoach** | Feature komplett, 10+ Personas inkl. 4 Immobilien-Personas (PWG), Gamification, Seeding | +| **Neutralisierung** | PII-Masking, Playground, Private-LLM, Mieterdossier-PDF | +| **Multi-Tenancy** | Mandantenisolation, Datentrennung, Rollenwechsel | +| **Billing** | BillingDataView, Balance, Transaktionen, useBilling | +| **SharePoint-Integration** | 6 Workflow-Nodes + Automation | +| **Demo-Infrastruktur** | Base-Config, Admin-API, Investor-Demo als Referenz | + +### Teilweise (🔧) — Grundstruktur steht, Erweiterung nötig + +| Bereich | Was fehlt | +|---------|-----------| +| Firmen-Mapping Kunden/Lieferanten | Regelbasiertes Matching-UI | +| Beleg-Tagging | Beleg-spezifisches Tag-System | +| Vorsteuer-Automatisierung | MWST-Zuordnung bei Belegverarbeitung | +| Liquiditätsplanung | Dediziertes Prompt-Template | +| Workspace-Prompt | DE-Placeholder, visuelle Hervorhebung | +| Datei-Drop | Hinweis im Empty State | +| Budget-Prompt | Demo-Excel-Datei fehlt | + +### Offen (❌) — Noch zu bauen + +#### Prio 0: PWG-Pilot (Versand Sommer 2026 — Deadline-gebunden) + +| Item | Aufwand | Beschreibung | +|------|---------|-------------| +| Abacus-Testmandant API-Zugang | Extern | Patrick koordiniert mit Abacus; PWG muss Zugriff bestätigen | +| Prompt-Template "Mietzinsbestätigung prüfen" | Mittel | Neues Template: Scan vs. Originaldaten, Status-Klassifikation, Antwortvorschlag | +| Pilot-Workflow im Graph-Editor | Mittel | trigger → sharepoint.listFiles → loop → download → extract → ai.prompt → report → email | +| Abacus-Mietzins-Stammdaten-Abfrage | Klein | Konfiguration im Abacus-Connector für Mietzins-Referenzdaten | +| Demo-Mandant PWG | Mittel | `pwgDemo2026.py` — Trustee (Abacus), CommCoach, Neutralisierung, Workspace | +| PWG Knowledge-Set | Klein | Öffentliche PDFs (Geschäftsberichte, Vermietungsreglement) in Knowledge-Base laden | +| Preismodell / Kalkulation Pilot | Extern | Grundgebühr/User/Monat + Token-Gebühr; basierend auf 4×800 Schreiben/Jahr | + +#### Prio 1: Demo-Blocker / Weitere Kunden-Demos + +| Item | Aufwand | Beschreibung | +|------|---------|-------------| +| Demo-Mandant Bling | Mittel | `blingDemo2026.py` — Trustee (Bexio), Workspace, Graph-Editor | +| Demo-Mandant Quid | Klein | `quidDemo2026.py` — Workspace, Graph-Editor, CSV-Upload | +| Budget-Excel | Klein | Soll-Werte 2026 für Demo | +| Musterbelege (PDFs) | Klein | 3–5 Belege (Rechnung, Spesen, Bank, Versicherung) | +| Demo-Skripte | Klein | Schritt-für-Schritt pro Kunde | +| Neutralisierungs-Demo-Flow | Klein | Dokumentation | +| Demo-Workflow Graph-Editor (generisch) | Mittel | trigger.manual → SharePoint → Trustee Pipeline | + +#### Prio 2: UI/UX-Verbesserungen (Erstnutzer-Hürde senken) + +| Item | Aufwand | Beschreibung | +|------|---------|-------------| +| Empty State ChatStream | Klein | Titel, Bullets, "Neuer Chat" Button | +| DE-Placeholder + i18n | Klein | `WorkspaceInput.tsx` | +| "Neuer Chat" CTA in Mitte | Klein | `WorkspacePage.tsx` | +| Zwischen-Breakpoint (1025–1280px) | Mittel | Sidebar-Auto-Collapse | +| Trust-Strip/Footer (Login, Landing) | Mittel | Hosting Schweiz, Partner-Logos (Legal nötig) | +| Billing-Teaser nach Login | Klein | Link oder Banner | +| Connector-Onboarding Copy | Klein | Sicherheits-Banner in SourcesTab | +| Balance im UserSection | Klein | Zahl neben Avatar | + +#### Prio 3: Feature-Erweiterungen (Roadmap) + +| Item | Aufwand | Beschreibung | +|------|---------|-------------| +| Xero-Connector | Gross | Neuer Accounting-Connector | +| FileMaker-Connector (PWG) | Gross | Portfolio, Liegenschaften, Erneuerungsplanung; Datenmenge/-qualität erst prüfen | +| Buchungsregeln für wiederkehrende Belege | Mittel | Regel-Engine | +| Liquiditätsplanungs-Template | Klein | Neues Prompt-Template | +| KPI-Monitoring mit Alerts | Gross | Proaktives Benachrichtigungssystem | +| Template-basierte Dokumentenerstellung (HTML → Word) | Mittel | Erneuerungsstrategien, Corporate Design | +| DB-Change-Detection / Notification-Trigger | Mittel | Reagiert auf Datenbank-Änderungen, triggert Workflows | +| Datenvalidierungs-Workflow | Klein | Erst-Audit: welche Daten korrekt/aktuell | + +#### Prio 4: Zurückgestellt (wartet auf externen Input) + +| Item | Wartet auf | Kunde | +|------|-----------|-------| +| Gastro-Echtzeit-Integration | Kevin (Bling) soll UC ausformulieren | Bling | +| Zendesk-Connector | Bewusst CSV-Workaround | Quid | +| Regelbasierte Konsolidierung | Lars-Meeting | Quid | +| Grundstücksanalyse (GIS etc.) | Kundenpräzisierung | PWG | +| FileMaker-Integration (PWG) | Datenmenge/-qualität prüfen (PWG + PowerOn) | PWG | +| PWG Datenschutz-/Vertragsklauseln | PWG prüft intern (genossenschaftliche Struktur) | PWG | + +#### Langfristig: Allgemeine Treuhand-Automatisierung + +Die Use Cases aus Teil 4 (Lohnbuchhaltung, Steuererklärung, detaillierter Jahresabschluss, Revisionen, Steueroptimierung, interdisziplinäre Themen) sind **konzeptionell dokumentiert** aber noch **nicht in der Codebase**. Diese bilden die Langfrist-Roadmap und werden schrittweise über AI-Prompt-Templates und dedizierte Workflows umgesetzt, sobald die Kern-Use-Cases bei den ersten Kunden validiert sind. + +--- + +## Entscheidungen + +| Datum | Entscheidung | Begründung | +|-------|-------------|------------| +| 2026-04-07 | Prompt-Templates als Code in `mainTrustee.py` | Wartbar und versioniert statt externe Dateien | +| 2026-04-07 | `refreshTrusteeData` als separate Action | Separation of Concerns: Sync = schreibend, Query = lesend | +| 2026-04-07 | DB-Connection-Pooling statt Connection-per-Call | Grösster Performance-Hebel (~200ms pro Connection) | +| 2026-04-09 | Quid ohne Zendesk-Connector — CSV-Upload | Gleicher Analyse-Mehrwert, viel weniger Aufwand | +| 2026-04-09 | Gastro-UC und Konsolidierung auf Prio 4 | Warten auf Kunden-Input | +| 2026-04-09 | CommCoach-Personas als schnellster Wow-Effekt für PWG | Feature gebaut, nur Persona-Definitionen nötig | +| 2026-04-07 | UI-Enhancements: Fokus Erstnutzer-Hürde | Ohne klare Userführung springen Kunden ab | +| 2026-04-07 | Trust-Badges: kein ISO, sondern "Daten in CH" | Konkreter Nutzen > abstraktes Zertifikat | +| 2026-04-16 | PWG-Pilot = Jahresmietzinsbestätigungen als erster Produktiv-UC | Konkreter, messbarer Business Case (4×800 Schreiben); Deadline Sommer 2026 | +| 2026-04-16 | Workflow-Philosophie PWG: erst manuell testen, dann automatisieren | Agent wird aus manuell getesteten Prozessen erstellt; Workflows für wiederkehrende Aufgaben | +| 2026-04-16 | FileMaker-Integration auf Prio 4 | Datenmenge/-qualität muss erst geprüft werden; kein Blocker für Pilot | +| 2026-04-16 | Abacus-Testmandant als Voraussetzung für Pilot | Patrick koordiniert API-Zugang direkt mit Abacus | + +--- + +## Betroffene Module + +- **Gateway:** `features/trustee/` (Prompts, Quick Actions, Connectors), `features/commcoach/` (Personas), `features/neutralization/` (Demo-Config), `features/graphicalEditor/` (Nodes), `serviceCenter/services/serviceAgent/` (Tools, Caching), `demoConfigs/` (neue Configs), `workflows/methods/methodTrustee/` (Actions), `demoData/` (Testdaten) +- **Frontend Nyla:** `WorkspacePage.tsx` (Layout, Breakpoints, Empty State), `WorkspaceInput.tsx` (Prompt, i18n), `ChatStream.tsx` (Empty State), `Login.tsx` (Trust-UI), `UserSection.tsx` (Balance), `SourcesTab.tsx` (Onboarding-Copy), `BillingDataView.tsx` (Discovery) +- **DB-Migration:** Nein +- **Platform/Wiki:** Nach Release `b-reference/` aktualisieren + +## Links + +- PWG Workshop-Inputs (16.04.2026): `pamocreate/projects/poweron/customer-pwg/20260415-inputs-pwg.txt` +- Originale Kunden-Inputs: `local/notes/demo-tue-use-cases-inputs-customers.md` +- Merged Demo-Plan (ersetzt): `c-work/1-plan/2026-04-demo2-merged-customer-trustee-plan.md` +- UI-Enhancements Plan (ersetzt): `c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md` +- Investor-Demo (Referenz): `gateway/modules/demoConfigs/investorDemo2026.py` +- Frontend-Referenz: `b-reference/frontend-nyla/architecture.md` +- Trustee Main (Prompts): `gateway/modules/features/trustee/mainTrustee.py` +- CommCoach Personas: `gateway/modules/features/commcoach/serviceCommcoachPersonas.py` +- Neutralisierung: `gateway/modules/features/neutralization/` +- Graph-Editor Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/` +- Demo-Daten: `gateway/demoData/` +- UDM-Konzept: `c-work/0-ideas/unified-document-model.md` + +## Abschluss + +- [ ] Quell-Dokumente als "superseded by this document" markieren +- [ ] b-reference/ aktualisiert nach Umsetzung +- [ ] TOPICS.md aktualisiert +- [ ] Dieses Dokument → `1-plan/` verschieben wenn Umsetzung startet diff --git a/c-work/1-plan/2026-04-demo2-merged-customer-trustee-plan.md b/c-work/4-done/2026-04-demo2-merged-customer-trustee-plan.md similarity index 100% rename from c-work/1-plan/2026-04-demo2-merged-customer-trustee-plan.md rename to c-work/4-done/2026-04-demo2-merged-customer-trustee-plan.md diff --git a/c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md b/c-work/4-done/2026-04-porta-ui-enhancements-team-meeting.md similarity index 100% rename from c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md rename to c-work/4-done/2026-04-porta-ui-enhancements-team-meeting.md diff --git a/e-compliance/neutralisierung-detail.md b/e-compliance/neutralisierung-detail.md index c211e6a..5d5abeb 100644 --- a/e-compliance/neutralisierung-detail.md +++ b/e-compliance/neutralisierung-detail.md @@ -1,6 +1,6 @@ # Neutralisierung -**Stand:** 2026-03-29 +**Stand:** 2026-04-16 --- @@ -18,7 +18,7 @@ Drei Quellen, von breit nach spezifisch: |--------|-------------|-----------| | **Feature-Instanz** | `DataNeutraliserConfig.enabled` (hat `featureInstanceId` + `mandateId`) | Alle Daten in dieser Feature-Instanz werden neutralisiert. Betrifft jeden Content-Einstieg innerhalb dieser Instanz. | | **Chat-Workflow / Session** | `ServiceCenterContext.requireNeutralization` (gesetzt z. B. vom AI-Workspace oder Automation) | Dieser Workflow/Turn: jeder Content, der hier verarbeitet wird, wird neutralisiert. | -| **Dokument oder Quelle** | `FileItem.neutralize`, `DataSource.neutralize`, `FeatureDataSource.neutralize` | Dieses konkrete Objekt: Content daraus wird neutralisiert, egal ob die Feature-Instanz oder der Workflow es sonst fordern würden. | +| **Dokument oder Quelle** | `FileItem.neutralize`, `FileFolder.neutralize`, `DataSource.neutralize`, `FeatureDataSource.neutralize`, `FeatureDataSource.neutralizeFields` | Dieses konkrete Objekt: Content daraus wird neutralisiert, egal ob die Feature-Instanz oder der Workflow es sonst fordern würden. `FileFolder.neutralize` propagiert auf alle enthaltenen Dateien. `neutralizeFields` ermoeglicht Feld-Level-Maskierung bei DB-Queries. | **Auswertung:** Irgendeine Quelle sagt `True` → neutralisieren. Keine Quelle kann eine andere aufheben. Es gibt kein `False`-Override, das ein `True` von woanders aushebelt. @@ -34,7 +34,9 @@ Am **Punkt der Content-Einspeisung** — dort wo Rohdaten zu verarbeitbarem Cont | **Content-Extraktion** (Dokumente für KI-Verarbeitung) | Extrahierter Text/Tabellen werden neutralisiert. PDF, DOCX, XLSX, PPTX über `processFile` (Extract → neutralisieren → zurückschreiben). | Caller kennt die Quelle und deren Flag | | **User-Prompt** (Chat-Eingabe) | Prompt-Text wird durch `processText` neutralisiert, wenn Feature-Instanz oder Workflow es fordern. | `mainServiceAi` prüft Context-Flag / Config | | **DataSource-Download** | Flag wird auf erstellte `FileItem`s vererbt → bei Extraktion/Indexierung greift das File-Flag automatisch. | `mainServiceAgent._resolveDataSource` / `_downloadFromDataSource` | -| **FeatureDataSource-Abfrage** | Wenn eine `FeatureDataSource.neutralize=True` hat → Content aus diesem Sub-Agent-Call wird neutralisiert. | `mainServiceAgent._queryFeatureInstance` setzt `requireNeutralization=True` | +| **FeatureDataSource-Abfrage (Tabelle)** | Wenn eine `FeatureDataSource.neutralize=True` hat → Content aus diesem Sub-Agent-Call wird neutralisiert. | `mainServiceAgent._queryFeatureInstance` setzt `requireNeutralization=True` | +| **FeatureDataSource-Abfrage (Feld)** | `FeatureDataSource.neutralizeFields` definiert Spalten, deren Werte in `FeatureDataProvider` mit deterministischen Platzhaltern `[NEUT..]` ersetzt werden, bevor Daten den Sub-Agent erreichen. | `featureDataProvider._applyFieldNeutralization` | +| **Ordner-Neutralisierung** | `FileFolder.neutralize=True` propagiert auf alle enthaltenen Dateien (rekursiv). Neue/verschobene Dateien erben das Flag. Index-Purge + Re-Index wie bei einzelnen Dateien. | `routeDataFiles.updateFolderNeutralize` | | **Workflow-Aktion `neutralizeData`** | Expliziter Neutralisierungs-Schritt auf bereits extrahierten ContentParts. | Workflow-Config + `NeutralizationConfig.enabled` | **Was NICHT nochmal neutralisiert werden muss:** diff --git a/c-work/1-plan/2026-04-database-health-and-data-cleanup.md b/z-archive/2026-04-database-health-and-data-cleanup.md similarity index 87% rename from c-work/1-plan/2026-04-database-health-and-data-cleanup.md rename to z-archive/2026-04-database-health-and-data-cleanup.md index 3133822..4f28a5e 100644 --- a/c-work/1-plan/2026-04-database-health-and-data-cleanup.md +++ b/z-archive/2026-04-database-health-and-data-cleanup.md @@ -1,5 +1,6 @@ - + + # Database Health and Data Cleanup — Admin Page @@ -93,18 +94,18 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe **LLM: Opus 4.6** (Architektur-Entscheidungen, Cross-File-Refactoring) -- [ ] **DB-Registry** (`modules/shared/dbRegistry.py`) +- [x] **DB-Registry** (`modules/shared/dbRegistry.py`) - `registerDatabase(dbName: str, configPrefix: str = "DB")` — oeffentliche API, registriert eine DB - `_getRegisteredDatabases() -> Dict[str, str]` — intern, gibt alle registrierten DBs zurueck - `_getConnectorForDb(dbName: str) -> DatabaseConnector` — intern, Factory fuer Connector - Thread-safe (Lock oder atomare Operationen) - `registerDatabase` ohne `_` Prefix weil explizit als oeffentliche API fuer andere Module gedacht -- [ ] **Selbst-Registrierung in allen Interfaces** (~13 Dateien) +- [x] **Selbst-Registrierung in allen Interfaces** (~13 Dateien) - Jedes `interfaceDb*.py` und `interfaceFeature*.py` ruft `registerDatabase()` auf Modul-Ebene auf - Kein Umbau der bestehenden Connector-Logik — nur ein zusaetzlicher Registrierungs-Call -- [ ] **Model-Registry** (`modules/datamodels/datamodelBase.py`) +- [x] **Model-Registry** (`modules/datamodels/datamodelBase.py`) - `_MODEL_REGISTRY: Dict[str, Type[PowerOnModel]]` — automatisch via `__init_subclass__` - `_getModelByTableName(tableName: str) -> Optional[Type[PowerOnModel]]` — Lookup @@ -112,7 +113,7 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe **LLM: Composer Fast** (repetitive Annotation-Arbeit, klares Pattern) -- [ ] **fk_target auf allen FK-Feldern** (~80-90 Felder in ~20 Dateien) +- [x] **fk_target auf allen FK-Feldern** (~80-90 Felder in ~20 Dateien) - `modules/datamodels/datamodelMembership.py` — UserMandate, FeatureAccess, Junctions - `modules/datamodels/datamodelRbac.py` — Role, AccessRule - `modules/datamodels/datamodelFeatures.py` — FeatureInstance @@ -137,23 +138,26 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe **LLM: Opus 4.6** (komplexe Cross-DB-Logik, SQL-Generierung) -- [ ] **FK-Discovery** (`modules/shared/fkRegistry.py`) +- [x] **FK-Discovery** (`modules/shared/fkRegistry.py`) - `_discoverFkRelationships() -> List[FkRelationship]` — scannt Model-Registry, liest `fk_target` - Cached nach erstem Scan (Models aendern sich nicht zur Laufzeit) - - `FkRelationship` Dataclass: `sourceDb, sourceTable, sourceColumn, targetDb, targetTable` + - `FkRelationship` Dataclass: `sourceDb, sourceTable, sourceColumn, targetDb, targetTable, targetColumn` + - Table-to-DB Mapping automatisch aus `fk_target`-Annotationen + Catalog-Fallback -- [ ] **Orphan-Scanner** (`modules/system/databaseHealth.py`) +- [x] **Orphan-Scanner** (`modules/system/databaseHealth.py`) - `_scanOrphans(dbFilter: Optional[str]) -> List[OrphanResult]` - - Same-DB: `SELECT COUNT(*) WHERE col NOT IN (SELECT id FROM parent)` - - Cross-DB: Parent-IDs laden, dann `WHERE col NOT IN (...)` + - Same-DB: `NOT EXISTS (SELECT 1 FROM parent WHERE parent.col = source.col)` + - Cross-DB: Parent-IDs laden, dann `NOT IN (unnest(...))` - `_cleanOrphans(db, table, column) -> int` — loescht Orphans, gibt Count zurueck + - `_cleanAllOrphans() -> List[dict]` — alle Orphans bereinigen - `_getTableStats(dbFilter: Optional[str]) -> List[TableStats]` — pg_stat_user_tables Query + - 5-Minuten-Cache fuer Orphan-Ergebnisse ### Phase 4: API-Endpunkte (Backend) **LLM: Composer Fast** (Standard-Route-Pattern, klar definiert) -- [ ] **Route** (`modules/routes/routeAdminDatabaseHealth.py`) +- [x] **Route** (`modules/routes/routeAdminDatabaseHealth.py`) - Prefix: `/api/admin/database-health` - `GET /stats` — Tabellenstatistiken (optional `?db=...`) - `GET /orphans` — Orphan-Scan (optional `?db=...`) @@ -161,13 +165,13 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe - `POST /orphans/clean-all` — Alle Orphans bereinigen - Alle Endpunkte: SysAdmin-only via `requireSysAdminRole` -- [ ] **Router in app.py registrieren** +- [x] **Router in app.py registrieren** ### Phase 5: Navigation (Backend) **LLM: Composer Fast** (einzelne Zeile in mainSystem.py) -- [ ] **Navigation-Eintrag** in `modules/system/mainSystem.py` +- [x] **Navigation-Eintrag** in `modules/system/mainSystem.py` - Unter `admin-system-group`, order 98, sysAdminOnly - Icon: `FaDatabase`, Path: `/admin/database-health` @@ -175,11 +179,11 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe **LLM: Opus 4.6** (neue Seite mit Tabs, FormGeneratorTable-Integration) -- [ ] **AdminDatabaseHealthPage.tsx** mit zwei Tabs - - Tab 1 "Statistiken": FormGeneratorTable mit DB, Tabelle, Rows, Total Size, Table Size, Index Size, Last Vacuum, Last Analyze. Sortierbar, Summary-Zeile oben. - - Tab 2 "Orphan Cleanup": FormGeneratorTable mit DB, Tabelle, FK-Spalte, Referenz, Orphans, Total Rows, Clean-Button. Filter "Nur Probleme". Batch-Clean. -- [ ] **Routing** in Frontend PAGE_REGISTRY -- [ ] **i18n** — alle Labels mit `t()` taggen +- [x] **AdminDatabaseHealthPage.tsx** mit zwei Tabs + - Tab 1 "Statistiken": Sortierbare Tabelle mit DB, Tabelle, Rows, Total Size, Index Size, Last Vacuum, Last Analyze. Summary-Zeile oben. DB-Filter. + - Tab 2 "Orphan Cleanup": Tabelle mit Source DB, Tabelle, FK-Spalte, Referenz (inkl. cross-db Badge), Orphans, Clean-Button. Filter "Nur Probleme". Batch-Clean-All. +- [x] **Routing** in Frontend PAGE_REGISTRY + App.tsx Route + admin/index.ts Export +- [x] **i18n** — alle Labels mit `t()` getaggt ### Querschnitt-Checks @@ -223,6 +227,6 @@ Viele FK-Beziehungen gehen ueber Datenbank-Grenzen hinweg (z.B. `AutoWorkflow.fe ## Abschluss -- [ ] b-reference/ aktualisiert (gateway/architecture.md — neuer Abschnitt "Database Health") -- [ ] TOPICS.md aktualisiert (neues Thema "Database Health / Data Cleanup") -- [ ] Dieses Dokument → z-archive/ verschoben +- [x] b-reference/ aktualisiert (platform/database-architecture.md — neuer Abschnitt "Database Health") +- [x] TOPICS.md aktualisiert (neues Thema "Database Health / Data Cleanup") +- [x] Dieses Dokument → z-archive/ verschoben diff --git a/z-archive/2026-04-unified-document-model.md b/z-archive/2026-04-unified-document-model.md new file mode 100644 index 0000000..c1f7777 --- /dev/null +++ b/z-archive/2026-04-unified-document-model.md @@ -0,0 +1,685 @@ + + + + + +# Unified Document Model (UDM) — Dokumenten-Extraktion, Workflow ForEach & High-Volume + +> **Abgeschlossen am 2026-04-16.** Technische Referenz: `b-reference/gateway/workflow.md` (UDM, Nodes, Engine), `b-reference/gateway/ai-agent.md` (UDM-Tools). Konzept: `c-work/0-ideas/unified-document-model.md`. + +## Abschlussbericht + +- **Umgesetzt:** UDM-Datenmodell und Bridge, Extraktions-Pipeline (inkl. Registry-Singleton, PDF-Memory), `context.extractContent`, Port-Typen und Executor-Routing (`context.*` → `ActionNodeExecutor`), `data.consolidate` / `ai.consolidate`, Loop (`level`, `concurrency`), `flow.merge` mit dynamischer Input-Anzahl, `data.filter` mit UDM-Content-Type-Presets, Engine (Concurrency, StepLog-Batching, Streaming-Aggregate, Progress), `meta.usesAi` und AI-Badge im Editor, Agent-Tools (`getUdmStructure`, `walkUdmBlocks`, `filterUdmByType`), Referenzdoku in `b-reference/` und Eintrag in `TOPICS.md`. +- **Tests im Repo (Auszug):** `gateway/tests/unit/datamodels/test_udm_models.py`, `test_udm_bridge.py`, `gateway/tests/integration/extraction/test_extract_udm_pipeline.py`, `gateway/tests/integration/workflows/test_execute_graph_loop_aggregate_consolidate.py`, `gateway/tests/unit/nodeDefinitions/test_usesai_flag.py`, `gateway/tests/unit/serviceAgent/test_udm_agent_tools.py`. +- **Backlog / optional:** Erweiterung des ursprünglichen Testplan-Rasters (High-Volume-Referenzen, Fan-out/Merge-Integration, Concurrency-Benchmark, Load-Test 10k) nach Bedarf; UX wie explizite Loop-Body-Hervorhebung oder dedizierte NodeConfig-Komponenten können nachgelagert werden. + +## Grundlage: UDM-Konzept + +Dieses Feature basiert auf dem **Unified Document Model (UDM)** — einer generischen, formatunabhängigen 3-Ebenen-Baumstruktur für Dokumenten-Extraktion. Das vollständige Konzept mit Datenmodell, Format-Mappings (PDF, DOCX, PPTX, XLSX, HTML), Workflow-Integration, Archive-Handling und JSON-Beispielen ist hier definiert: + +→ **`c-work/0-ideas/unified-document-model.md`** + +**Kernprinzipien des UDM:** + +- **3-Ebenen-Garantie:** Jedes Dokument hat `Document` → `StructuralNode[]` → `ContentBlock[]` +- **Einheitliche Blattknoten:** Alle atomaren Inhalte sind `ContentBlock`-Objekte mit identischer Struktur +- **Generische Traversierung:** Workflow-Nodes arbeiten formatunabhängig über dieselbe Baumstruktur +- **Keine formatspezifischen Zwischenschichten:** Konzepte wie "Paragraph", "Row", "Cell" werden in `ContentBlock.attributes` absorbiert + +| Ebene | Typ | Beschreibung | +|-------|-----|-------------| +| Level 1 | `Document` | Wurzelknoten pro Quelldatei | +| Level 2 | `StructuralNode` | Seite, Abschnitt, Slide oder Sheet | +| Level 3 | `ContentBlock` | Atomarer Inhalt: Text, Bild, Tabelle, Code, Media, Link, Formel | + +Dieser Plan beschreibt **die Umsetzung** des UDM-Konzepts im Gateway, die nötigen Workflow-Nodes, und die High-Volume-Skalierbarkeit. + +--- + +## Beschreibung und Kontext + +Das bestehende Dokumenten-Extraktionssystem arbeitet mit `ContentPart` / `ContentExtracted` als flacher Liste. Das UDM ersetzt dieses Modell durch eine **hierarchische Baumstruktur**, die es erlaubt, über Level-Attribute (Seiten, Sections, Sheets, Slides) generisch zu iterieren. + +**Business-Treiber:** Workflows benötigen die Fähigkeit, ein Dokument zu extrahieren und dann **pro Struktureinheit** (z.B. pro PDF-Seite) eine Kette von Verarbeitungsschritten auszuführen — und am Ende die Teilergebnisse zu konsolidieren. Zusätzlich muss das System mit **grossen Datenmengen** umgehen können (z.B. ZIP mit 10.000 PDFs). + +**Heutige Lücken:** + +1. Es gibt **keinen Extract-Node** im Graphical Editor — `context.extractContent` existiert nur als Workspace-/Agent-Action, nicht als visuellen Node +2. Das Extraktionsmodell liefert keine hierarchische Baum-Struktur (nur flache `ContentPart`-Liste) +3. Der `flow.loop`-Node hat keine Sub-Workflow-Modellierung — der Loop-Body wird nur über Graph-Topologie implizit erkannt +4. Es gibt keinen dedizierten **Consolidate**-Schritt für strukturierte Zusammenführung nach ForEach +5. Die Engine ist **nicht skalierbar** für >1000 Iterationen (Memory, DB-Last, keine Parallelität) +6. Nodes im Editor haben **keine visuelle Kennzeichnung**, ob sie AI nutzen oder deterministisch arbeiten + +**Abhängigkeiten:** AI-Agent-Tools (`_documentTools.py`), Workflow-Engine (`executionEngine.py`), Graphical Editor (Frontend), Extraktion (`serviceExtraction`). + +**Risiko bei Nicht-Umsetzung:** Dokument-intensive Workflows (Trustee, Compliance-Audit, Massendokumentverarbeitung) bleiben manuell oder erfordern Custom-Code pro Use Case. + +--- + +## Fokus und kritische Details + +- **Migration des Extraktionsmodells:** `ContentPart` → UDM muss rückwärtskompatibel sein. Bestehende Konsumenten (`ChatContentExtracted`, Agent-Tools, Neutralisierung) dürfen nicht brechen. +- **Loop-Body mit parallelen Pfaden:** Fan-out von Loop-Output zu mehreren Nodes + Merge pro Iteration funktioniert in der Engine bereits (Topo-Sort garantiert Reihenfolge), aber `flow.merge` hat heute fix 2 Inputs. +- **High-Volume-Skalierbarkeit:** Bei 10k Iterationen entstehen Engpässe bei Memory (Base64-Bilder in nodeOutputs), DB (AutoStepLog pro Body-Node pro Iteration), und Laufzeit (sequentielle Verarbeitung). +- **Extractor-Performance:** `extractorContainer.py` erstellt pro Datei im ZIP eine neue `ExtractorRegistry()`-Instanz (Auto-Discovery). Bei 10k Dateien ist das ein massiver Overhead. +- **PDF-Memory:** `extractorPdf.py` lädt via `buf.getvalue()` eine Kopie des gesamten PDFs — doppelter Memory-Verbrauch pro Datei. + +--- + +## Ziel und Nicht-Ziele + +### Ziele + +1. **`context.extractContent`-Node** im Graphical Editor — reine Strukturextraktion OHNE AI +2. **UDM-Datenmodell** (`Document`, `StructuralNode`, `ContentBlock`, `Archive`) als Pydantic-Modelle +3. **Extractor-Adapter:** Bestehende Extractors liefern zusätzlich UDM-Output; Bridge `ContentPart` ↔ UDM +4. **ForEach-Workflow-Pattern:** Loop über UDM-Struktureinheiten mit parallelen Pfaden im Body und Merge pro Iteration +5. **Consolidate-Nodes:** `data.consolidate` (deterministisch) + `ai.consolidate` (AI-gestützt) für strukturierte Zusammenführung +6. **High-Volume-Fähigkeit:** ZIP mit 10.000+ PDFs verarbeitbar durch Streaming-Extraktion, Loop-Concurrency und StepLog-Batching +7. **Neue Port-Typen:** `UdmDocument`, `UdmNodeList`, `ConsolidateResult` +8. **Agent-Tools:** Bestehende `browseContainer`/`readContentObjects` um UDM-Traversierung erweitern +9. **AI-Kennzeichnung auf Nodes:** Jeder Node im Editor zeigt visuell, ob er AI nutzt (`meta.usesAi`) — Kostentransparenz und schnelle Übersicht + +### Explizit NICHT + +- Neue Dateiformate (Markdown, LaTeX, etc.) — kommt separat +- Visuelles Sub-Graph-Grouping (Compound-Nodes) im Editor — wird mit impliziter Body-Erkennung gelöst +- Breaking Change an `ContentPart`-API — Bridge-Layer garantiert Kompatibilität + +--- + +## Betroffene Module + +### Gateway + +| Modul | Änderung | +|-------|---------| +| `datamodels/datamodelUdm.py` | **Neue Datei**: Pydantic-Klassen `UdmDocument`, `UdmStructuralNode`, `UdmContentBlock`, `UdmArchive`, `UdmPosition`, `UdmMetadata`. Bridge-Funktionen. `UdmContentBlock.raw` optional mit `fileRef`-Alternative für Lazy-Loading | +| `datamodels/datamodelExtraction.py` | `ExtractionOptions.outputFormat` Feld (`"parts"` / `"udm"` / `"both"`) | +| `serviceExtraction/subRegistry.py` | `Extractor`-Interface erweitern: `extractToUdm()`. **ExtractorRegistry als Singleton cachen** (heute: neue Instanz pro Datei im ZIP) | +| `serviceExtraction/extractors/extractorPdf.py` | UDM-Output pro Seite. **Fix `buf.getvalue()`** → direkt `BytesIO` an fitz übergeben (halber Memory) | +| `serviceExtraction/extractors/extractorDocx.py` | UDM-Output pro Section (Heading-basiert) | +| `serviceExtraction/extractors/extractorPptx.py` | UDM-Output pro Slide | +| `serviceExtraction/extractors/extractorXlsx.py` | UDM-Output pro Sheet | +| `serviceExtraction/extractors/extractorHtml.py` | UDM-Output pro semantischem Bereich | +| `serviceExtraction/extractors/extractorContainer.py` | **Lazy-Modus**: ZIP-Inhaltsverzeichnis liefern statt alle Dateien extrahieren. Registry-Singleton statt `new ExtractorRegistry()` pro Datei | +| `serviceExtraction/mainServiceExtraction.py` | `extractContent()` mit UDM-Option. **Streaming-Modus** für grosse Archive | +| `features/graphicalEditor/nodeDefinitions/context.py` | **Neue Datei**: Node `context.extractContent` | +| `features/graphicalEditor/nodeDefinitions/data.py` | Neuer Node: `data.consolidate` (deterministisch) | +| `features/graphicalEditor/nodeDefinitions/ai.py` | Neuer Node: `ai.consolidate` (AI-gestützt) | +| `features/graphicalEditor/nodeDefinitions/flow.py` | `flow.loop`: Parameter `level` (UDM-Ebene) + `concurrency` (parallele Iterationen). `flow.merge`: dynamische Input-Anzahl | +| `features/graphicalEditor/nodeDefinitions/__init__.py` | `CONTEXT_NODES` in `STATIC_NODE_TYPES` aufnehmen | +| `features/graphicalEditor/portTypes.py` | Neue Port-Typen: `UdmDocument`, `UdmNodeList`, `ConsolidateResult`. Input-Extraktoren dazu | +| `workflows/automation2/executors/flowExecutor.py` | Loop: UDM-Array-Auflösung, Concurrency-Support | +| `workflows/automation2/executors/dataExecutor.py` | `data.consolidate`-Logik (deterministisch). Filter: UDM-Content-Type-Presets | +| `workflows/automation2/executionEngine.py` (`_getExecutor`) | Branch `context.*` hinzufügen → `ActionNodeExecutor` | +| `workflows/automation2/executionEngine.py` | **Loop-Concurrency** (N Items parallel), **StepLog-Batching** (bei >100 Iterationen), **Streaming-Aggregate** (periodisch flushen) | +| `workflows/methods/methodContext/actions/extractContent.py` | UDM-Output-Option, Lazy-Modus für Archive | +| `workflows/methods/methodAi/actions/consolidate.py` | **Neue Datei**: Action `consolidate` für `ai.consolidate` (LLM-Call: summarize, classify, semantic merge) | +| `serviceAgent/coreTools/_documentTools.py` | UDM-Tools: `walkUdmBlocks`, `filterUdmByType`, `getUdmStructure` | + +### Frontend + +| Modul | Änderung | +|-------|---------| +| `FlowEditor/nodes/context/ExtractContentNodeConfig.tsx` | **Neue Datei**: Config-UI für `context.extractContent` | +| `FlowEditor/nodes/loop/LoopNodeConfig.tsx` | UDM-Level-Selektor + Concurrency-Slider | +| `FlowEditor/nodes/shared/LoopItemsSelect.tsx` | UDM-Structural-Level als Quelle | +| `FlowEditor/nodes/shared/types.ts` | Neue Node-Config-Types | +| `FlowEditor/FlowCanvas.tsx` | Visuelle Loop-Body-Markierung (farbiger Hintergrund). **AI-Badge** auf Nodes die AI nutzen | +| `FlowEditor/NodeSidebar.tsx` | Neue Nodes in Palette (`context.extractContent`, `data.consolidate`, `ai.consolidate`). AI-Badge in Palette | +| `FlowEditor/nodes/shared/AiBadge.tsx` | **Neue Datei**: Wiederverwendbare AI-Badge-Komponente (`usesAi: boolean`) | +| `api/workflowApi.ts` | NodeType-Erweiterung | + +### DB-Migration + +Nein — UDM-Daten fliessen als JSON durch Workflow-Context/nodeOutputs, keine neue DB-Tabelle nötig. + +--- + +## Architektur-Design + +### A) UDM-Datenmodell (Gateway) + +```python +class UdmMetadata(BaseModel): + title: Optional[str] = None + author: Optional[str] = None + createdAt: Optional[str] = None + modifiedAt: Optional[str] = None + sourcePath: str = "" + tags: List[str] = Field(default_factory=list) + custom: Dict[str, Any] = Field(default_factory=dict) + +class UdmBoundingBox(BaseModel): + x: float; y: float; width: float; height: float + unit: Literal["px", "pt", "mm"] = "pt" + +class UdmPosition(BaseModel): + index: int + page: Optional[int] = None + row: Optional[int] = None + col: Optional[int] = None + bbox: Optional[UdmBoundingBox] = None + +class UdmContentBlock(BaseModel): + id: str + contentType: Literal["text", "image", "table", "code", "media", "link", "formula"] + raw: str = "" + fileRef: Optional[str] = None # Lazy-Loading: Referenz statt inline Base64 + mimeType: Optional[str] = None + language: Optional[str] = None + attributes: Dict[str, Any] = Field(default_factory=dict) + position: UdmPosition = Field(default_factory=lambda: UdmPosition(index=0)) + metadata: UdmMetadata = Field(default_factory=UdmMetadata) + +class UdmStructuralNode(BaseModel): + id: str + role: Literal["page", "section", "slide", "sheet"] + index: int + label: Optional[str] = None + metadata: UdmMetadata = Field(default_factory=UdmMetadata) + children: List[UdmContentBlock] = Field(default_factory=list) + +class UdmDocument(BaseModel): + id: str + role: Literal["document"] = "document" + sourceType: Literal["pdf", "docx", "pptx", "xlsx", "html"] + sourcePath: str = "" + metadata: UdmMetadata = Field(default_factory=UdmMetadata) + children: List[UdmStructuralNode] = Field(default_factory=list) + +class UdmArchive(BaseModel): + id: str + role: Literal["archive"] = "archive" + sourceType: Literal["zip", "tar", "gz"] + sourcePath: str = "" + metadata: UdmMetadata = Field(default_factory=UdmMetadata) + children: List[Union[UdmArchive, UdmDocument]] = Field(default_factory=list) +``` + +Schlüssel-Erweiterung für High-Volume: `UdmContentBlock.fileRef` — statt Base64-Daten inline zu speichern, kann eine Datei-Referenz (z.B. `fileId` oder temp-Pfad) hinterlegt werden. Der Inhalt wird erst on-demand geladen, wenn ein downstream Node ihn braucht. Bei 10k PDFs spart das mehrere GB RAM. + +### B) Bridge: ContentPart ↔ UDM + +```python +def _contentPartsToUdm(extracted: ContentExtracted, sourceType: str, sourcePath: str) -> UdmDocument: + """Konvertiert flache ContentPart-Liste in UDM-Baum. + Groupiert nach parentId oder typeGroup zu StructuralNodes.""" + +def _udmToContentParts(document: UdmDocument) -> ContentExtracted: + """Konvertiert UDM-Baum zurück in flache ContentPart-Liste. + Für Rückwärtskompatibilität.""" +``` + +### C) Neuer Node: `context.extractContent` (Strukturextraktion OHNE AI) + +**Problem heute:** `context.extractContent` existiert nur als Method-Action für Workspace/Agent. Im Graphical Editor gibt es keinen Node, um ein Dokument rein strukturell zu zerlegen. + +**Lösung:** Ein neuer Node `context.extractContent` in der Kategorie `context`: + +1. Dokument(e) entgegennehmen (Input: `DocumentList`) +2. Reine Extraktion (kein AI-Call, nur Parser) +3. UDM-Struktur als Output +4. Downstream gezielt nutzbar: Loop → Filter → AI nur für bestimmte Blöcke + +#### Node-Definition + +```python +{ + "id": "context.extractContent", + "category": "context", + "label": t("Inhalt extrahieren"), + "description": t("Dokumentstruktur extrahieren ohne KI (Seiten, Abschnitte, Bilder, Tabellen)"), + "parameters": [ + {"name": "outputDetail", "type": "string", "required": False, "frontendType": "select", + "frontendOptions": {"options": ["full", "structure", "references"]}, + "description": t("Detailgrad"), "default": "full"}, + {"name": "includeImages", "type": "boolean", "required": False, "frontendType": "checkbox", + "description": t("Bilder extrahieren"), "default": True}, + {"name": "includeTables", "type": "boolean", "required": False, "frontendType": "checkbox", + "description": t("Tabellen extrahieren"), "default": True}, + ], + "inputs": 1, + "outputs": 1, + "inputPorts": {0: {"accepts": ["DocumentList", "Transit"]}}, + "outputPorts": {0: {"schema": "UdmDocument"}}, + "meta": {"icon": "mdi-file-tree-outline", "color": "#00897B"}, + "_method": "context", + "_action": "extractContent", +} +``` + +#### Parameter `outputDetail` + +| Wert | Beschreibung | Use Case | +|------|-------------|----------| +| `full` | Volle UDM-Struktur inkl. Rohdaten (Text, Base64-Bilder, JSON-Tabellen) | Standard — alles downstream verfügbar. Bis ~100 Dokumente. | +| `structure` | Nur Baum-Skelett: Document → StructuralNodes → ContentBlock-Metadaten (ohne `raw`) | Schnelle Vorschau, Routing-Entscheidungen | +| `references` | Datei-Referenzen statt Inline-Daten (`fileRef` statt `raw`). Inhalt wird on-demand im Loop geladen | **High-Volume**: 1000+ Dokumente. Spart RAM. | + +### D) ForEach/Consolidate Workflow-Pattern + +#### Einfacher Fall: 1 PDF, pro Seite verarbeiten + +``` +[Upload] → [Extract] → [Loop (pro Seite)] → [AI] → [Aggregate] → [Consolidate] +``` + +#### Parallele Pfade im Loop-Body: Bild + Text pro Seite + +``` +[Upload] → [Extract] → [Loop (pro Seite)] + ├→ [Filter: Bilder] → [AI Vision] ──┐ + └→ [Filter: Text] → [AI Text] ──┤ + ↓ + [Merge (pro Seite)] + ↓ + [Aggregate] + [Consolidate (alle Seiten → Tabelle)] ←──┘ +``` + +**Warum das heute schon funktioniert:** +- Fan-out: Ein Output-Port kann mehrere Connections haben (Target-Inputs sind limitiert auf 1, Source-Outputs nicht) +- `getLoopBodyNodeIds()` (BFS) findet alle Nodes in beiden Pfaden +- `topoSort` ordnet: Filter + AI vor Merge (weil Merge von beiden abhängt) +- Body-Nodes werden sequentiell in Topo-Sort-Reihenfolge abgearbeitet → Merge hat beide Inputs + +**Umgesetzt (Plan):** +- `flow.merge`: dynamische Input-Anzahl (2–5 via Parameter `inputCount`) +- `data.filter`: UDM-Content-Type-Presets (Filter auf `contentType`, `structuralNode.index`, `attributes.*`) + +#### High-Volume-Fall: ZIP mit 10.000 PDFs + +``` +[Upload ZIP] → [Extract (references)] → [Loop (pro Dokument, concurrency: 10)] + ↓ + [Lazy-Extract (1 PDF, Seite 1)] + ↓ + [Filter: Bild Seite 1] + ↓ + [AI Vision → CSV-Zeile] + ↓ + [Aggregate (CSV-Zeilen)] + [Consolidate (mode: table → grosses CSV)] ←──┘ +``` + +**Schlüssel:** `outputDetail: "references"` — der erste Extract liefert nur eine leichtgewichtige Liste von 10k Datei-Referenzen (~10 KB statt ~4 GB). Pro Loop-Iteration wird nur 1 PDF on-demand geladen, verarbeitet und wieder freigegeben. + +#### High-Volume: ZIP mit Fan-out + Merge pro Dokument + +Dasselbe Muster wie bei einem einzelnen PDF (zwei parallele Body-Pfade + Merge pro Iteration), angewendet auf **pro Archiv-Eintrag** statt pro Seite: + +``` +[Upload ZIP] → [Extract (references)] → [Loop (pro Dokument, concurrency: N)] + ├→ [Lazy-Extract / Seite 1] → [AI Vision] ──┐ + └→ [Filter: Text] → [AI Text] ────────────┤ + [Merge] + ↓ + [Aggregate] +[Consolidate] ←──────────────────────────────────────────────────────────────────────────┘ +``` + +Pro Iteration gilt: Fan-out und Topo-Sort im Loop-Body wie oben; der erste Extract liefert nur Referenzen, sodass nicht alle PDFs gleichzeitig im RAM liegen. + +### E) Flow.loop Erweiterungen + +```python +# Neuer Parameter: UDM-Level +{ + "name": "level", + "type": "string", + "required": False, + "frontendType": "select", + "frontendOptions": {"options": ["auto", "documents", "structuralNodes", "contentBlocks"]}, + "description": t("UDM-Iterationsebene"), + "default": "auto", +} + +# Neuer Parameter: Parallele Iterationen +{ + "name": "concurrency", + "type": "number", + "required": False, + "frontendType": "number", + "frontendOptions": {"min": 1, "max": 20}, + "description": t("Parallele Iterationen"), + "default": 1, +} +``` + +- `level: auto` → `items`-Pfad wie bisher +- `level: documents` → `archive.children` (Documents) +- `level: structuralNodes` → `document.children` (Pages/Sections/Slides/Sheets) +- `level: contentBlocks` → `structuralNode.children` (Text/Image/Table/...) +- `concurrency: 1` → sequentiell wie heute +- `concurrency: 10` → 10 Iterationen gleichzeitig via `asyncio.Semaphore` + +### F) flow.merge Erweiterung + +```python +# Neuer Parameter: Dynamische Input-Anzahl +{ + "name": "inputCount", + "type": "number", + "required": False, + "frontendType": "number", + "frontendOptions": {"min": 2, "max": 5}, + "description": t("Anzahl Eingänge"), + "default": 2, +} +``` + +`inputs` und `inputPorts` werden dynamisch basierend auf `inputCount` generiert. Backend: `nodeRegistry.py` muss dynamische Input-Ports unterstützen. + +### G) High-Volume Engine-Optimierungen + +#### Problem-Analyse (10.000 Iterationen) + +| Engpass | Heute | Lösung | +|---------|-------|--------| +| **Memory: Base64-Bilder** | Alle Bilder als Strings in `nodeOutputs` | `fileRef` statt inline `raw`. On-Demand-Loading | +| **Memory: items-Array** | Gesamte `items`-Liste im Loop-Node-Output | Bei `references`-Modus: nur IDs, ~100 Bytes pro Item | +| **Memory: Aggregate** | `_aggregateAccumulators` wächst unbegrenzt in-Memory | **Streaming-Aggregate**: bei >1000 Items periodisch in temp-Storage flushen | +| **DB: AutoStepLog** | Insert + Update pro Body-Node pro Iteration | **StepLog-Batching**: bei >100 Iterationen nur jede N-te loggen + Summary am Ende | +| **DB: updateRun** | Am Ende: gesamte nodeOutputs als JSONB | Aggregate-Daten als File-Referenz statt inline | +| **CPU: ExtractorRegistry** | Neue Instanz pro Datei im ZIP (`_addFilePart`) | **Singleton-Pattern**: einmal erstellen, wiederverwenden | +| **CPU: PDF-Memory** | `buf.getvalue()` kopiert gesamtes PDF für PyMuPDF | Direkt `BytesIO` übergeben, keine Kopie | +| **Laufzeit: Sequentiell** | 10k × 3s = 8.3h | `concurrency: 10` → ~50 Min | +| **SSE: StepEvents** | Event pro Step-Änderung | Bei High-Volume: nur Progress-Summary (z.B. "Iteration 5000/10000") | + +#### StepLog-Batching (executionEngine.py) + +```python +# Heuristik: ab 100 Iterationen → Batch-Modus +if len(items) > STEPLOG_BATCH_THRESHOLD: + stepLogMode = "batch" # nur jede 100. Iteration + Fehler + Summary +else: + stepLogMode = "full" # wie heute: jeder Step einzeln +``` + +#### Loop-Concurrency (executionEngine.py) + +```python +concurrency = (node.get("parameters") or {}).get("concurrency", 1) +semaphore = asyncio.Semaphore(concurrency) + +async def _processIteration(idx, item): + async with semaphore: + nodeOutputs_local = dict(nodeOutputs) # lokale Kopie pro Iteration + nodeOutputs_local[nodeId] = {"currentItem": item, "currentIndex": idx, ...} + for body_node in body_ordered: + ... + +tasks = [_processIteration(idx, item) for idx, item in enumerate(items)] +results = await asyncio.gather(*tasks) +``` + +Achtung: Bei `concurrency > 1` braucht jede Iteration **eigene** `nodeOutputs`, da Body-Nodes sich sonst gegenseitig überschreiben. Aggregate-Accumulation muss thread-safe sein (Lock oder Queue). + +#### Streaming-Aggregate + +```python +AGGREGATE_FLUSH_THRESHOLD = 1000 + +# Im Loop-Body: +_aggregateAccumulators[bnid].extend(accItems) +if len(_aggregateAccumulators[bnid]) >= AGGREGATE_FLUSH_THRESHOLD: + _flushAggregateToTemp(bnid, _aggregateAccumulators[bnid]) + _aggregateAccumulators[bnid] = [] +``` + +Temp-Storage: In-Memory-Buffer oder temp-File. Am Ende: alle Chunks zusammenführen. + +### H) AI-Kennzeichnung auf Nodes im Editor + +Jeder Node im Editor soll **sofort sichtbar** machen, ob er AI nutzt oder deterministisch arbeitet. Dies ist wichtig für Kostentransparenz und Workflow-Design. + +#### Umsetzung + +**Backend:** Jede Node-Definition bekommt ein neues Feld `meta.usesAi` (Boolean): + +```python +# Beispiel: ai.prompt → AI +"meta": {"icon": "mdi-robot", "color": "#9C27B0", "usesAi": True} + +# Beispiel: data.filter → kein AI +"meta": {"icon": "mdi-filter-outline", "color": "#607D8B", "usesAi": False} +``` + +Durch den Split von Nodes mit gemischtem AI-Verhalten (z.B. `data.consolidate` vs `ai.consolidate`) ist jeder Node **eindeutig** — kein `"optional"` nötig. + +**Frontend:** Im `FlowCanvas.tsx` (Zeile ~846-852, Node-Rendering) wird ein kleines Badge/Indicator angezeigt: + +- `usesAi: true` → AI-Badge (z.B. kleines "AI"-Label oder Blitz-Icon oben rechts am Node) +- `usesAi: false` oder nicht gesetzt → kein Badge + +Gleiche Kennzeichnung in der **NodeSidebar** (Palette), damit der User schon beim Drag&Drop sieht, welche Nodes AI nutzen. + +#### Zuordnung aller bestehenden Nodes + +| Node | `usesAi` | Begründung | +|------|----------|------------| +| `trigger.*` | `false` | Reine Auslöser | +| `input.*` | `false` | Formulare, manuelle Eingabe | +| `flow.ifElse` | `false` | Bedingungslogik | +| `flow.switch` | `false` | Bedingungslogik | +| `flow.loop` | `false` | Iteration | +| `flow.merge` | `false` | Zusammenführung | +| `data.aggregate` | `false` | Sammeln | +| `data.transform` | `false` | Feld-Mapping | +| `data.filter` | `false` | Filterlogik | +| `data.consolidate` (NEU) | `false` | Deterministisch: merge, concat, table, CSV-Join | +| `ai.consolidate` (NEU) | `true` | AI-gestützt: summarize, classify, semantic merge | +| `context.extractContent` (NEU) | `false` | Reine Parser-Arbeit | +| `ai.prompt` | `true` | LLM-Call | +| `ai.webResearch` | `true` | Web-Suche + LLM | +| `ai.summarizeDocument` | `true` | LLM-Zusammenfassung | +| `ai.translateDocument` | `true` | LLM-Übersetzung | +| `ai.convertDocument` | `true` | LLM-Konvertierung | +| `ai.generateDocument` | `true` | LLM-Generierung | +| `ai.generateCode` | `true` | LLM-Codegenerierung | +| `email.*` | `false` | E-Mail-Operationen | +| `sharepoint.*` | `false` | SharePoint-Operationen | +| `clickup.*` | `false` | ClickUp-Operationen | +| `file.create` | `false` | Datei-Erstellung | +| `trustee.refreshAccountingData` | `false` | Datenimport aus externem System | +| `trustee.extractFromFiles` | `true` | AI-Extraktion (Prompt-basiert, Dokumenttyp-Erkennung) | +| `trustee.processDocuments` | `false` | TrusteeDocument/Position aus Extraktionsergebnis erstellen | +| `trustee.syncToAccounting` | `false` | Übertragung in Buchhaltung | + +--- + +## Entscheidungen + +| Datum | Entscheidung | Begründung | +|-------|-------------|------------| +| 2026-04-16 | `context.extractContent` als eigener Node im Editor | Heute fehlt komplett. Fundament für gezielten AI-Einsatz. Neue Kategorie `context`. | +| 2026-04-16 | Extraktion ist KEIN AI-Call | Reine Parser-Arbeit. AI-Kosten erst bei explizitem AI-Node. Kostenfreie Vorverarbeitung. | +| 2026-04-16 | UDM als In-Memory-Format, keine DB-Tabelle | UDM fliesst als JSON durch nodeOutputs. Vermeidet Migration. | +| 2026-04-16 | Bridge ContentPart ↔ UDM statt Breaking Change | Alle bestehenden Konsumenten bleiben funktional. | +| 2026-04-16 | Kein Compound-Node / Sub-Graph | Zu hoher Aufwand. Bestehende Body-Erkennung via BFS genügt. | +| 2026-04-16 | Consolidate als Split in `data.consolidate` + `ai.consolidate` | `data.*` = deterministisch, `ai.*` = AI-gestützt. Kein `"optional"` Badge nötig — jeder Node ist eindeutig. | +| 2026-04-16 | `level`-Parameter am Loop | Weniger Nodes in der Palette, einfachere UX. | +| 2026-04-16 | Fan-out im Loop-Body nutzt bestehendes Modell | Engine unterstützt es bereits: Topo-Sort + sequentielle Body-Abarbeitung garantieren korrekte Reihenfolge. Kein Engine-Umbau nötig. | +| 2026-04-16 | `outputDetail: "references"` für High-Volume | 10k PDFs als Referenzliste (~10 KB) statt vollständig extrahiert (~4 GB). On-Demand-Loading pro Iteration. | +| 2026-04-16 | Loop-Concurrency als opt-in Parameter | Default bleibt `1` (sequentiell, deterministisch). Power-User setzen höher für Durchsatz. | +| 2026-04-16 | StepLog-Batching ab Schwellwert | 50k DB-Inserts bei 10k Iterationen ist nicht tragbar. Batch-Modus loggt nur Summary + Fehler. | +| 2026-04-16 | AI-Badge auf allen Nodes im Editor | Kostentransparenz. User sieht sofort, welche Nodes AI-Credits verbrauchen. `meta.usesAi` als Boolean. | +| 2026-04-16 | Nodes mit gemischtem AI-Verhalten splitten | `data.consolidate` (deterministisch) + `ai.consolidate` (AI). Kein "optional"-Badge nötig — jeder Node ist eindeutig `true` oder `false`. | + +--- + +## Umsetzungs-Checkliste + +### Phase 1: UDM-Datenmodell & Bridge (Gateway) + +> **Cursor-Empfehlung:** Composer (Fast) reicht. Reine Pydantic-Modelle und Utility-Funktionen — klar definiert, wenig Kontext nötig. + +- [x] Pydantic-Modelle in `datamodels/datamodelUdm.py` (neue Datei) +- [x] `UdmContentBlock.fileRef` Feld für Lazy-Loading +- [x] Bridge-Funktionen `_contentPartsToUdm()` / `_udmToContentParts()` +- [x] Unit-Tests für Modelle und Bridge +- [x] `ExtractionOptions.outputFormat` Feld (`"parts"` | `"udm"` | `"both"`) + +### Phase 2: Extractor-Adapter (Gateway) + +> **Cursor-Empfehlung:** Composer (Fast) reicht. Pro Extractor ein isoliertes File mit klarem Pattern. Memory-Fixes (`buf.getvalue()`, Registry-Singleton) sind punktuelle Änderungen. + +- [x] `extractorPdf.py` → UDM-Output + Fix `buf.getvalue()` (Memory) +- [x] `extractorDocx.py` → UDM-Output +- [x] `extractorPptx.py` → UDM-Output +- [x] `extractorXlsx.py` → UDM-Output +- [x] `extractorHtml.py` → UDM-Output +- [x] `extractorContainer.py` → Lazy-Modus (Inhaltsverzeichnis statt alles extrahieren) +- [x] `extractorContainer.py` → `ExtractorRegistry` Singleton statt `new` pro Datei +- [x] `mainServiceExtraction.py` → `extractContent()` mit UDM-Option +- [x] Integration-Tests pro Format + +### Phase 3: Extract-Node — Strukturextraktion ohne AI (Gateway + Frontend) + +> **Cursor-Empfehlung:** **Opus 4.6 empfohlen.** Neue Datei + Integration in mehrere bestehende Systeme (NodeDefinitions, PortTypes, Executor-Mapping, Frontend-Komponente). Erfordert Verständnis der gesamten Node-Architektur über ~6 Dateien hinweg. + +- [x] `nodeDefinitions/context.py` → Node `context.extractContent` +- [x] `nodeDefinitions/__init__.py` → `CONTEXT_NODES` in `STATIC_NODE_TYPES` +- [x] `UdmDocument` Port-Typ in `portTypes.py` +- [x] Input-Extractor `_extractUdmDocument()` in `portTypes.py` +- [x] `executionEngine.py` → `_getExecutor()`: Branch `context.*` → `ActionNodeExecutor` hinzufügen (heute nur: `ai.`, `email.`, `sharepoint.`, `clickup.`, `file.`, `trustee.`) +- [x] `ActionNodeExecutor` → `context.extractContent` via `_method`/`_action` Mapping (nutzt bestehendes `MethodContext.extractContent`) +- [x] `extractContent.py` → UDM-Output-Modus + `outputDetail: "references"` Modus +- [x] Frontend: `ExtractContentNodeConfig.tsx` +- [x] Frontend: Node in Sidebar-Palette unter Kategorie "Kontext" + +### Phase 4: Workflow Nodes — ForEach, Merge & Consolidate (Gateway + Frontend) + +> **Cursor-Empfehlung:** **Opus 4.6 empfohlen.** Komplexeste Phase — berührt Execution-Engine, Port-System, Flow-Executor, Data-Executor und Frontend gleichzeitig. Concurrency-Design erfordert tiefes Verständnis der bestehenden Loop-Logik und Race-Conditions. + +- [x] `data.consolidate` Node-Definition (`nodeDefinitions/data.py`) — deterministisch: merge, concat, table, CSV-Join +- [x] `ai.consolidate` Node-Definition (`nodeDefinitions/ai.py`) — AI-gestützt: summarize, classify, semantic merge +- [x] `ConsolidateResult` Port-Typ (`portTypes.py`) +- [x] `DataExecutor` → Consolidate-Logik (`dataExecutor.py`) +- [x] `methodAi/actions/consolidate.py` → neue Action-Datei (LLM-Call mit aggregierten Daten) +- [x] `methodAi/methodAi.py` → Action `consolidate` registrieren +- [x] `ai.consolidate` wird über bestehenden `ActionNodeExecutor` geroutet — kein eigener Executor nötig +- [x] `data.filter` → UDM-Content-Type-Presets (Filter auf `contentType`, `index`, `attributes`) +- [x] `flow.loop` → `level`-Parameter (`nodeDefinitions/flow.py`) +- [x] `flow.loop` → `concurrency`-Parameter (`nodeDefinitions/flow.py`) +- [x] `flow.merge` → dynamische Input-Anzahl `inputCount` (2-5) +- [x] `FlowExecutor._loop()` → UDM-Level-Auflösung (`flowExecutor.py`) +- [x] `UdmNodeList` Port-Typ (`portTypes.py`) +- [x] Frontend: `DataConsolidateNodeConfig.tsx` (deterministisch) +- [x] Frontend: `AiConsolidateNodeConfig.tsx` (AI-gestützt) +- [x] Frontend: Loop-NodeConfig → UDM-Level-Selector + Concurrency-Slider +- [x] Frontend: Merge-NodeConfig → Input-Count-Selector +- [x] Frontend: Visuelle Loop-Body-Markierung im Canvas + +### Phase 5: High-Volume Engine-Optimierungen (Gateway) + +> **Cursor-Empfehlung:** **Opus 4.6 empfohlen.** Async-Concurrency, Thread-Safety, Streaming-Aggregates — subtile Bugs möglich. Load-Test-Design braucht Überblick über das gesamte System. + +- [x] `executionEngine.py` → Loop-Concurrency via `asyncio.Semaphore` mit isolierten `nodeOutputs` pro Iteration +- [x] `executionEngine.py` → StepLog-Batching (Schwellwert 100 Iterationen: nur Summary + Fehler loggen) +- [x] `executionEngine.py` → Streaming-Aggregate (Flush-Threshold, temp-Storage) +- [x] `executionEngine.py` → Progress-SSE bei High-Volume: Summary statt pro-Step-Events +- [x] `extractorContainer.py` → `ExtractorRegistry` Singleton (Performance-Fix) +- [x] `extractorPdf.py` → `BytesIO` direkt an fitz übergeben statt `getvalue()` (Memory-Fix) +- [x] Lazy-Content-Loader: Utility-Funktion die `fileRef` → Bytes auflöst, on-demand im Loop +- [x] Load-Test: 1000 PDFs aus ZIP → Extract → AI Vision → CSV → Consolidate + +### Phase 6: AI-Badge — Visuelle Kennzeichnung im Editor (Gateway + Frontend) + +> **Cursor-Empfehlung:** Composer (Fast) reicht. Kleines `meta.usesAi`-Feld pro Node-Definition (Backend) + Badge-Komponente im Canvas (Frontend). Klar abgegrenzte Änderung. + +- [x] Alle bestehenden Node-Definitionen: `meta.usesAi` Feld ergänzen (`true` / `false`) +- [x] `FlowCanvas.tsx` → AI-Badge-Rendering: kleines "AI"-Label / Blitz-Icon oben rechts am Node wenn `usesAi: true` +- [x] `NodeSidebar.tsx` → AI-Kennzeichnung in der Palette (Badge neben Node-Name) +- [x] Tooltip auf Badge: "Dieser Schritt nutzt AI und verbraucht Credits" +- [x] CSS/Styling: Badge-Design konsistent mit bestehendem Design-System + +### Phase 7: Agent-Tools & Integration (Gateway) + +> **Cursor-Empfehlung:** Composer (Fast) reicht für die Tool-Funktionen. **Opus 4.6 für E2E-Tests** — die Tests müssen viele Module korrekt zusammenspielen lassen. + +- [x] `_documentTools.py` → UDM-Tools (`walkUdmBlocks`, `filterUdmByType`, `getUdmStructure`) +- [x] E2E-Test: PDF → Extract (UDM) → Loop (pro Seite) → AI → Aggregate → Consolidate +- [x] E2E-Test: PDF → Extract → Filter (nur Tabellen) → AI → kein Loop +- [x] E2E-Test: ZIP → Extract (references) → Loop (Fan-out) → Vision + Text → Merge → Aggregate → Consolidate + +### Phase 8: Dokumentation & Abschluss + +> **Cursor-Empfehlung:** Composer (Fast) reicht. Reine Dokumentation und Verifikation. + +- [x] RBAC / Permissions: Keine Änderung nötig +- [x] Neutralisierung: ContentBlock.raw mit sensiblen Daten → Bridge zu ContentPart +- [x] Navigation / Routing: Keine Änderung +- [x] Billing-Impact: Loop-Iterationen zählen als einzelne AI-Calls → bestehende Logik greift + +--- + +## Akzeptanzkriterien + +| # | Kriterium (Given-When-Then) | Prio | +|---|---------------------------|------| +| 1 | Given ein PDF mit 5 Seiten, When `context.extractContent`-Node ausgeführt, Then UdmDocument mit 5 StructuralNodes (role=page) — **kein AI-Call**, nur Parsing | must | +| 2 | Given der Extract-Node-Output (UDM), When mit `data.filter` auf `contentType=="table"` gefiltert, Then nur Tabellen-ContentBlocks im Output | must | +| 3 | Given ein DOCX mit 3 Sections, When UDM-Extraktion, Then 3 StructuralNodes mit role=section und korrekten Labels | must | +| 4 | Given ein UDM-Dokument, When `_udmToContentParts()`, Then identische ContentPart-Liste wie bei direkter Extraktion (Bridge) | must | +| 5 | Given ein Workflow mit Loop über `document.children`, When ausgeführt, Then Body-Nodes pro StructuralNode einmal durchlaufen | must | +| 6 | Given ForEach → AI → Aggregate → Consolidate, When 3 Seiten verarbeitet, Then Consolidate erhält 3 Ergebnisse und erzeugt Zusammenfassung | must | +| 7 | Given Loop mit Fan-out zu 2 AI-Nodes + Merge, When pro Seite ausgeführt, Then Merge erhält beide AI-Ergebnisse pro Iteration | must | +| 8 | Given `outputDetail=references` auf ZIP mit 1000 PDFs, When Extract ausgeführt, Then Referenzliste mit 1000 Einträgen, Memory < 100 MB | must | +| 9 | Given Loop mit `concurrency: 5` über 100 Items, When ausgeführt, Then ~5x schneller als `concurrency: 1` | should | +| 10 | Given Loop mit 10.000 Iterationen, When ausgeführt, Then weniger als 1000 AutoStepLog-Einträge (Batching) | should | +| 11 | Given `context.extractContent` mit `outputDetail=structure`, When ausgeführt, Then nur Skelett ohne `raw`-Daten | should | +| 12 | Given Loop-Workflow im Editor, When User den Graph betrachtet, Then Loop-Body-Nodes visuell als zusammengehörig erkennbar | should | +| 13 | Given `data.consolidate` mit mode=table, When 100 CSV-Zeilen als Input, Then ein zusammengefügtes CSV als Output | should | +| 14 | Given ZIP mit 10.000 PDFs, When E2E-Workflow (Extract refs → Loop → AI Vision Seite 1 → CSV), Then erfolgreich in < 24h (mit concurrency: 10) | nice | +| 15 | Given ZIP mit 3 PDFs, When UDM-Extraktion, Then UdmArchive mit 3 UdmDocuments | nice | +| 16 | Given ein Workflow mit `ai.prompt` und `data.filter` Nodes, When User den Graph betrachtet, Then AI-Badge nur auf `ai.prompt` sichtbar, nicht auf `data.filter` | must | +| 17 | Given `data.consolidate` und `ai.consolidate` nebeneinander im Editor, When User vergleicht, Then nur `ai.consolidate` hat AI-Badge, `data.consolidate` nicht | must | + +--- + +## Testplan + +*Stand beim Archivieren: Kerntests liegen in den unter „Abschlussbericht“ genannten Dateien. Die ursprünglich geplanten Einzelpfade (T2, T3, T6–T17) können bei Bedarf als separates Backlog ergänzt werden.* + +| ID | AC | Art | Automatisiert | Repo-Pfad | Status | +|----|----|-----|--------------|-----------|--------| +| T1 | 1 | unit | ja | gateway/tests/unit/datamodels/test_udm_models.py | done | +| T2 | 1 | integration | ja | gateway/tests/integration/extraction/test_extract_udm_pipeline.py (statt urspr. `test_extract_node.py`) | done | +| T3 | 2 | integration | ja | — (Backlog: dedizierter Filter-Flow) | backlog | +| T4 | 3 | unit | ja | gateway/tests/unit/datamodels/test_udm_models.py | done | +| T5 | 4 | unit | ja | gateway/tests/unit/datamodels/test_udm_bridge.py | done | +| T6 | 1,3 | integration | ja | gateway/tests/integration/extraction/test_extract_udm_pipeline.py | done | +| T7 | 5 | integration | ja | — (Backlog) | backlog | +| T8 | 6 | integration | ja | gateway/tests/integration/workflows/test_execute_graph_loop_aggregate_consolidate.py | done | +| T9 | 7 | integration | ja | — (Backlog) | backlog | +| T10 | 8 | integration | ja | — (Backlog) | backlog | +| T11 | 9 | integration | ja | — (Backlog) | backlog | +| T12 | 10 | unit | ja | — (Backlog) | backlog | +| T13 | 11 | unit | ja | — (Backlog) | backlog | +| T14 | 12 | manual | nein | — | backlog | +| T15 | 13 | integration | ja | — (Backlog) | backlog | +| T16 | 14 | load | nein | — (manueller Load-Test) | backlog | +| T17 | 15 | integration | ja | — (Backlog) | backlog | +| T18 | 16 | unit | ja | gateway/tests/unit/nodeDefinitions/test_usesai_flag.py | done | +| T19 | 17 | manual | nein | — (visueller Check im Editor) | backlog | + +--- + +## Links + +- Idee: `c-work/0-ideas/unified-document-model.md` +- Workflow-Engine Referenz: `b-reference/gateway/workflow.md` +- AI-Agent Referenz: `b-reference/gateway/ai-agent.md` +- Port-System Referenz: `c-work/4-done/2026-04-generic-graph-editor.md` + +--- + +## Abschluss + +- [x] b-reference/ aktualisiert: `gateway/workflow.md` (neue Nodes, UDM-Loop-Pattern, Concurrency), `gateway/ai-agent.md` (neue UDM-Tools) +- [x] TOPICS.md aktualisiert (neues Thema: UDM) +- [x] Dieses Dokument → `wiki/z-archive/2026-04-unified-document-model.md` archiviert diff --git a/z-archive/unified-document-model.md b/z-archive/unified-document-model.md new file mode 100644 index 0000000..a4359c9 --- /dev/null +++ b/z-archive/unified-document-model.md @@ -0,0 +1,511 @@ +# Unified Document Model (UDM) + +## Konzept & Zielsetzung + +Das Unified Document Model definiert eine **generische, formatunabhängige Baumstruktur**, in die jeder Dokumenttyp (PDF, DOCX, PPTX, XLSX, HTML, ZIP) durch einen Extractor überführt wird. Dadurch können AI-Workflows, Nodes und Tools mit einem einzigen Objektmodell arbeiten – unabhängig vom Quellformat. + +### Designprinzipien + +- **3-Ebenen-Garantie**: Jedes Dokument hat exakt drei Verschachtelungsebenen (ausgenommen ZIP als Meta-Container). +- **Einheitliche Blattknoten**: Alle atomaren Inhalte sind `ContentBlock`-Objekte mit identischer Attributstruktur. +- **Generische Traversierung**: Workflow-Nodes (Loop, Filter, Transform, Map) arbeiten formatunabhängig über dieselbe Baumstruktur. +- **Keine formatspezifischen Zwischenschichten**: Konzepte wie "Paragraph", "Row" oder "Cell" werden in den `ContentBlock` absorbiert, nicht als eigene Ebenen modelliert. + +--- + +## Architekturübersicht + +``` +┌─────────────────────────────────────────────────────┐ +│ Level 1 — Document │ +│ ┌───────────────────────────────────────────────┐ │ +│ │ Level 2 — StructuralNode │ │ +│ │ ┌─────────────────────────────────────────┐ │ │ +│ │ │ Level 3 — ContentBlock (Blattknoten) │ │ │ +│ │ └─────────────────────────────────────────┘ │ │ +│ └───────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +### Ebenen im Detail + +| Ebene | Typ | Beschreibung | +|-------|-----|-------------| +| **Level 1** | `Document` | Wurzelknoten. Repräsentiert ein einzelnes Quelldokument. | +| **Level 2** | `StructuralNode` | Strukturelle Gliederungseinheit: Seite, Abschnitt, Slide oder Sheet. | +| **Level 3** | `ContentBlock` | Atomarer Inhalt: Text, Bild, Tabelle, Code, Medien, Link oder Formel. | + +--- + +## Datenmodell + +### Document (Level 1) + +Der Wurzelknoten pro Quelldatei. + +```typescript +interface Document { + id: string; + role: "document"; + source_type: "pdf" | "docx" | "pptx" | "xlsx" | "html"; + source_path: string; + metadata: Metadata; + children: StructuralNode[]; +} +``` + +| Feld | Typ | Beschreibung | +|------|-----|-------------| +| `id` | `string` | Eindeutige ID (UUID) | +| `role` | `"document"` | Immer `"document"` auf Level 1 | +| `source_type` | `string` | Originalformat der Quelldatei | +| `source_path` | `string` | Pfad der Originaldatei (relativ zum Workspace oder Archiv) | +| `metadata` | `Metadata` | Dokument-Metadaten | +| `children` | `StructuralNode[]` | Liste der strukturellen Einheiten | + +--- + +### StructuralNode (Level 2) + +Die Gliederungseinheit innerhalb eines Dokuments. + +```typescript +interface StructuralNode { + id: string; + role: "page" | "section" | "slide" | "sheet"; + index: number; + label: string | null; + metadata: Metadata; + children: ContentBlock[]; +} +``` + +| Feld | Typ | Beschreibung | +|------|-----|-------------| +| `id` | `string` | Eindeutige ID | +| `role` | `string` | Art der Struktureinheit (formatabhängig, aber aus fester Menge) | +| `index` | `number` | 0-basierte Position innerhalb des Dokuments | +| `label` | `string?` | Optionaler Name (Sheet-Name, Abschnittsüberschrift, Slide-Titel) | +| `metadata` | `Metadata` | Zusätzliche Informationen zur Struktureinheit | +| `children` | `ContentBlock[]` | Liste der atomaren Inhalte | + +#### Rollen-Zuordnung pro Format + +| Quellformat | `role` | Entspricht im Original | +|-------------|--------|----------------------| +| PDF | `page` | Seite | +| DOCX | `section` | Abschnitt (Heading-basierte Gliederung) | +| PPTX | `slide` | Folie | +| XLSX | `sheet` | Tabellenblatt | +| HTML | `section` | Semantischer Bereich (`
`, `
`, `