This commit is contained in:
ValueOn AG 2026-06-02 09:42:12 +02:00
parent 878226d71b
commit 244726a716
95 changed files with 1585 additions and 1234 deletions

View file

@ -7,11 +7,12 @@
PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung.
| Komponente | Repository | Technologie | Beschreibung |
| Komponente | Repository (Forgejo: git.poweron.swiss/PowerOn) | Technologie | Beschreibung |
|-----------|-----------|-------------|-------------|
| Frontend Nyla | `frontend_nyla` | React/TypeScript, Vite | Zentrales UI für alle Features |
| Gateway | `gateway` | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | `private-llm` | Python | Internes LLM für Neutralisierung + sensitive Daten |
| Frontend Nyla | `ui-nyla` | React/TypeScript, Vite | Zentrales UI für alle Features |
| Platform Core | `platform-core` | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | `service-llm-private` | Python | Internes LLM für Neutralisierung + sensitive Daten |
| Preprocessing | `service-preprocessing` | Python | Datenvorverarbeitung Power BI → SQLite, SQL-Query-Service |
| Teams Bot | `service-teams-browser-bot` | TypeScript/Node.js | Bot für Teams-Meeting-Teilnahme |
| Wiki | `wiki` | Markdown | Dokumentation (dieses Repo) |
@ -53,7 +54,7 @@ PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-
```
b-reference/
├── product.md Komponentenübersicht, Repo-Map, Tech-Stack
├── gateway/ Backend-Komponente
├── platform-core/ Backend-Komponente
│ ├── architecture.md Module, Services, Interfaces
│ ├── ai-agent.md Agent Core, Tools, Knowledge/RAG
│ ├── workflow.md Workflow-Engine, Methoden, Aktionen
@ -61,9 +62,9 @@ b-reference/
│ ├── billing.md Billing, Subscriptions
│ ├── voice-google.md Google STT/TTS (VoiceObjects, Streaming-WS, Feature-Mapping)
│ └── features/ trustee.md, commcoach.md, chatbot.md, ...
├── frontend-nyla/ Frontend-Komponente
├── ui-nyla/ Frontend-Komponente
│ └── architecture.md Seiten, Komponenten, Hooks, Routing
├── private-llm/ Internes LLM
├── service-llm-private/ Internes LLM
│ └── architecture.md Setup, Modelle, Gateway-Integration
├── teams-bot/ Teams Meeting Bot
│ └── architecture.md Service, WebSocket, Architektur
@ -90,5 +91,5 @@ b-reference/
```
<!-- status: canonical | draft | superseded -->
<!-- lastReviewed: YYYY-MM-DD -->
<!-- verifiedAgainst: gateway@<sha>, frontend_nyla@<sha> -->
<!-- verifiedAgainst: platform-core@<sha>, ui-nyla@<sha> -->
```

View file

@ -18,16 +18,16 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
| Thema | Datei | Wann laden |
|-------|-------|------------|
| Komponentenübersicht | b-reference/product.md | Repo-übergreifende Fragen, Tech-Stack |
| Gateway-Architektur | b-reference/gateway/architecture.md | Backend-Module, Services, Interfaces |
| AI Agent & Tools | b-reference/gateway/ai-agent.md | Agent-Verhalten, Tool-Registrierung, RAG |
| Agent-Tool File Bridge | b-reference/gateway/agent-file-bridge.md | Wie Agent-Tool-Outputs (download / writeFile / renderDocument / generateImage / createChart) als ChatDocument im Workflow landen, `docItem:<id>`-Pattern, runAgent Workflow-Propagation |
| Workflow-Engine | b-reference/gateway/workflow.md | Methoden, Aktionen, WorkflowManager |
| Automation | b-reference/gateway/automation.md | Graphical Editor, Scheduler, System-Automatisierung (`/automations`, `/api/system/workflow-runs/*`) |
| Billing & Subscriptions | b-reference/gateway/billing.md | Abrechnung, Prepaid, State Machine |
| Google Voice (STT/TTS) | b-reference/gateway/voice-google.md | VoiceObjects, ConnectorGoogleSpeech, `/voice-google/stt/*`, CommCoach vs Teamsbot vs Agent |
| Frontend Nyla | b-reference/frontend-nyla/architecture.md | UI-Seiten, Komponenten, Hooks, Routing |
| FormGenerator (Table, Form, Tree, Report) | b-reference/frontend-nyla/formgenerator.md | Generische UI-Komponenten, Provider-Pattern, API-Anbindung |
| Private LLM | b-reference/private-llm/architecture.md | Internes LLM, Neutralisierung |
| Gateway-Architektur | b-reference/platform-core/architecture.md | Backend-Module, Services, Interfaces |
| AI Agent & Tools | b-reference/platform-core/ai-agent.md | Agent-Verhalten, Tool-Registrierung, RAG |
| Agent-Tool File Bridge | b-reference/platform-core/agent-file-bridge.md | Wie Agent-Tool-Outputs (download / writeFile / renderDocument / generateImage / createChart) als ChatDocument im Workflow landen, `docItem:<id>`-Pattern, runAgent Workflow-Propagation |
| Workflow-Engine | b-reference/platform-core/workflow.md | Methoden, Aktionen, WorkflowManager |
| Automation | b-reference/platform-core/automation.md | Graphical Editor, Scheduler, System-Automatisierung (`/automations`, `/api/system/workflow-runs/*`) |
| Billing & Subscriptions | b-reference/platform-core/billing.md | Abrechnung, Prepaid, State Machine |
| Google Voice (STT/TTS) | b-reference/platform-core/voice-google.md | VoiceObjects, ConnectorGoogleSpeech, `/voice-google/stt/*`, CommCoach vs Teamsbot vs Agent |
| Frontend Nyla | b-reference/ui-nyla/architecture.md | UI-Seiten, Komponenten, Hooks, Routing |
| FormGenerator (Table, Form, Tree, Report) | b-reference/ui-nyla/formgenerator.md | Generische UI-Komponenten, Provider-Pattern, API-Anbindung |
| Private LLM | b-reference/service-llm-private/architecture.md | Internes LLM, Neutralisierung |
| Teams Bot | b-reference/teams-bot/architecture.md | Meeting-Bot, Browser-Bot WebSocket, Director Prompts (Hybrid Agent-Routing), MeetingModule + 5-Tab-UI, Dashboard-SSE, Live-Session-SSE + MFA |
## Cross-Cutting (repo-übergreifend)
@ -41,7 +41,7 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
| 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 |
| i18n / Mehrsprachigkeit | b-reference/platform-core/architecture.md (Abschnitt i18n), d-guides/coding-conventions.md (Backend i18n), b-reference/ui-nyla/architecture.md (Routing/i18n) | `t()`, `@i18nModel`, UiLanguageSet, TextMultilingual, AI-Uebersetzung, Boot-Sync |
## Aktive Arbeiten (c-work)
@ -62,11 +62,11 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
| 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 |
| Typed Generic Handover (Pick-not-Push, done) | c-work/4-done/2026-04-typed-generic-handover.md | DataRef-only runtime, `validateGraph` Port-Hard-Fail, upstream-paths API, `bindNodeParameter` / `listUpstreamPaths` Tools, graph-defined FormPayload, Migrationsskript |
| 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 |
| Unified Document Model (UDM) & Workflows (done) | z-archive/2026-04-unified-document-model.md, b-reference/platform-core/workflow.md (Abschnitt UDM) | UDM-Baum, Extract-Node, Loop/Consolidate, Agent-UDM-Tools |
| i18n Static Text Elimination (Ph. 12 done) | c-work/2-build/2026-04-i18n-static-text-elimination.md | Gateway Feature+Nodes: Dicts → de-Keys; Ph. 35 offen |
| Database Health & Data Cleanup (done) | z-archive/2026-04-database-health-and-data-cleanup.md | DB-Registry, FK-Discovery, Orphan-Scanner, Admin-Seite |
| Teamsbot Director Prompts (done) | c-work/4-done/2026-04-teamsbot-director-prompts.md | Private Operator-Prompts (One-Shot/Persistent), Hybrid SPEECH_TEAMS+Agent (`needsAgent`), `_activeServices`-Registry, Reconnect-Persistenz, 26 Backend-Tests |
| **Typed Action Architecture** (canonical) | b-reference/gateway/architecture.md (Abschnitt 4-Schichten), b-reference/gateway/workflow.md (Abschnitt Typed Action Architecture), b-reference/gateway/ai-agent.md (Tool-Generierung aus Catalog), b-reference/gateway/features/trustee.md, b-reference/frontend-nyla/architecture.md (FlowEditor), c-work/3-validate/2026-04-typed-action-architecture.md, c-work/1-plan/2026-04-typed-action-followups.md | Catalog → Methods → Adapter → Runtime; FeatureInstanceRef-Envelope; Pick-not-Push; `*`-Wildcard; Save-with-errors (AC-9); DB-CLI `script_migrate_feature_instance_refs.py`; Vitest+RTL FE-Tests |
| **Typed Action Architecture** (canonical) | b-reference/platform-core/architecture.md (Abschnitt 4-Schichten), b-reference/platform-core/workflow.md (Abschnitt Typed Action Architecture), b-reference/platform-core/ai-agent.md (Tool-Generierung aus Catalog), b-reference/platform-core/features/trustee.md, b-reference/ui-nyla/architecture.md (FlowEditor), c-work/3-validate/2026-04-typed-action-architecture.md, c-work/1-plan/2026-04-typed-action-followups.md | Catalog → Methods → Adapter → Runtime; FeatureInstanceRef-Envelope; Pick-not-Push; `*`-Wildcard; Save-with-errors (AC-9); DB-CLI `script_migrate_feature_instance_refs.py`; Vitest+RTL FE-Tests |
## Infrastruktur & Deployment

View file

@ -2,7 +2,7 @@
**Dokument:** Markt- und Wettbewerbsanalyse mit strategischer Empfehlung
**Stand:** 23. Maerz 2026
**Bezug:** poweron.swiss, langdock.com, Codebase (`frontend_nyla`, `gateway`)
**Bezug:** poweron.swiss, langdock.com, Codebase (`ui-nyla`, `platform-core`)
---
@ -218,7 +218,7 @@ Der Code enthaelt bereits Treuhand, Immobilien und CommCoach. Diese Module gehoe
## 9. Quellen und Methodik
- **PowerOn:** Homepage poweron.swiss (Stand Maerz 2026) sowie Codeanalyse gateway und frontend_nyla.
- **PowerOn:** Homepage poweron.swiss (Stand Maerz 2026) sowie Codeanalyse gateway und ui-nyla.
- **Langdock:** Oeffentliche Website langdock.com und Produktunterseiten, Presseartikel (Stand Maerz 2026).
- Keine vertraulichen Materialien verwendet. Fuer verbindliche Pricing- und SLA-Vergleiche ist Herstellerkontakt noetig.

View file

@ -62,7 +62,7 @@ PowerOn ist eine **Multi-Mandanten-Plattform**:
---
## 3. Feature-Übersicht (`gateway/modules/features`)
## 3. Feature-Übersicht (`platform-core/modules/features`)
### 3.1 Chatbot

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-29 -->
<!-- verifiedAgainst: gateway/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py (_attachFileAsChatDocument helper); _dataSourceTools.py / _workspaceTools.py / _mediaTools.py (5 file-producing agent tools); mainServiceAgent.py runAgent workflow propagation; mainServiceChat.py (storeMessageWithDocuments + getChatDocumentsFromDocumentList); workflowProcessor.persistTaskResult (canonical pattern); methodTrustee.extractFromFiles (peer pattern); datamodelChat.ChatDocument; datamodelDocref.coerceDocumentReferenceList -->
<!-- verifiedAgainst: platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py (_attachFileAsChatDocument helper); _dataSourceTools.py / _workspaceTools.py / _mediaTools.py (5 file-producing agent tools); mainServiceAgent.py runAgent workflow propagation; mainServiceChat.py (storeMessageWithDocuments + getChatDocumentsFromDocumentList); workflowProcessor.persistTaskResult (canonical pattern); methodTrustee.extractFromFiles (peer pattern); datamodelChat.ChatDocument; datamodelDocref.coerceDocumentReferenceList -->
# Agent-Tool File Bridge
@ -56,7 +56,7 @@ flowchart LR
### `_attachFileAsChatDocument` (Single Source of Truth)
Datei: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py`
Datei: `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py`
```python
def _attachFileAsChatDocument(
@ -101,7 +101,7 @@ documentList-Pfad braucht Workflow-Kontext sowieso.
### Workflow-Propagation in `runAgent`
Datei: `gateway/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py`
Datei: `platform-core/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py`
`runAgent(workflowId=...)` setzt das Workflow-Objekt jetzt in
`self.services.workflow` UND in `_context.workflow` aller Services
@ -139,7 +139,7 @@ die einzige Luecke.
## Tolerante `documentList`-Parsing-Schicht
Komplementaer dazu: `coerceDocumentReferenceList` in
`gateway/modules/datamodels/datamodelDocref.py` parst das, was der LLM
`platform-core/modules/datamodels/datamodelDocref.py` parst das, was der LLM
am anderen Ende reinschickt -- typischerweise
* `["docItem:<id>", "docItem:<id2>"]` (kanonisch),

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-22 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-04-07, post Automation Unification); gateway/modules/features/teamsbot/service.py (Hybrid Agent Escalation 2026-04-24); Typed Action Architecture Phasen 1-5; featureDataAgent domain hints hook 2026-04-27; central parameterValidation + DatabaseQueryError 2026-04-28; OpenAI temperature contract for GPT-5.x / o-series 2026-04-28; Voice STT speechToText params note 2026-05-10; RAG Consent & Control Unification (Phases A-D) 2026-05-12; Zombie-Killer + Walker-Timeouts 2026-05-14; FeatureDataAgent Query-Repair-Loop + Ontology layer 2026-05-15; UDB DataSource Settings + configurable RAG-Limits 2026-05-17; Cost-Estimate Währung USD→CHF 2026-05-22 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-04-07, post Automation Unification); platform-core/modules/features/teamsbot/service.py (Hybrid Agent Escalation 2026-04-24); Typed Action Architecture Phasen 1-5; featureDataAgent domain hints hook 2026-04-27; central parameterValidation + DatabaseQueryError 2026-04-28; OpenAI temperature contract for GPT-5.x / o-series 2026-04-28; Voice STT speechToText params note 2026-05-10; RAG Consent & Control Unification (Phases A-D) 2026-05-12; Zombie-Killer + Walker-Timeouts 2026-05-14; FeatureDataAgent Query-Repair-Loop + Ontology layer 2026-05-15; UDB DataSource Settings + configurable RAG-Limits 2026-05-17; Cost-Estimate Währung USD→CHF 2026-05-22 -->
# AI Agent & Knowledge Store
@ -10,7 +10,7 @@ Der **AI-Agent** ist der Service `serviceAgent` (`AgentService`) im **ServiceCen
Darunter liegt **`serviceAi`** als Low-Level-Gateway (Billing-Preflight, Provider-/Modellwahl, Neutralisierung vor Modellaufruf). **`serviceKnowledge`** liefert **RAG**: Indexierung extrahierter Inhalte, semantische Suche (pgvector) und **`buildAgentContext`** für kontextuelle Injektion vor jeder Agent-Runde.
Der **AI-Core** (`gateway/modules/aicore/`) kapselt Provider-Plugins und die Modellwahl; der Agent nutzt ihn indirekt über `serviceAi` (u. a. `OperationTypeEnum.AGENT`, Embeddings für den Knowledge Store).
Der **AI-Core** (`platform-core/modules/aicore/`) kapselt Provider-Plugins und die Modellwahl; der Agent nutzt ihn indirekt über `serviceAi` (u. a. `OperationTypeEnum.AGENT`, Embeddings für den Knowledge Store).
---
@ -52,7 +52,7 @@ Pro Request propagiert der **ServiceCenterContext** u. a. `userId`, `mandateId`,
Datenfluss der Zeitzone:
1. **Browser**: `Intl.DateTimeFormat().resolvedOptions().timeZone` (z. B. `"Europe/Zurich"`).
2. **Frontend**: `frontend_nyla/src/api.ts` Axios-Interceptor sendet den IANA-Namen als `X-User-Timezone`-Header.
2. **Frontend**: `ui-nyla/src/api.ts` Axios-Interceptor sendet den IANA-Namen als `X-User-Timezone`-Header.
3. **Gateway**: `_requestContextMiddleware` (`app.py`) liest den Header und schreibt ihn via `_setRequestTimezone` in eine `ContextVar`.
4. **Konsumenten**: `getRequestNow()` / `getRequestTimezone()` aus `modules/shared/timeUtils.py` liefern die Werte für den Prompt-Block (gleiche Pattern wie `_setLanguage` / `_getLanguage`).
5. **Fallback**: Header fehlt oder ist ungültig → `UTC`. Niemals server-seitige Hardcoded-TZ.
@ -98,7 +98,7 @@ Keine separate Tool-Level-RBAC: Zugriff wird über **Datenbank-RBAC** (z. B. Fil
## FeatureDataAgent: Query-Repair-Loop + Ontologie (ab 2026-05)
Der Feature Data Sub-Agent (`gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`) ist die Spezialisten-Schicht hinter dem `queryFeatureInstance`-Tool. Er hat seinen eigenen ReAct-Loop und drei Tools (`browseTable`, `queryTable`, `aggregateTable`) gegen jede Feature-Datentabelle. Ab Mai 2026 verhindern zwei Schichten Halluzinationen deterministisch:
Der Feature Data Sub-Agent (`platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`) ist die Spezialisten-Schicht hinter dem `queryFeatureInstance`-Tool. Er hat seinen eigenen ReAct-Loop und drei Tools (`browseTable`, `queryTable`, `aggregateTable`) gegen jede Feature-Datentabelle. Ab Mai 2026 verhindern zwei Schichten Halluzinationen deterministisch:
### 1. Pre-execute Validator (`queryValidator.py`)
@ -127,7 +127,7 @@ Statt freier `_AGENT_DOMAIN_HINTS`-Strings exportieren Features einen **struktur
### 3. Eval-Harness (Phase 1.5)
`gateway/tests/eval/runTrusteeBenchmark.py` ist ein standalone Runner (kein pytest), der jede Frage des Goldstandards (`tests/fixtures/trusteeBenchmark/questions.yaml`, derzeit 19) gegen einen `FakeFeatureDataProvider` mit synthetischen aber realistischen Trustee-Daten fährt. Drei Modi werden parallel gemessen:
`platform-core/tests/eval/runTrusteeBenchmark.py` ist ein standalone Runner (kein pytest), der jede Frage des Goldstandards (`tests/fixtures/trusteeBenchmark/questions.yaml`, derzeit 19) gegen einen `FakeFeatureDataProvider` mit synthetischen aber realistischen Trustee-Daten fährt. Drei Modi werden parallel gemessen:
| Mode | Validator | Ontologie | Prompt-Block |
|-----------|-----------|-----------|-----------------------------------------------|
@ -256,7 +256,7 @@ Zusätzlich zu den unten genannten **Kern-Tools** existieren **dynamische Tools*
| **Model Registry** | `aicoreModelRegistry.py` — registriert Provider-Plugins und Modelle |
| **Model Selector** | `aicoreModelSelector.py` — Auswahl nach Operationstyp, Promptgrösse, Restriktionen, Ranking |
### Provider-Plugins (Dateien unter `gateway/modules/aicore/`)
### Provider-Plugins (Dateien unter `platform-core/modules/aicore/`)
| Plugin-Modul | Typische Rolle |
|--------------|----------------|
@ -414,7 +414,7 @@ Das gleiche Modal wird auf der `RagInventoryPage` aus dem Partial-Banner (`stopp
## Teamsbot-Integration (Hybrid-Routing, kein eigenes Toolset)
Der Teamsbot ruft den **selben** `AgentService.runAgent` über das ServiceCenter auf — es gibt **kein** Teamsbot-spezifisches Toolset. Aufrufer ist `gateway/modules/features/teamsbot/service.py::_runAgentForMeeting` mit `AgentConfig(maxRounds=5, maxCostCHF=0.10, toolSet="core", initialToolboxes=["core","web"], excludeActionTools=True)`.
Der Teamsbot ruft den **selben** `AgentService.runAgent` über das ServiceCenter auf — es gibt **kein** Teamsbot-spezifisches Toolset. Aufrufer ist `platform-core/modules/features/teamsbot/service.py::_runAgentForMeeting` mit `AgentConfig(maxRounds=5, maxCostCHF=0.10, toolSet="core", initialToolboxes=["core","web"], excludeActionTools=True)`.
| Trigger | Pfad | Wer ruft `runAgent`? |
|---|---|---|
@ -435,34 +435,34 @@ Siehe [`b-reference/teams-bot/architecture.md`](../teams-bot/architecture.md) f
| Datei | Rolle |
|-------|--------|
| `gateway/modules/serviceCenter/registry.py` | Registrierung `agent`, `knowledge`, Dependencies, `objectKey` |
| `gateway/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py` | `AgentService`, `runAgent`, Prompt-Enrichment, Registry-Orchestrierung |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/registerCore.py` | Orchestrator: delegiert Tool-Registrierung an Domänen-Module |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_workspaceTools.py` | Dateien, Ordner, Web, Übersetzung |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py` | Externe Connections, Upload, Mail |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` | DataSource Browse/Search/Download |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_documentTools.py` | Container, Content-Objects, Vision |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py` | Rendering, TTS, STT, Bildgenerierung, Charts, Neutralize, Code |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py` | Feature Data Sub-Agent (queryFeatureInstance) |
| `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_crossWorkflowTools.py` | Workflow-Historie, Messages, `_CORE_ONLY_TOOLS`-Tagging |
| `gateway/modules/serviceCenter/services/serviceAgent/agentLoop.py` | ReAct-Loop, Budget, RAG-Injektion, Tool-Dispatch, Summaries |
| `gateway/modules/serviceCenter/services/serviceAgent/toolRegistry.py` | Registrierung, Dispatch, `readOnly`, Function-Calling-Format |
| `gateway/modules/serviceCenter/services/serviceAgent/conversationManager.py` | Kontextfenster, Summarization, Systemprompt |
| `gateway/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` | `AgentConfig`, Events, Trace-Modelle |
| `gateway/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py` | Workflow-Actions → Agent-Tools (Schema-Generierung; Param-Validierung erfolgt zentral im `ActionExecutor`) |
| `gateway/modules/workflows/processing/shared/parameterValidation.py` | Universelle Action-Parameter-Validierung + Coercion (Required-Enforcement, Ref-Schema → id-String, Primitive-Coercion); aufgerufen aus `ActionExecutor.executeAction` für **alle** Aufrufpfade (Agent, Workflow-Graph, REST) |
| `gateway/modules/connectors/connectorDbPostgre.py` | DB-Connector; Read-Methoden raisen `DatabaseQueryError` bei echten Query-Fehlern (Postgres-Adapt, UndefinedTable/Column, OperationalError, …); Empty Result Sets bleiben `[]`/`None` |
| `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` | Toolbox-Definitionen, `requestToolbox` Meta-Tool-Schema |
| `gateway/modules/serviceCenter/services/serviceAgent/workflowTools.py` | Workflow-Editing-Tools (readWorkflowGraph, addNode, ...) |
| `gateway/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py` | `executeCode`-Sandbox |
| `gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | Index, `buildAgentContext`, Workflow-/Round-Memory-Helfer |
| `gateway/modules/interfaces/interfaceDbKnowledge.py` | DB-Zugriff Knowledge / RAG |
| `gateway/modules/datamodels/datamodelKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory, WorkflowMemory |
| `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py` | Zentrales Neutralisierungs-Gate vor LLM, Billing, Provider-Aufruf |
| `gateway/modules/aicore/aicoreModelRegistry.py` | Provider-/Modell-Registry |
| `gateway/modules/aicore/aicoreModelSelector.py` | Modellauswahl |
| `gateway/modules/aicore/aicorePlugin*.py` | Provider-Implementierungen |
| `gateway/modules/datamodels/datamodelAi.py` | `OperationTypeEnum`, `AiCallRequest`, Optionen |
| `platform-core/modules/serviceCenter/registry.py` | Registrierung `agent`, `knowledge`, Dependencies, `objectKey` |
| `platform-core/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py` | `AgentService`, `runAgent`, Prompt-Enrichment, Registry-Orchestrierung |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/registerCore.py` | Orchestrator: delegiert Tool-Registrierung an Domänen-Module |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_workspaceTools.py` | Dateien, Ordner, Web, Übersetzung |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py` | Externe Connections, Upload, Mail |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` | DataSource Browse/Search/Download |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_documentTools.py` | Container, Content-Objects, Vision |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py` | Rendering, TTS, STT, Bildgenerierung, Charts, Neutralize, Code |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py` | Feature Data Sub-Agent (queryFeatureInstance) |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_crossWorkflowTools.py` | Workflow-Historie, Messages, `_CORE_ONLY_TOOLS`-Tagging |
| `platform-core/modules/serviceCenter/services/serviceAgent/agentLoop.py` | ReAct-Loop, Budget, RAG-Injektion, Tool-Dispatch, Summaries |
| `platform-core/modules/serviceCenter/services/serviceAgent/toolRegistry.py` | Registrierung, Dispatch, `readOnly`, Function-Calling-Format |
| `platform-core/modules/serviceCenter/services/serviceAgent/conversationManager.py` | Kontextfenster, Summarization, Systemprompt |
| `platform-core/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` | `AgentConfig`, Events, Trace-Modelle |
| `platform-core/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py` | Workflow-Actions → Agent-Tools (Schema-Generierung; Param-Validierung erfolgt zentral im `ActionExecutor`) |
| `platform-core/modules/workflows/processing/shared/parameterValidation.py` | Universelle Action-Parameter-Validierung + Coercion (Required-Enforcement, Ref-Schema → id-String, Primitive-Coercion); aufgerufen aus `ActionExecutor.executeAction` für **alle** Aufrufpfade (Agent, Workflow-Graph, REST) |
| `platform-core/modules/connectors/connectorDbPostgre.py` | DB-Connector; Read-Methoden raisen `DatabaseQueryError` bei echten Query-Fehlern (Postgres-Adapt, UndefinedTable/Column, OperationalError, …); Empty Result Sets bleiben `[]`/`None` |
| `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` | Toolbox-Definitionen, `requestToolbox` Meta-Tool-Schema |
| `platform-core/modules/serviceCenter/services/serviceAgent/workflowTools.py` | Workflow-Editing-Tools (readWorkflowGraph, addNode, ...) |
| `platform-core/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py` | `executeCode`-Sandbox |
| `platform-core/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | Index, `buildAgentContext`, Workflow-/Round-Memory-Helfer |
| `platform-core/modules/interfaces/interfaceDbKnowledge.py` | DB-Zugriff Knowledge / RAG |
| `platform-core/modules/datamodels/datamodelKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory, WorkflowMemory |
| `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py` | Zentrales Neutralisierungs-Gate vor LLM, Billing, Provider-Aufruf |
| `platform-core/modules/aicore/aicoreModelRegistry.py` | Provider-/Modell-Registry |
| `platform-core/modules/aicore/aicoreModelSelector.py` | Modellauswahl |
| `platform-core/modules/aicore/aicorePlugin*.py` | Provider-Implementierungen |
| `platform-core/modules/datamodels/datamodelAi.py` | `OperationTypeEnum`, `AiCallRequest`, Optionen |
---

View file

@ -10,7 +10,7 @@ Das Gateway ist das Python-Backend der PowerOn-Plattform (FastAPI, PostgreSQL).
## Modulstruktur
Unter `gateway/modules/` (Kontext-Audit):
Unter `platform-core/modules/` (Kontext-Audit):
| Modul | Zweck |
|-------|-------|
@ -82,26 +82,26 @@ Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap)
| Datei / Pfad | Rolle |
|--------------|-------|
| `gateway/app.py` | FastAPI-Anwendung (generischer Entry-Point), Routen, Middleware, EventManager, Scheduler-MainLoop |
| `gateway/modules/serviceCenter/__init__.py` | Service Center: `getService`, `preWarm`, RBAC-Registrierung für Service-Objekte |
| `gateway/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request |
| `gateway/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) |
| `gateway/modules/serviceCenter/resolver.py` | Auflösung von Service-Instanzen inkl. Cache |
| `gateway/modules/serviceHub/__init__.py` | Hub / DI, `PublicService`-Wrapper für kontrollierte Oberflächen |
| `gateway/modules/routes/*.py` | HTTP-Endpunkte, Aufruf in Richtung Service Center / Features (inkl. `routeI18n.py` für DB-backed i18n mit AI-Übersetzung) |
| `gateway/modules/interfaces/*.py` | Stabile Verträge und DB-Zugriffe (keine direkte Vendor-Logik in Services) |
| `gateway/modules/connectors/*.py` | Vendor-spezifische Adapter (Auth, Transport, Mapping) |
| `gateway/modules/security/*` | RBAC-Auswertung, RBAC-Katalog, Root-Access |
| `gateway/modules/auth/*` | CSRF, Token-Refresh-Middleware, JWT, OAuth |
| `gateway/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
| `gateway/modules/system/registry.py` | Feature-Discovery, Router-Laden, Katalog-Registrierung beim App-Start |
| `gateway/modules/workflows/workflowManager.py` | Zentrale Workflow-Steuerung (Workspace/Chat Workflows) |
| `gateway/modules/workflows/automation2/executionEngine.py` | Graph-Execution-Engine: topoSort, Transit-Routing, `_normalizeToSchema` nach Execute, `flow.merge`-Wait, Resume-Schema-Validierung |
| `gateway/modules/workflows/scheduler/mainScheduler.py` | Konsolidierter Workflow-Scheduler |
| `gateway/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) |
| `gateway/modules/interfaces/interfaceVoiceObjects.py` | Fassade Google STT/TTS, Billing-Callback Streaming |
| `gateway/modules/connectors/connectorVoiceGoogle.py` | Google Speech v1 + Translation + TTS-Client |
| `gateway/modules/routes/routeVoiceGoogle.py` | `/voice-google/*` inkl. STT-Streaming-WebSocket |
| `platform-core/app.py` | FastAPI-Anwendung (generischer Entry-Point), Routen, Middleware, EventManager, Scheduler-MainLoop |
| `platform-core/modules/serviceCenter/__init__.py` | Service Center: `getService`, `preWarm`, RBAC-Registrierung für Service-Objekte |
| `platform-core/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request |
| `platform-core/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) |
| `platform-core/modules/serviceCenter/resolver.py` | Auflösung von Service-Instanzen inkl. Cache |
| `platform-core/modules/serviceHub/__init__.py` | Hub / DI, `PublicService`-Wrapper für kontrollierte Oberflächen |
| `platform-core/modules/routes/*.py` | HTTP-Endpunkte, Aufruf in Richtung Service Center / Features (inkl. `routeI18n.py` für DB-backed i18n mit AI-Übersetzung) |
| `platform-core/modules/interfaces/*.py` | Stabile Verträge und DB-Zugriffe (keine direkte Vendor-Logik in Services) |
| `platform-core/modules/connectors/*.py` | Vendor-spezifische Adapter (Auth, Transport, Mapping) |
| `platform-core/modules/security/*` | RBAC-Auswertung, RBAC-Katalog, Root-Access |
| `platform-core/modules/auth/*` | CSRF, Token-Refresh-Middleware, JWT, OAuth |
| `platform-core/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
| `platform-core/modules/system/registry.py` | Feature-Discovery, Router-Laden, Katalog-Registrierung beim App-Start |
| `platform-core/modules/workflows/workflowManager.py` | Zentrale Workflow-Steuerung (Workspace/Chat Workflows) |
| `platform-core/modules/workflows/automation2/executionEngine.py` | Graph-Execution-Engine: topoSort, Transit-Routing, `_normalizeToSchema` nach Execute, `flow.merge`-Wait, Resume-Schema-Validierung |
| `platform-core/modules/workflows/scheduler/mainScheduler.py` | Konsolidierter Workflow-Scheduler |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) |
| `platform-core/modules/interfaces/interfaceVoiceObjects.py` | Fassade Google STT/TTS, Billing-Callback Streaming |
| `platform-core/modules/connectors/connectorVoiceGoogle.py` | Google Speech v1 + Translation + TTS-Client |
| `platform-core/modules/routes/routeVoiceGoogle.py` | `/voice-google/*` inkl. STT-Streaming-WebSocket |
## Google Voice (STT / TTS)
@ -116,7 +116,7 @@ Das Gateway nutzt ein DB-basiertes Sprachsystem (`UiLanguageSet`). Alle UI-sicht
| `i18nRegistry.py` | `modules/shared/` | `t()`, `resolveText()`, `@i18nModel` Decorator, `_REGISTRY`, `_CACHE`, `_setLanguage`, Boot-Sync |
| `attributeUtils.py` | `modules/shared/` | `getModelLabels()` / `getModelLabel()` lesen aus `i18nRegistry.MODEL_LABELS`, nutzen `resolveText()` |
| `routeI18n.py` | `modules/routes/` | Admin-API: Sprachset-CRUD, AI-Uebersetzung, xx-Sync, TextMultilingual-Batch-Uebersetzung |
| `app.py` | `gateway/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) |
| `app.py` | `platform-core/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) |
### Architektur-Regeln
@ -167,7 +167,7 @@ Felder vom Typ `TextMultilingual` speichern Benutzertexte mehrsprachig. `xx` ist
Hintergrundjobs laufen ausserhalb des Request-Kontexts und haben deshalb keinen `_CURRENT_LANGUAGE`-Wert. Walker schreiben deshalb einen **strukturierten i18n-Payload** in die DB und der Route-Handler uebersetzt server-side beim Read -- der Frontend ruft `t()` nie auf Backend-supplied Werten auf (Regel #2).
**1. Walker schreibt strukturiert** (`gateway/modules/serviceCenter/.../subConnectorSync*.py`):
**1. Walker schreibt strukturiert** (`platform-core/modules/serviceCenter/.../subConnectorSync*.py`):
```python
progressCb(
@ -222,14 +222,14 @@ UI-seitig sind diese Endpunkte unter `/mandates/{m}/trustee/{i}/data-tables[?tab
## Typed Action Architecture (4-Schichten)
Seit Phase 1-5 (April 2026) folgt jede Workflow-Aktion einem strikten 4-Schichten-Modell. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `gateway/tests/unit/workflows/`, `gateway/tests/integration/trustee/`.
Seit Phase 1-5 (April 2026) folgt jede Workflow-Aktion einem strikten 4-Schichten-Modell. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `platform-core/tests/unit/workflows/`, `platform-core/tests/integration/trustee/`.
| Schicht | Modul / Verantwortung | Type-Anker |
|---------|-----------------------|------------|
| **1. Editor (Frontend)** | `frontend_nyla/src/components/FlowEditor/nodes/shared/` -- `RequiredAttributePicker`, `DataPicker` (strict-mode + Object-Drill-Down mit `*`-Wildcard), `paramValidation.ts` | Action-Signaturen aus dem Catalog (`/api/automation2/catalog`) |
| **2. Action / Method** | `gateway/modules/workflows/methods/method<Feature>/actions/*.py` (`extractFromFiles`, `processDocuments`, `syncToAccounting`, ...) | Typisierte Pydantic-Eingabe + `ActionResult`-Output, `FeatureInstanceRef` als Discriminator-Envelope |
| **3. Adapter** | `gateway/modules/features/graphicalEditor/nodeDefinitions/registerNodeWithMethod` -- leitet Node-Definitions aus Action-Signaturen ab, liefert Snapshot fuer den Editor (`adapter_validator`) | Snapshot-Test `test_staticNodesHaveNoDriftAgainstLiveMethods` (`_KNOWN_ADAPTER_DRIFTS = frozenset()`) |
| **4. Runtime** | `gateway/modules/workflows/automation2/executionEngine.py` -- `executeGraph` mit `materializeFeatureInstanceRefs` + `materializeConnectionRefs`, `_unwrapTypedRef` fuer Action-Calls | Migrations-Helper in `automation2/featureInstanceRefMigration.py` + DB-CLI `scripts/script_migrate_feature_instance_refs.py` |
| **1. Editor (Frontend)** | `ui-nyla/src/components/FlowEditor/nodes/shared/` -- `RequiredAttributePicker`, `DataPicker` (strict-mode + Object-Drill-Down mit `*`-Wildcard), `paramValidation.ts` | Action-Signaturen aus dem Catalog (`/api/automation2/catalog`) |
| **2. Action / Method** | `platform-core/modules/workflows/methods/method<Feature>/actions/*.py` (`extractFromFiles`, `processDocuments`, `syncToAccounting`, ...) | Typisierte Pydantic-Eingabe + `ActionResult`-Output, `FeatureInstanceRef` als Discriminator-Envelope |
| **3. Adapter** | `platform-core/modules/features/graphicalEditor/nodeDefinitions/registerNodeWithMethod` -- leitet Node-Definitions aus Action-Signaturen ab, liefert Snapshot fuer den Editor (`adapter_validator`) | Snapshot-Test `test_staticNodesHaveNoDriftAgainstLiveMethods` (`_KNOWN_ADAPTER_DRIFTS = frozenset()`) |
| **4. Runtime** | `platform-core/modules/workflows/automation2/executionEngine.py` -- `executeGraph` mit `materializeFeatureInstanceRefs` + `materializeConnectionRefs`, `_unwrapTypedRef` fuer Action-Calls | Migrations-Helper in `automation2/featureInstanceRefMigration.py` + DB-CLI `scripts/script_migrate_feature_instance_refs.py` |
Konsequenzen:

View file

@ -185,7 +185,7 @@ Rollen werden beim Feature-Start via `_syncTemplateRolesToDb()` synchronisiert (
## System-Automatisierung (Meine Sicht)
Mandatsuebergreifende Uebersicht im Frontend: Route **`/automations`** (`frontend_nyla` → `AutomationsDashboardPage`), Eintrag unter **Meine Sicht** in der Navigation.
Mandatsuebergreifende Uebersicht im Frontend: Route **`/automations`** (`ui-nyla` → `AutomationsDashboardPage`), Eintrag unter **Meine Sicht** in der Navigation.
| Tab | Inhalt |
|-----|--------|
@ -207,7 +207,7 @@ Instanzspezifische Verwaltung unveraendert unter **`/api/workflows/{instanceId}/
## Schluessel-Dateien
| Bereich | Pfade (`gateway/modules/`) |
| Bereich | Pfade (`platform-core/modules/`) |
|---------|--------------------------|
| Feature-Definition | `features/graphicalEditor/mainGraphicalEditor.py` |
| API-Routes | `features/graphicalEditor/routeFeatureGraphicalEditor.py` |

View file

@ -1,4 +1,4 @@
<!-- status: canonical -->
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: gateway (codebase audit 2026-04-05) -->
@ -161,9 +161,9 @@ Typische Trigger: Stripe-Webhooks (`checkout.session.completed`, `invoice.paymen
| `features/workspace/routeFeatureWorkspace.py` | Pattern für Billing-/Fehlerantworten an UI |
| `aicore/aicoreModelSelector.py` | Filter nach erlaubten Providern |
| `aicore/*Plugin*.py` | `connectorType`, Preislogik CHF |
| `frontend_nyla/src/pages/billing/*` | Dashboard, Admin, Stripe-Flow, Subscription-UI |
| `frontend_nyla/src/hooks/useBilling.ts` | Billing-Settings / Subscription-Daten |
| `frontend_nyla/src/pages/views/workspace/useWorkspace.ts` | `billingUiPath` / User-Actions — gleiches Muster für Subscription-Pfade |
| `ui-nyla/src/pages/billing/*` | Dashboard, Admin, Stripe-Flow, Subscription-UI |
| `ui-nyla/src/hooks/useBilling.ts` | Billing-Settings / Subscription-Daten |
| `ui-nyla/src/pages/views/workspace/useWorkspace.ts` | `billingUiPath` / User-Actions — gleiches Muster für Subscription-Pfade |
---

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-15 -->
<!-- verifiedAgainst: gateway/modules/workflows/methods/methodTrustee/ + gateway/modules/features/trustee/ + Typed Action Architecture Phasen 1-5 + Account-Balance-Import + Agent-Ontologie (getAgentOntology) 2026-05-15 -->
<!-- verifiedAgainst: platform-core/modules/workflows/methods/methodTrustee/ + platform-core/modules/features/trustee/ + Typed Action Architecture Phasen 1-5 + Account-Balance-Import + Agent-Ontologie (getAgentOntology) 2026-05-15 -->
# Feature: Trustee
@ -31,10 +31,10 @@ Alle drei Actions konsumieren `featureInstanceId` als typisierten **`FeatureInst
| Modul | Pfad | Verantwortung |
|-------|------|---------------|
| Method (Workflow) | `gateway/modules/workflows/methods/methodTrustee/` | `MethodTrustee` registriert die fuenf Actions; jede Action liegt in `actions/<name>.py` mit eigener typisierter Eingabe + `ActionResult`-Output. |
| Feature-Domain | `gateway/modules/features/trustee/` | Datenmodell (`datamodelTrustee.py`), Interface (`interfaceTrustee.py`), Route-Module (`routeFeatureTrustee*.py`), `AccountingBridge` (`accountingBridge.py`). |
| Editor-Adapter | `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py` | Bindet die fuenf Actions als Editor-Nodes (`trustee.extractFromFiles`, ...) -- Ports + Pflicht-Felder werden via `registerNodeWithMethod` aus den Action-Signaturen abgeleitet. |
| Frontend | `frontend_nyla/src/components/Trustee/` + `TrusteeDataTablesView` | UI fuer Document/Position-Verwaltung, Daten-Tabellen, Connector-Konfiguration. |
| Method (Workflow) | `platform-core/modules/workflows/methods/methodTrustee/` | `MethodTrustee` registriert die fuenf Actions; jede Action liegt in `actions/<name>.py` mit eigener typisierter Eingabe + `ActionResult`-Output. |
| Feature-Domain | `platform-core/modules/features/trustee/` | Datenmodell (`datamodelTrustee.py`), Interface (`interfaceTrustee.py`), Route-Module (`routeFeatureTrustee*.py`), `AccountingBridge` (`accountingBridge.py`). |
| Editor-Adapter | `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py` | Bindet die fuenf Actions als Editor-Nodes (`trustee.extractFromFiles`, ...) -- Ports + Pflicht-Felder werden via `registerNodeWithMethod` aus den Action-Signaturen abgeleitet. |
| Frontend | `ui-nyla/src/components/Trustee/` + `TrusteeDataTablesView` | UI fuer Document/Position-Verwaltung, Daten-Tabellen, Connector-Konfiguration. |
---
@ -48,7 +48,7 @@ Alle drei Actions konsumieren `featureInstanceId` als typisierten **`FeatureInst
| `trustee.refreshAccountingData` | `featureInstanceId` | `ActionResult` (`success`, `error`) | Refresht Kontenplan + Saldo + Kontakte aus dem Buchhaltungssystem. |
| `trustee.queryData` | `featureInstanceId`, freie Filter-Argumente | `ActionResult` mit Query-Resultat | Read-only Zugriff fuer den AI-Agent (`dynamicMode=True`). |
> Schemas leben in `gateway/modules/datamodels/datamodelWorkflowActions.py` + `gateway/modules/features/trustee/datamodelTrustee.py`. **Single source of truth** fuer Editor + AI-Agent + Adapter ist die Action-Signatur (`/api/automation2/catalog`).
> Schemas leben in `platform-core/modules/datamodels/datamodelWorkflowActions.py` + `platform-core/modules/features/trustee/datamodelTrustee.py`. **Single source of truth** fuer Editor + AI-Agent + Adapter ist die Action-Signatur (`/api/automation2/catalog`).
---
@ -77,7 +77,7 @@ Seit Phase 5 ist `featureInstanceId` ueberall als **typisierter Envelope** persi
"featureCode": "trustee" }
```
- **Schreiben:** `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) wandelt rohe UUIDs **bei jedem Run** automatisch ins Envelope-Format. Optional persistiert `gateway/scripts/script_migrate_feature_instance_refs.py` die Aenderung in der DB (`--dry-run` Default).
- **Schreiben:** `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) wandelt rohe UUIDs **bei jedem Run** automatisch ins Envelope-Format. Optional persistiert `platform-core/scripts/script_migrate_feature_instance_refs.py` die Aenderung in der DB (`--dry-run` Default).
- **Lesen:** `_unwrapTypedRef` (`graphUtils`) entpackt den Envelope vor dem Action-Call -- Trustee-Actions sehen weiterhin `featureInstanceId: "<uuid>"` und brauchen keinen Patch.
- **Discriminator:** `featureCode = "trustee"` macht die Trustee-Variante eindeutig (Editor zeigt `[trustee] <Label>` im Picker).
@ -103,7 +103,7 @@ trigger.manual -> trustee.extractFromFiles -> trustee.processDocuments -> truste
## AccountingBridge
`gateway/modules/features/trustee/accountingBridge.py` ist die einheitliche Abstraktion ueber alle Buchhaltungssysteme. `AccountingBridge.pushBatch(positions, config)` validiert + pusht; konkrete Adapter (`abacus.py`, `bexio.py`, `banana.py`, ...) implementieren das Protokoll. Sync-Ergebnisse landen als `TrusteeAccountingSync`-Audit-Eintraege.
`platform-core/modules/features/trustee/accountingBridge.py` ist die einheitliche Abstraktion ueber alle Buchhaltungssysteme. `AccountingBridge.pushBatch(positions, config)` validiert + pusht; konkrete Adapter (`abacus.py`, `bexio.py`, `banana.py`, ...) implementieren das Protokoll. Sync-Ergebnisse landen als `TrusteeAccountingSync`-Audit-Eintraege.
`trustee.refreshAccountingData` ruft `AccountingBridge.fetchSnapshots` -- die Tabellen `TrusteeDataAccount`, `TrusteeDataJournal*`, `TrusteeDataContact`, `TrusteeDataAccountBalance` werden read-only befuellt.
@ -125,7 +125,7 @@ Quelle wird im Log pro Sync dokumentiert: `source=connector` bzw. `source=local-
## REST-Endpunkte (Auswahl)
Liste in `wiki/b-reference/gateway/architecture.md` (Abschnitt "Feature: Trustee -- Daten-Tabellen-Endpunkte"); zentral:
Liste in `wiki/b-reference/platform-core/architecture.md` (Abschnitt "Feature: Trustee -- Daten-Tabellen-Endpunkte"); zentral:
| Endpunkt | Modell | Zweck |
|----------|--------|-------|
@ -141,7 +141,7 @@ UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.featur
## Agent-Ontologie (ab 2026-05)
`mainTrustee.py` exportiert `getAgentOntology() -> OntologyDescriptor` (`gateway/modules/features/trustee/trusteeOntology.py`). Die Ontologie ist die **Single Source of Truth** sowohl fuer den Feature Data Sub-Agent-Prompt als auch fuer den `QueryValidator`:
`mainTrustee.py` exportiert `getAgentOntology() -> OntologyDescriptor` (`platform-core/modules/features/trustee/trusteeOntology.py`). Die Ontologie ist die **Single Source of Truth** sowohl fuer den Feature Data Sub-Agent-Prompt als auch fuer den `QueryValidator`:
| Bestandteil | Inhalt im Trustee-Pilot |
|-------------|------------------------|
@ -152,7 +152,7 @@ UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.featur
**Migrations-Pfad:** Die alten Domain-Hints (`_AGENT_DOMAIN_HINTS`) sind als `_AGENT_DOMAIN_HINTS_LEGACY` geparkt; `getAgentDomainHints()` liefert sie weiter als Fallback fuer Code-Pfade, die `getAgentOntology()` noch nicht kennen. Der `_buildSchemaContext`-Builder in `featureDataAgent` zieht jedoch standardmaessig die kompilierte Ontologie. Eval-Override: `POWERON_DISABLE_FEATURE_ONTOLOGY=1` schaltet auf den Legacy-Block zurueck (Benchmark-Vergleich Baseline/Phase1/Phase2).
**Begruendung des Trustee-Pilots:** Trustee ist heute der Hot-Spot fuer Halluzinationen (SUM closingBalance ueber Perioden, Verwechslung von `creditTotal`/`closingBalance` bei Ertragsfragen). Die Eval-Suite (`gateway/tests/eval/runTrusteeBenchmark.py`, 19 Fragen) misst Genauigkeit, Pattern-Compliance und Repair-Konversion deterministisch -- siehe `b-reference/gateway/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie".
**Begruendung des Trustee-Pilots:** Trustee ist heute der Hot-Spot fuer Halluzinationen (SUM closingBalance ueber Perioden, Verwechslung von `creditTotal`/`closingBalance` bei Ertragsfragen). Die Eval-Suite (`platform-core/tests/eval/runTrusteeBenchmark.py`, 19 Fragen) misst Genauigkeit, Pattern-Compliance und Repair-Konversion deterministisch -- siehe `b-reference/platform-core/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie".
---
@ -160,15 +160,15 @@ UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.featur
| Test | Datei | Was er beweist |
|------|-------|----------------|
| Unit | `gateway/tests/unit/methods/test_methodTrustee.py` (sofern vorhanden) | Action-Schemas + Pflicht-Felder. |
| Adapter-Drift | `gateway/tests/unit/graphicalEditor/test_adapter_validator.py` | Editor-Nodes synchron zu Method-Signaturen (`assert report.errors == []`). |
| FeatureInstanceRef | `gateway/tests/unit/workflows/test_featureInstanceRefMigration.py` | Materialisierung + Auto-Unwrap, Idempotenz. |
| Live-E2E | `gateway/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | `executeGraph` durch `processDocuments + syncToAccounting` mit In-Memory-Fakes. |
| DB-CLI | `gateway/tests/unit/scripts/test_migrate_feature_instance_refs.py` | Dry-run + Live-Migration des persistierten Graphs. |
| Balance RMA | `gateway/tests/unit/features/trustee/test_accountingConnectorRma_balances.py` | `getAccountBalances` via gemocktem `/gl/saldo` (BuHa-SoHa-Szenario + ER-Reset). |
| Balance Bexio | `gateway/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py` | Kumulative Aggregation aus Journal (BS carry-over + ER-Reset). |
| Balance Abacus | `gateway/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py` | OData-Aggregation (BS carry-over + ER-Reset). |
| Balance Sync | `gateway/tests/unit/features/trustee/test_accountingDataSync_balances.py` | Connector-Pfad (verbatim persist) + Local-Fallback (kumulative Berechnung). |
| Unit | `platform-core/tests/unit/methods/test_methodTrustee.py` (sofern vorhanden) | Action-Schemas + Pflicht-Felder. |
| Adapter-Drift | `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py` | Editor-Nodes synchron zu Method-Signaturen (`assert report.errors == []`). |
| FeatureInstanceRef | `platform-core/tests/unit/workflows/test_featureInstanceRefMigration.py` | Materialisierung + Auto-Unwrap, Idempotenz. |
| Live-E2E | `platform-core/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | `executeGraph` durch `processDocuments + syncToAccounting` mit In-Memory-Fakes. |
| DB-CLI | `platform-core/tests/unit/scripts/test_migrate_feature_instance_refs.py` | Dry-run + Live-Migration des persistierten Graphs. |
| Balance RMA | `platform-core/tests/unit/features/trustee/test_accountingConnectorRma_balances.py` | `getAccountBalances` via gemocktem `/gl/saldo` (BuHa-SoHa-Szenario + ER-Reset). |
| Balance Bexio | `platform-core/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py` | Kumulative Aggregation aus Journal (BS carry-over + ER-Reset). |
| Balance Abacus | `platform-core/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py` | OData-Aggregation (BS carry-over + ER-Reset). |
| Balance Sync | `platform-core/tests/unit/features/trustee/test_accountingDataSync_balances.py` | Connector-Pfad (verbatim persist) + Local-Fallback (kumulative Berechnung). |
---

View file

@ -36,7 +36,7 @@ flowchart TD
## Builtin-Resolvers
Definiert in `gateway/modules/routes/routeHelpers.py`:
Definiert in `platform-core/modules/routes/routeHelpers.py`:
| `fk_target.table` | Resolver-Funktion | Datenquelle | Label-Feld |
|---|---|---|---|
@ -230,12 +230,12 @@ if mode == "filterValues":
| Datei | Zweck |
|---|---|
| `gateway/modules/routes/routeHelpers.py` | `_BUILTIN_FK_RESOLVERS`, `_buildLabelResolversFromModel`, `enrichRowsWithFkLabels` |
| `gateway/modules/shared/fkRegistry.py` | `validateFkTargets` (Startup-Validierung), FK-Discovery |
| `gateway/modules/features/trustee/routeFeatureTrustee.py` | `_buildFeatureInternalResolvers` (Referenz-Implementierung) |
| `gateway/modules/features/trustee/datamodelFeatureTrustee.py` | Beispiel-Annotationen (`fk_target` auf allen Modellen) |
| `platform-core/modules/routes/routeHelpers.py` | `_BUILTIN_FK_RESOLVERS`, `_buildLabelResolversFromModel`, `enrichRowsWithFkLabels` |
| `platform-core/modules/shared/fkRegistry.py` | `validateFkTargets` (Startup-Validierung), FK-Discovery |
| `platform-core/modules/features/trustee/routeFeatureTrustee.py` | `_buildFeatureInternalResolvers` (Referenz-Implementierung) |
| `platform-core/modules/features/trustee/datamodelFeatureTrustee.py` | Beispiel-Annotationen (`fk_target` auf allen Modellen) |
## Siehe auch
- [FormGenerator Referenz](../frontend-nyla/formgenerator.md) — Frontend-Darstellung der aufgeloesten Labels
- [FormGenerator Referenz](../ui-nyla/formgenerator.md) — Frontend-Darstellung der aufgeloesten Labels
- [Gateway Architektur](architecture.md) — Modulstruktur und routeHelpers

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-10 -->
<!-- verifiedAgainst: gateway/modules/{connectors/connectorVoiceGoogle.py,interfaces/interfaceVoiceObjects.py,routes/routeVoiceGoogle.py}; gateway/modules/features/{commcoach/serviceCommcoach.py,teamsbot/service.py}; frontend_nyla/src/hooks/useSpeechAudioCapture.ts; frontend_nyla/src/pages/views/commcoach/useVoiceController.ts -->
<!-- verifiedAgainst: platform-core/modules/{connectors/connectorVoiceGoogle.py,interfaces/interfaceVoiceObjects.py,routes/routeVoiceGoogle.py}; platform-core/modules/features/{commcoach/serviceCommcoach.py,teamsbot/service.py}; ui-nyla/src/hooks/useSpeechAudioCapture.ts; ui-nyla/src/pages/views/commcoach/useVoiceController.ts -->
# Google Voice (STT / TTS)

View file

@ -22,7 +22,7 @@ Die Workflow-Engine im Gateway orchestriert KI-gestützte Aufgabenpläne und die
## WorkflowManager
Zentrale Steuerung in `gateway/modules/workflows/workflowManager.py` (grosse Datei; Einstieg für Start/Stopp und Hauptloop).
Zentrale Steuerung in `platform-core/modules/workflows/workflowManager.py` (grosse Datei; Einstieg für Start/Stopp und Hauptloop).
**Öffentliche / zentrale Verantwortlichkeiten (Konzept):**
@ -45,7 +45,7 @@ Zusätzlich definiert `WorkflowModeEnum` den Modus **`WORKFLOW_CHATBOT`** (Chatb
## Methoden
Methoden sind Python-Klassen unter `gateway/modules/workflows/methods/`; der **Methodenname** (`self.name`) ist der Registry-Schlüssel (z.B. `ai`, `context`). Aktionen sind über `WorkflowActionDefinition` registriert; viele tragen `actionId` im Muster `<method>.<action>` und `dynamicMode=True` für den Agent/Graph.
Methoden sind Python-Klassen unter `platform-core/modules/workflows/methods/`; der **Methodenname** (`self.name`) ist der Registry-Schlüssel (z.B. `ai`, `context`). Aktionen sind über `WorkflowActionDefinition` registriert; viele tragen `actionId` im Muster `<method>.<action>` und `dynamicMode=True` für den Agent/Graph.
| Method (`self.name`) | Actions (Registry-Keys) |
|---------------------|-------------------------|
@ -85,23 +85,23 @@ Seit April 2026 ist jede Action typisiert; Editor, Adapter und Runtime lesen die
### Action-Signaturen + Catalog
- `gateway/modules/workflows/methods/method<Feature>/actions/<action>.py` deklariert pro Action eine **typisierte Pydantic-Eingabe** (Pflicht-Felder, Typen, Default-Werte) und liefert `ActionResult` (`success`, `error`, `documents`).
- `platform-core/modules/workflows/methods/method<Feature>/actions/<action>.py` deklariert pro Action eine **typisierte Pydantic-Eingabe** (Pflicht-Felder, Typen, Default-Werte) und liefert `ActionResult` (`success`, `error`, `documents`).
- `FeatureInstanceRef` (`{$type, id, featureCode}`) ist der **Discriminator-Envelope** fuer feature-instance-Parameter -- ersetzt rohe UUID-Strings, behaelt Backwards-Compat durch Auto-Unwrap im Runtime.
- `/api/automation2/catalog` exportiert die normalisierten Signaturen; Editor + AI-Agent + Adapter konsumieren genau diesen Stream.
### Adapter-Layer (`registerNodeWithMethod`)
- `gateway/modules/features/graphicalEditor/nodeDefinitions/registerNodeWithMethod.py` leitet die Editor-Node-Definitionen automatisch aus den Action-Signaturen ab (Ports, Pflicht-Felder, Typen, Frontend-Hints).
- Snapshot-Test `gateway/tests/unit/graphicalEditor/test_adapter_validator.py::test_staticNodesHaveNoDriftAgainstLiveMethods` haelt das Adapter-Layer hart gegen die Methods (`assert report.errors == []`, `_KNOWN_ADAPTER_DRIFTS = frozenset()`).
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/registerNodeWithMethod.py` leitet die Editor-Node-Definitionen automatisch aus den Action-Signaturen ab (Ports, Pflicht-Felder, Typen, Frontend-Hints).
- Snapshot-Test `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py::test_staticNodesHaveNoDriftAgainstLiveMethods` haelt das Adapter-Layer hart gegen die Methods (`assert report.errors == []`, `_KNOWN_ADAPTER_DRIFTS = frozenset()`).
- Drift-Backlog wird in `wiki/c-work/4-done/2026-04-adapter-drift-cleanup.md` (abgeschlossen) tracked; neue Drifts MUESSEN entweder behoben oder bewusst ergaenzt werden.
### Runtime (`executeGraph`) -- Pick-not-Push + Materialisierung
- `gateway/modules/workflows/automation2/executionEngine.py::executeGraph` ruft beim Start zwei Migrations-Helper:
- `platform-core/modules/workflows/automation2/executionEngine.py::executeGraph` ruft beim Start zwei Migrations-Helper:
- `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) -- wandelt rohe `featureInstanceId: "<uuid>"` in `FeatureInstanceRef`-Envelope.
- `materializeConnectionRefs` (`automation2/pickNotPushMigration.py`) -- resolviert leere `connectionReference` aus Upstream-DataRefs.
- `resolveParameterReferences` / `_unwrapTypedRef` (`graphUtils`) entpacken Envelopes vor dem Action-Call -- Legacy-Aktionen sehen weiterhin den nackten Wert (`id`).
- DB-Hygiene: `gateway/scripts/script_migrate_feature_instance_refs.py` migriert Stored Graphs persistent (Editor-Reads sehen sofort die Envelopes; Workflows laufen aber auch ohne Skript korrekt).
- DB-Hygiene: `platform-core/scripts/script_migrate_feature_instance_refs.py` migriert Stored Graphs persistent (Editor-Reads sehen sofort die Envelopes; Workflows laufen aber auch ohne Skript korrekt).
### Bindings-Resolver mit `*`-Wildcard
@ -117,7 +117,7 @@ Seit April 2026 ist jede Action typisiert; Editor, Adapter und Runtime lesen die
## Schlüssel-Dateien
| Pfad (unter `gateway/modules/`) | Rolle |
| Pfad (unter `platform-core/modules/`) | Rolle |
|--------------------------------|--------|
| `workflows/workflowManager.py` | Workflow-Orchestrierung fuer Workspace/Chat (Einstieg) |
| `workflows/processing/` | Processor, Modi (`modeDynamic`, `modeAutomation`), `ActionExecutor` |

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-26 -->
<!-- verifiedAgainst: gateway+frontend-nyla (codebase audit 2026-04-26) -->
<!-- lastReviewed: 2026-05-28 -->
<!-- verifiedAgainst: platform-core+ui-nyla (streaming migration update 2026-05-28) -->
# Datenbank-Architektur
@ -319,10 +319,22 @@ mandateId: str = Field(
Alle Endpunkte: SysAdmin-only via `requireSysAdminRole`.
### Migration API (Streaming, seit 2026-05-28)
| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/admin/database-health/migration/export-stream` | Streaming-Export aller/ausgewaehlter DBs als JSON via `StreamingResponse`. Query-Params: `databases` (kommagetrennt, optional), `filename`. Frontend nutzt `ReadableStream` + File System Access API fuer direktes Streaming-to-Disk. |
| GET | `/api/admin/database-health/migration/export-single?database=...` | Export einer einzelnen DB als JSON. |
| POST | `/api/admin/database-health/migration/upload-import` | Multipart-Upload der Import-JSON auf Disk. Gibt `{token, fileSizeMb}` zurueck. |
| GET | `/api/admin/database-health/migration/process-import-stream?token=...` | Streaming-Validierung + Split der hochgeladenen Datei via `StreamingResponse` (ndjson). Two-Pass mit `ijson`: Pass 1 validiert + extrahiert Metadaten, Pass 2 splittet in per-Table JSONL. Liefert Progress-Events `{phase, db, table, rows}`. |
| POST | `/api/admin/database-health/migration/import-single` | Import einer einzelnen DB (aus per-Table JSONL oder Legacy-Format). |
| POST | `/api/admin/database-health/migration/import-done` | Cleanup temporaerer Dateien nach abgeschlossenem Import. |
### Frontend (`AdminDatabaseHealthPage.tsx`)
- Tab "Statistiken": Sortierbare Tabelle mit DB-Filter und Summary-Leiste
- Tab "Orphan Cleanup": Tabelle mit Clean-Button pro Zeile + "Alle bereinigen", Checkboxen `Nur Probleme` und `Ohne FK-Referenzen zu UserInDB.id` (letzteres default ON)
- Tab "Migration": Streaming-Export (DB-Auswahl, Fortschrittslog mit DB x/n + MB) und Streaming-Import (Upload, Validierungs-Progress, per-DB-Import mit Modus Neu/Zusammenfuehren)
---
@ -330,20 +342,21 @@ Alle Endpunkte: SysAdmin-only via `requireSysAdminRole`.
| 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` |
| Knowledge-DB Interface | `gateway/modules/interfaces/interfaceDbKnowledge.py` |
| Billing-DB Interface | `gateway/modules/interfaces/interfaceDbBilling.py` |
| Subscription Interface | `gateway/modules/interfaces/interfaceDbSubscription.py` |
| RBAC in DB-Schicht | `gateway/modules/interfaces/interfaceRbac.py` |
| Feature-Interface (Template) | `gateway/modules/interfaces/interfaceFeatures.py` |
| 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` |
| PostgreSQL Connector | `platform-core/modules/connectors/connectorDbPostgre.py` |
| DB-Registry | `platform-core/modules/shared/dbRegistry.py` |
| FK-Registry | `platform-core/modules/shared/fkRegistry.py` |
| Database Health | `platform-core/modules/system/databaseHealth.py` |
| Health API Route | `platform-core/modules/routes/routeAdminDatabaseHealth.py` |
| App-DB Interface | `platform-core/modules/interfaces/interfaceDbApp.py` |
| Chat-DB Interface | `platform-core/modules/interfaces/interfaceDbChat.py` |
| Management-DB Interface | `platform-core/modules/interfaces/interfaceDbManagement.py` |
| Knowledge-DB Interface | `platform-core/modules/interfaces/interfaceDbKnowledge.py` |
| Billing-DB Interface | `platform-core/modules/interfaces/interfaceDbBilling.py` |
| Subscription Interface | `platform-core/modules/interfaces/interfaceDbSubscription.py` |
| RBAC in DB-Schicht | `platform-core/modules/interfaces/interfaceRbac.py` |
| Feature-Interface (Template) | `platform-core/modules/interfaces/interfaceFeatures.py` |
| Bootstrap / DB-Seed | `platform-core/modules/interfaces/interfaceBootstrap.py` |
| DB-Migration (Streaming) | `platform-core/modules/system/databaseMigration.py` |
| DB-Migration Script | `platform-core/scripts/script_db_export_migration.py` |
| Datenmodelle (Pydantic) | `platform-core/modules/datamodels/` |
| Frontend Health Page | `ui-nyla/src/pages/admin/AdminDatabaseHealthPage.tsx` |

View file

@ -62,6 +62,14 @@ Key Pair: `ida-laptop` (alle Instanzen)
|---|---|---|---|---|
| `service-main-llm-private` | main | Ollama + FastAPI (Vision-LLM) | GPU L4 (24 GB VRAM), 8 vCPU, 16 GB RAM, 150 GB | `llm.poweron.swiss` / `83.228.200.109` (Port 8000, HTTPS) |
**Geplante Migration → FireStorm (Zug/Zuerich):**
| Anbieter | Produkt | GPU | VRAM | CPU | RAM | Storage | Preis |
|---|---|---|---|---|---|---|---|
| FireStorm ISP | GPU Pro | RTX PRO 6000 Blackwell Max-Q | 96 GB GDDR7 | AMD Threadripper 3970X (32C/64T) | 256 GB DDR4 ECC | 8 TB NVMe RAID 10 | CHF 749/Mt. + CHF 1'900 Setup |
Status: Code vorbereitet (Modell-Definitionen in `aicorePluginPrivateLlm.py`), Hardware noch zu bestellen. DNS-Umschaltung `llm.poweron.swiss` bei Migration.
#### Projekt: Service-Teamsbot (PCP-KO2UYXT)
| Instanzname | Env | Komponente | Flavor | Floating IP | DNS |

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-18 -->
<!-- verifiedAgainst: gateway + frontend_nyla (codebase audit 2026-04-18) -->
<!-- verifiedAgainst: gateway + ui-nyla (codebase audit 2026-04-18) -->
# Mandate-Identifier: `name` (Kurzzeichen) und `label` (Voller Name)
@ -56,7 +56,7 @@ Beispiele:
| `Müller AG` (zweites Mal) | `mueller-ag-2` |
| ` ` (leer) | `mn` (Fallback) |
Code: `gateway/modules/shared/mandateNameUtils.py` (Backend) und `frontend_nyla/src/utils/slugUtils.ts` + `mandateNameUtils.ts` (Frontend, mirror).
Code: `platform-core/modules/shared/mandateNameUtils.py` (Backend) und `ui-nyla/src/utils/slugUtils.ts` + `mandateNameUtils.ts` (Frontend, mirror).
## RBAC und Editierbarkeit
@ -80,7 +80,7 @@ Im UI ist das Kurzzeichen-Feld in den Mandate-Formularen vom Typ `slug` (Live-Ma
3. Stable order ueber `id`-String, deterministisch.
4. Zweiter Lauf ist No-op.
Tests: `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`.
Tests: `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`.
## UI-Anzeige (Konvention)
@ -90,7 +90,7 @@ Tests: `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`.
## Verwandte Dateien
- Backend: `gateway/modules/datamodels/datamodelUam.py` (Pydantic-Modell), `gateway/modules/interfaces/interfaceDbApp.py` (`createMandate`, `updateMandate`, `_provisionMandateForUser`, `_generateUniqueMandateName`), `gateway/modules/routes/routeDataMandates.py`, `gateway/modules/shared/mandateNameUtils.py`.
- Frontend: `frontend_nyla/src/types/mandate.ts`, `frontend_nyla/src/api/mandateApi.ts`, `frontend_nyla/src/utils/slugUtils.ts`, `frontend_nyla/src/utils/mandateNameUtils.ts`, `frontend_nyla/src/utils/mandateDisplayUtils.ts`, `frontend_nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx` (slug-Type Renderer).
- Tests: `gateway/tests/unit/shared/test_mandateNameUtils.py`, `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`, `gateway/tests/integration/mandates/`.
- Backend: `platform-core/modules/datamodels/datamodelUam.py` (Pydantic-Modell), `platform-core/modules/interfaces/interfaceDbApp.py` (`createMandate`, `updateMandate`, `_provisionMandateForUser`, `_generateUniqueMandateName`), `platform-core/modules/routes/routeDataMandates.py`, `platform-core/modules/shared/mandateNameUtils.py`.
- Frontend: `ui-nyla/src/types/mandate.ts`, `ui-nyla/src/api/mandateApi.ts`, `ui-nyla/src/utils/slugUtils.ts`, `ui-nyla/src/utils/mandateNameUtils.ts`, `ui-nyla/src/utils/mandateDisplayUtils.ts`, `ui-nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx` (slug-Type Renderer).
- Tests: `platform-core/tests/unit/shared/test_mandateNameUtils.py`, `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`, `platform-core/tests/integration/mandates/`.
- Plan-Doku: `wiki/c-work/1-plan/2026-04-mandate-name-label-logic.md`.

View file

@ -12,7 +12,7 @@ Die Navigation-API ist die **Single Source of Truth** für die Navigationsstrukt
**Personalisierung:** Sortierung über numerisches `order`; User-Overrides in Settings (`navOrder`), Merge im Gateway: `EffektiveOrder = User-Override ?? Default ?? 50`. Update-Konzept: `PUT /api/user/settings/navOrder`.
Aktuelle UI-Bezüge im Kontext: `MandateNavigation`, Hook `useNavigation` (`frontend_nyla`).
Aktuelle UI-Bezüge im Kontext: `MandateNavigation`, Hook `useNavigation` (`ui-nyla`).
## Block-Struktur
@ -71,7 +71,7 @@ Die exakte Liste und Default-`order` stammen aus der Gateway-Konfiguration (`NAV
| Feature-Views / Template-Rollen | z. B. `mainTrustee.py`, `mainRealEstate.py``UI_OBJECTS`, `TEMPLATE_ROLES` |
| Admin-Feature-Permission (Ist teils feature-spezifisch) | `routeAdminFeatures.py` — z. B. `_deriveViewPermissions` |
| Frontend: Navigation | `MandateNavigation.tsx`, `useNavigation` |
| Frontend: Registry | `frontend_nyla/src/config/pageRegistry.tsx` — `PAGE_REGISTRY`, `FEATURE_REGISTRY` |
| Frontend: Registry | `ui-nyla/src/config/pageRegistry.tsx` — `PAGE_REGISTRY`, `FEATURE_REGISTRY` |
| Legacy-Duplikate (Audit) | `mandate.ts``FEATURE_REGISTRY` / View-Definitionen parallel zum Backend |
## Regeln / Invarianten

View file

@ -68,7 +68,7 @@ Vollstaendige Doku: `b-reference/platform/unified-data-bar.md`. Hier nur Bezug z
## NeutralizationPanel (Frontend)
`frontend_nyla/src/pages/views/workspace/NeutralizationPanel.tsx` — Übersicht zu Dateien mit `neutralize`-Flag, Status und Platzhalter-Mappings. Datenbasis u. a. `GET /api/workspace/{instanceId}/files``{ files: [...] }`.
`ui-nyla/src/pages/views/workspace/NeutralizationPanel.tsx` — Übersicht zu Dateien mit `neutralize`-Flag, Status und Platzhalter-Mappings. Datenbasis u. a. `GET /api/workspace/{instanceId}/files``{ files: [...] }`.
## Schlüssel-Dateien

View file

@ -422,11 +422,11 @@ graph TB
end
subgraph "Integration Points"
WF_DIR[gateway/modules/workflows/methods/]
SVC_DIR[gateway/modules/serviceCenter/services/]
CONN_DIR[gateway/modules/connectors/]
ROUTE_DIR[gateway/modules/routes/]
FEAT_DIR[gateway/modules/features/]
WF_DIR[platform-core/modules/workflows/methods/]
SVC_DIR[platform-core/modules/serviceCenter/services/]
CONN_DIR[platform-core/modules/connectors/]
ROUTE_DIR[platform-core/modules/routes/]
FEAT_DIR[platform-core/modules/features/]
end
subgraph "Development Workflow"

View file

@ -333,7 +333,7 @@ Felder `id` und Namen mit fuehrendem `_` (z.B. `_createdBy`, `_createdAt`) sind
## Frontend-Optionen fuer Rollen
`frontend_options` an Feldern kann statische Listen oder String-Referenzen (z.B. `"user.role"`) nutzen. Dynamische Optionen ueber `/api/options/{optionsName}`. Typ-Hilfen: `gateway/modules/shared/frontendTypes.py`.
`frontend_options` an Feldern kann statische Listen oder String-Referenzen (z.B. `"user.role"`) nutzen. Dynamische Optionen ueber `/api/options/{optionsName}`. Typ-Hilfen: `platform-core/modules/shared/frontendTypes.py`.
---
@ -341,14 +341,14 @@ Felder `id` und Namen mit fuehrendem `_` (z.B. `_createdBy`, `_createdAt`) sind
| Thema | Pfad |
|-------|------|
| RBAC-Auswertung, SQL-Integration | `gateway/modules/interfaces/interfaceRbac.py` |
| AccessRule/Permission-Modelle | `gateway/modules/datamodels/datamodelRbac.py` |
| Membership-Modelle | `gateway/modules/datamodels/datamodelMembership.py` |
| Bootstrap (System Templates, Copy) | `gateway/modules/interfaces/interfaceBootstrap.py` |
| Feature-Template-Copy | `gateway/modules/interfaces/interfaceFeatures.py` |
| Feature-Registrierung | `gateway/modules/system/registry.py` |
| RBAC-Rule-Resolution | `gateway/modules/security/rbac.py` |
| TEMPLATE_ROLES (Beispiel) | `gateway/modules/features/workspace/mainWorkspace.py` |
| RBAC-Auswertung, SQL-Integration | `platform-core/modules/interfaces/interfaceRbac.py` |
| AccessRule/Permission-Modelle | `platform-core/modules/datamodels/datamodelRbac.py` |
| Membership-Modelle | `platform-core/modules/datamodels/datamodelMembership.py` |
| Bootstrap (System Templates, Copy) | `platform-core/modules/interfaces/interfaceBootstrap.py` |
| Feature-Template-Copy | `platform-core/modules/interfaces/interfaceFeatures.py` |
| Feature-Registrierung | `platform-core/modules/system/registry.py` |
| RBAC-Rule-Resolution | `platform-core/modules/security/rbac.py` |
| TEMPLATE_ROLES (Beispiel) | `platform-core/modules/features/workspace/mainWorkspace.py` |
## Feature-Admin-Gate fuer UDB-Flag-Edits

View file

@ -15,7 +15,7 @@ Dieses Dokument ist die kanonische Quelle der Wahrheit fuer:
> Zugehoerige Bereiche:
> - Neutralisierung (Daten-Gate, Engine, Failsafe): `b-reference/platform/neutralization.md`
> - RAG-Indexierung (Ingestion-Pipeline, Inventory): `b-reference/gateway/ai-agent.md`
> - RAG-Indexierung (Ingestion-Pipeline, Inventory): `b-reference/platform-core/ai-agent.md`
> - RBAC (Roles, Permissions, Resolution): `b-reference/platform/rbac.md`
## Architektur-Prinzipien

View file

@ -14,6 +14,7 @@ PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-
| Frontend Nyla | ui-nyla | React/TypeScript, Vite | Zentrales UI für alle Features |
| Platform Core | platform-core | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | service-llm-private | Python | Internes LLM für Neutralisierung + sensitive Daten |
| Preprocessing | service-preprocessing | Python | Datenvorverarbeitung Power BI → SQLite, SQL-Query-Service |
| Teams Bot | service-teams-browser-bot | TypeScript/Node.js | Bot für Teams-Meeting-Teilnahme |
| Wiki | wiki | Markdown | Dokumentation (dieses Repo) |

View file

@ -1,30 +1,101 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: private-llm (codebase review 2026-04-05) -->
<!-- lastReviewed: 2026-05-29 -->
<!-- verifiedAgainst: service-llm-private (codebase review 2026-05-29) -->
# Private LLM -- Architektur
## Überblick
Eigenständiger Service für die Verarbeitung sensitiver Daten mit lokalen AI-Modellen (Ollama). Läuft auf einem dedizierten GPU-Server (Infomaniak Swiss Cloud) und wird vom Gateway als Provider-Plugin (`aicorePluginPrivateLlm.py`) angesprochen. Kein Datenabfluss an externe Cloud-APIs.
Eigenständiger Service für die Verarbeitung sensitiver Daten mit lokalen AI-Modellen (Ollama). Läuft auf einem dedizierten GPU-Server und wird vom Gateway als Provider-Plugin (`aicorePluginPrivateLlm.py`) angesprochen. Kein Datenabfluss an externe Cloud-APIs.
## Technologie-Stack
| Layer | Technologie |
|-------|------------|
| Framework | FastAPI (Python) |
| AI Runtime | Ollama (lokale Vision/Text-Modelle) |
| AI Runtime | Ollama (lokale Vision/Text/Reasoning-Modelle) |
| PDF-Support | PyMuPDF (fitz) |
| Hosting | Infomaniak Swiss Cloud (GPU) |
| Deployment | GitHub Actions → `main` Branch |
| Hosting | Aktuell: Infomaniak (GPU L4, 24 GB) / Geplant: FireStorm (RTX PRO 6000, 96 GB) |
| Deployment | Forgejo Actions → `main` Branch |
## Modelle
| Externer Name | Internes Ollama-Modell | Typ |
|--------------|----------------------|-----|
| `poweron-text-general` | `qwen2.5:7b` | Text |
| `poweron-vision-general` | `qwen2.5vl:7b` | Vision |
| `poweron-vision-deep` | `granite3.2-vision` | Vision |
### Aktuell (Infomaniak L4, 24 GB VRAM)
| Externer Name | Internes Ollama-Modell | Typ | Zweck |
|--------------|----------------------|-----|-------|
| `poweron-text-general` | `qwen2.5:7b` | Text | Neutralisierung, Datenanalyse |
| `poweron-vision-general` | `qwen2.5vl:7b` | Vision | Bildanalyse, Dokumenten-OCR |
| `poweron-vision-deep` | `granite3.2-vision` | Vision | Detaillierte Dokumentenanalyse |
### Geplant (FireStorm RTX PRO 6000, 96 GB VRAM)
| Externer Name | Internes Ollama-Modell | Typ | VRAM | Zweck |
|--------------|----------------------|-----|------|-------|
| `poweron-text-reasoning` | `deepseek-r1:70b` | Reasoning | ~40 GB | Chain-of-Thought, Logik, Planung |
| `poweron-vision-multimodal` | `llama4:scout` | Vision | ~16 GB | Multimodal, Long-Context (10M Tokens) |
| `poweron-embed` | `nomic-embed-text` | Embedding | ~0.3 GB | Lokales RAG-Embedding (ersetzt OpenAI) |
| `poweron-transcribe` | `whisper-large-v3-turbo` (faster-whisper) | STT | ~6 GB | Voice-Transkription, 99 Sprachen, Batch |
**VRAM-Budget gesamt: ~62 GB** (Reserve 34 GB fuer KV-Cache und Parallelitaet)
Die LLM-Modelle sind im Code vorbereitet und werden **automatisch aktiv**, sobald sie in Ollama gepullt sind (`_isModelAvailableInOllama`-Filter). Whisper laeuft als separater Faster-Whisper-Service mit OpenAI-kompatiblem API (`/v1/audio/transcriptions`).
## Migrations-Plan: Infomaniak → FireStorm
### Vorbedingungen
1. FireStorm GPU Pro bestellt (CHF 749/Mt., RTX PRO 6000 Blackwell, 96 GB VRAM)
2. Ubuntu 24.04 LTS mit CUDA-Treibern (vorinstalliert durch FireStorm)
### Migrationsschritte
```bash
# 1. Ollama installieren
curl -fsSL https://ollama.com/install.sh | sh
# 2. Service deployen (git clone + venv + systemd)
git clone git@git.poweron.swiss:PowerOn/service-llm-private.git /srv/llm-private/current
cd /srv/llm-private/current
python3.11 -m venv .venv
.venv/bin/pip install -r requirements.txt
# systemd service file: siehe docu/setupserver.md
# 3. Modelle pullen (aktuell + next-gen)
ollama pull qwen2.5:7b # ~4.5 GB (Abwaertskompatibilitaet)
ollama pull qwen2.5vl:7b # ~6 GB
ollama pull granite3.2-vision # ~2.4 GB
ollama pull deepseek-r1:70b # ~40 GB (Reasoning)
ollama pull llama4:scout # ~16 GB (Vision Multimodal)
ollama pull nomic-embed-text # ~0.3 GB (Embedding)
# 4. Whisper STT Service (separater Prozess)
pip install faster-whisper
# Oder: git clone https://github.com/Hantok/local-whisper-backend /srv/whisper
# Env: LOCAL_WHISPER_MODEL=large-v3-turbo, LOCAL_WHISPER_DEVICE=cuda
# Systemd service auf Port 9000, OpenAI-kompatibel: /v1/audio/transcriptions
# 5. config.ini anpassen (API-Key, TLS)
# 6. DNS umschalten: llm.poweron.swiss -> neue IP
# 7. TLS-Zertifikat (Let's Encrypt oder manuell)
```
### Nach Migration
- `MODEL_MAPPING` in `config.py` auf neue Modelle umschalten (auskommentierter Block)
- Alte Modelle (qwen2.5:7b etc.) koennen parallel weiterlaufen oder entfernt werden
- Infomaniak GPU-VM kuendigen
### Kostenvergleich
| | Infomaniak (aktuell) | FireStorm (geplant) |
|--|---|---|
| GPU | NVIDIA L4 (24 GB) | RTX PRO 6000 Blackwell (96 GB) |
| VRAM | 24 GB | 96 GB (+300%) |
| TFLOPS | ~30 FP32 | 125 FP32 (+316%) |
| RAM | 16 GB | 256 GB |
| Storage | 150 GB | 8 TB NVMe RAID 10 |
| Preis/Mt. | ~CHF 200 (geschaetzt) | CHF 749 |
| Reasoning-Modell | nicht moeglich (zu wenig VRAM) | DeepSeek R1 70B |
| Lokales Embedding | nicht moeglich | nomic-embed-text |
## API-Routen
@ -37,8 +108,10 @@ Eigenständiger Service für die Verarbeitung sensitiver Daten mit lokalen AI-Mo
## Integration mit Gateway
Der Gateway nutzt das Private LLM über `aicorePluginPrivateLlm.py` als Provider für:
- **Neutralisierung:** Text-Analyse mit `poweron-text-general`
- **Neutralisierung:** Text-Analyse mit `poweron-text-general` (oder `poweron-text-reasoning`)
- **Sensitive Datenverarbeitung:** Vision-Analyse von Dokumenten (Rechnungen, Belege, Handschrift)
- **Reasoning:** Komplexe Logik und Planung mit `poweron-text-reasoning`
- **Lokales Embedding:** RAG-Indexierung ohne externe API-Kosten
- **Keine Billing-Kosten** für mandanteninterne LLM-Calls (eigene Infrastruktur)
## Sicherheit
@ -64,3 +137,4 @@ Der Gateway nutzt das Private LLM über `aicorePluginPrivateLlm.py` als Provider
- Model-Mapping ist die einzige Stelle für Namensauflösung (`MODEL_MAPPING` in `config.py`)
- API-Keys werden aus `config.ini` oder Environment gelesen, nie hardcoded
- PDF-Verarbeitung rendert Seiten als Bilder für Vision-Modelle (max 5 Seiten)
- Neue Modelle werden automatisch erkannt wenn in Ollama verfuegbar (kein Code-Deploy noetig)

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-12 -->
<!-- verifiedAgainst: service-teams-browser-bot (statisches Avatar-Video + anonymer Join via Chrome-Channel + WebRTC-Wrapper-Gating 2026-05-12); service-teams-browser-bot (documentation review 2026-02-18); gateway/modules/features/teamsbot/{service,routeFeatureTeamsbot,interfaceFeatureTeamsbot,datamodelTeamsbot}.py + STT single-language (2026-05-12) + `GET /api/teamsbot/{instanceId}/dashboard/stream` (2026-05-11); gateway/tests/unit/teamsbot/test_directorPrompts.py (Director Prompts 2026-04-24); gateway Voice STT batch + linear16 (2026-05-10); frontend_nyla TeamsbotDashboardView / TeamsbotModulesView / TeamsbotSessionView (IA + SSE 2026-05-11) -->
<!-- verifiedAgainst: service-teams-browser-bot (statisches Avatar-Video + anonymer Join via Chrome-Channel + WebRTC-Wrapper-Gating 2026-05-12); service-teams-browser-bot (documentation review 2026-02-18); platform-core/modules/features/teamsbot/{service,routeFeatureTeamsbot,interfaceFeatureTeamsbot,datamodelTeamsbot}.py + STT single-language (2026-05-12) + `GET /api/teamsbot/{instanceId}/dashboard/stream` (2026-05-11); platform-core/tests/unit/teamsbot/test_directorPrompts.py (Director Prompts 2026-04-24); gateway Voice STT batch + linear16 (2026-05-10); ui-nyla TeamsbotDashboardView / TeamsbotModulesView / TeamsbotSessionView (IA + SSE 2026-05-11) -->
# Teams Meeting Bot -- Architektur
@ -70,9 +70,9 @@ Der Gateway (Feature `teamsbot`) verwaltet Sessions und stellt die AI-Pipeline b
| Datei / Bereich | Rolle |
|-----------------|-------|
| `gateway/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul (inkl. `dashboard/stream`, Session-SSE, Module-CRUD) |
| `frontend_nyla/src/pages/views/teamsbot/` | Dashboard (SSE), Assistent, Module, Live-Session, Einstellungen |
| `frontend_nyla/src/api/teamsbotApi.ts` | u.a. `createDashboardStream`, `createSessionStream`, Module-API |
| `platform-core/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul (inkl. `dashboard/stream`, Session-SSE, Module-CRUD) |
| `ui-nyla/src/pages/views/teamsbot/` | Dashboard (SSE), Assistent, Module, Live-Session, Einstellungen |
| `ui-nyla/src/api/teamsbotApi.ts` | u.a. `createDashboardStream`, `createSessionStream`, Module-API |
| `service-teams-browser-bot/` | Eigenständiger Bot-Service (separates Repository) |
## Regeln / Invarianten
@ -82,7 +82,7 @@ Der Gateway (Feature `teamsbot`) verwaltet Sessions und stellt die AI-Pipeline b
- Authentifizierter Join (mit Microsoft-Account) oder Anonymous Guest -- je nach Konfiguration
- Gateway ist die **einzige** Schnittstelle für AI-Aufrufe und TTS -- der Bot-Service selbst hat keine AI-Logik
**STT auf dem Gateway:** Meeting-Audio-Chunks (WebSocket `audioChunk`, PCM) werden pro Chunk mit `VoiceObjects.speechToText` transkribiert (Batch `recognize`, gemeinsamer Connector mit CommCoach). Konfiguration u. a. `audioFormat=linear16`, `skipFallbacks=True`; Details und Modell-Defaults: [voice-google.md](../gateway/voice-google.md).
**STT auf dem Gateway:** Meeting-Audio-Chunks (WebSocket `audioChunk`, PCM) werden pro Chunk mit `VoiceObjects.speechToText` transkribiert (Batch `recognize`, gemeinsamer Connector mit CommCoach). Konfiguration u. a. `audioFormat=linear16`, `skipFallbacks=True`; Details und Modell-Defaults: [voice-google.md](../platform-core/voice-google.md).
**Sprache ist single-language.** Die STT-Sprache ist die Sessionsprache (`TeamsbotUserSettings.language` überschreibt `TeamsbotConfig.language`, Schema-Default `de-DE`). Es gibt **keine** hardcodierten Alternativ-Sprachen — frühere `alternative_language_codes=["en-US"]`-Kombi liess Google STT bei verrauschter Audio (z.B. nach langem Bot-TTS-Playback mit minimalem akustischem Loopback) auf en-US springen und englisches Kauderwelsch zurückgeben (Confidences 0.30.5), während saubere Sprache korrekt als de-DE mit ~0.9+ erkannt wurde. Falls mehrsprachige Meetings gebraucht werden: `connectorVoiceGoogle.speechToText` akzeptiert `alternativeLanguages: list[str]`; eine entsprechende Konfig-Spalte (z.B. `TeamsbotConfig.alternativeLanguages`) müsste explizit eingeführt werden.
@ -241,6 +241,6 @@ Operator-Prompts sind **privat** (nur per SSE an den Session-Owner sichtbar) und
| Persistenz + Lifecycle | `interfaceFeatureTeamsbot.py` (`createDirectorPrompt`, `getActivePersistentPrompts`, `updateDirectorPrompt`, `deleteDirectorPrompt`) |
| Orchestrierung + Agent-Lauf + SSE | `service.py` (`submitDirectorPrompt`, `_processDirectorPrompt`, `_runAgentForMeeting`, `_buildPersistentDirectorContext`, `removePersistentPrompt`) |
| HTTP + RBAC + Limits | `routeFeatureTeamsbot.py` (POST/GET/DELETE `/sessions/{id}/directorPrompts`) |
| Frontend Regie-Panel + UDB-Sidebar + SSE-Listener | `frontend_nyla/src/pages/views/teamsbot/TeamsbotSessionView.tsx` + `Teamsbot.module.css` |
| Frontend API-Wrapper | `frontend_nyla/src/api/teamsbotApi.ts` (`submitDirectorPrompt`, `listDirectorPrompts`, `deleteDirectorPrompt`) |
| Tests | `gateway/tests/unit/teamsbot/test_directorPrompts.py` (26 Tests, AC 5 + 6 abgedeckt; AC 14 manuell live) |
| Frontend Regie-Panel + UDB-Sidebar + SSE-Listener | `ui-nyla/src/pages/views/teamsbot/TeamsbotSessionView.tsx` + `Teamsbot.module.css` |
| Frontend API-Wrapper | `ui-nyla/src/api/teamsbotApi.ts` (`submitDirectorPrompt`, `listDirectorPrompts`, `deleteDirectorPrompt`) |
| Tests | `platform-core/tests/unit/teamsbot/test_directorPrompts.py` (26 Tests, AC 5 + 6 abgedeckt; AC 14 manuell live) |

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-15 -->
<!-- verifiedAgainst: frontend_nyla (codebase audit 2026-04-07, post Automation Unification) + Typed Action Architecture Phasen 1-5 + Vitest+RTL Setup + useVoiceStream STT open options (2026-05-10) + Teams Bot dashboard SSE + Module deep-link (2026-05-11) + RAG Consent & Control (RagInventoryPage, UDB 4. Toggle, RagRunningBadge, Wizard-Refactor) (2026-05-15) + UDB Sources Generic-Tree Refactor (2026-05-18) -->
<!-- verifiedAgainst: ui-nyla (codebase audit 2026-04-07, post Automation Unification) + Typed Action Architecture Phasen 1-5 + Vitest+RTL Setup + useVoiceStream STT open options (2026-05-10) + Teams Bot dashboard SSE + Module deep-link (2026-05-11) + RAG Consent & Control (RagInventoryPage, UDB 4. Toggle, RagRunningBadge, Wizard-Refactor) (2026-05-15) + UDB Sources Generic-Tree Refactor (2026-05-18) -->
# Frontend Nyla -- Architektur
@ -110,7 +110,7 @@ Wenn eine Feature-Seite N verwandte Modelle in eigenen Tabs zeigen soll (Beispie
## FlowEditor -- Typed Action Architecture (Phasen 1-5)
Seit April 2026 stuetzt sich der FlowEditor (Graphical Editor) auf eine typisierte Action-Architektur. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `frontend_nyla/src/components/FlowEditor/**/*.test.tsx`.
Seit April 2026 stuetzt sich der FlowEditor (Graphical Editor) auf eine typisierte Action-Architektur. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `ui-nyla/src/components/FlowEditor/**/*.test.tsx`.
### Picker-Komponenten
@ -134,7 +134,7 @@ Seit April 2026 stuetzt sich der FlowEditor (Graphical Editor) auf eine typisier
### Tests (Vitest + RTL)
`frontend_nyla` nutzt seit Track A1 Vitest 2.x + jsdom + `@testing-library/react`. Die Test-Dateien liegen neben den Komponenten als `*.test.tsx`:
`ui-nyla` nutzt seit Track A1 Vitest 2.x + jsdom + `@testing-library/react`. Die Test-Dateien liegen neben den Komponenten als `*.test.tsx`:
| Test | Datei | Akzeptanzkriterium |
|------|-------|--------------------|

View file

@ -1,6 +1,6 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-05-03 -->
<!-- verifiedAgainst: frontend_nyla (FormGeneratorTable.tsx, FormGeneratorControls.tsx, FormGeneratorTree.tsx) + gateway routeHelpers.py -->
<!-- verifiedAgainst: ui-nyla (FormGeneratorTable.tsx, FormGeneratorControls.tsx, FormGeneratorTree.tsx) + gateway routeHelpers.py -->
# FormGenerator -- Referenz
@ -45,7 +45,7 @@ export const MyPage: React.FC = () => (
);
```
Die drei CSS-Klassen aus `frontend_nyla/src/pages/admin/Admin.module.css`:
Die drei CSS-Klassen aus `ui-nyla/src/pages/admin/Admin.module.css`:
| Klasse | Wirkung |
|--------|---------|
@ -159,7 +159,7 @@ GET /api/users/?mode=ids&pagination={"filters":{"status":"active"},"search":"adm
### Backend-Implementierung
Zentrale Hilfsfunktionen in `gateway/modules/routes/routeHelpers.py` (FK-Label-Aufloesung: siehe [FK Label Resolution](../gateway/fk-label-resolution.md)):
Zentrale Hilfsfunktionen in `platform-core/modules/routes/routeHelpers.py` (FK-Label-Aufloesung: siehe [FK Label Resolution](../platform-core/fk-label-resolution.md)):
| Funktion | Zweck |
|----------|-------|

View file

@ -67,17 +67,17 @@ PowerOn unterstützt Web-Suche über den Tavily-Connector (`WEB_SEARCH_DATA`). E
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | gateway/tests/test_google_connector.py | pending |
| T2 | 2 | unit | ja | gateway/tests/test_google_connector.py | pending |
| T3 | 3 | api | ja | gateway/tests/test_search_images_action.py | pending |
| T1 | 1 | integration | ja | platform-core/tests/test_google_connector.py | pending |
| T2 | 2 | unit | ja | platform-core/tests/test_google_connector.py | pending |
| T3 | 3 | api | ja | platform-core/tests/test_search_images_action.py | pending |
## Links
- Google Custom Search API: https://developers.google.com/custom-search/v1/overview
- Bestehender Tavily Connector: `gateway/modules/aicore/aicorePluginTavily.py`
- Bestehender Tavily Connector: `platform-core/modules/aicore/aicorePluginTavily.py`
## Abschluss
- [ ] b-reference/gateway/ai-agent.md aktualisiert (neuer OperationType)
- [ ] b-reference/platform-core/ai-agent.md aktualisiert (neuer OperationType)
- [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-16 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
<!-- replaces: 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 -->
# Konsolidierter Kundenwünsche-Plan — PORTA Umsetzung
@ -555,13 +555,13 @@ Die Use Cases aus Teil 4 (Lohnbuchhaltung, Steuererklärung, detaillierter Jahre
- 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/`
- Investor-Demo (Referenz): `platform-core/modules/demoConfigs/investorDemo2026.py`
- Frontend-Referenz: `b-reference/ui-nyla/architecture.md`
- Trustee Main (Prompts): `platform-core/modules/features/trustee/mainTrustee.py`
- CommCoach Personas: `platform-core/modules/features/commcoach/serviceCommcoachPersonas.py`
- Neutralisierung: `platform-core/modules/features/neutralization/`
- Graph-Editor Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/`
- Demo-Daten: `platform-core/demoData/`
- UDM-Konzept: `c-work/0-ideas/unified-document-model.md`
## Abschluss

View file

@ -0,0 +1,220 @@
<!-- status: idea -->
<!-- started: 2026-05-30 -->
<!-- component: platform-core | platform -->
# Depoformance Property Match — Backend über PORTA
## Beschreibung und Kontext
Depoformance betreibt mit **Property Match** ein fertiges Frontend für Gewerbeimmobilien-Matching (Supply/Demand), das heute auf Mock-Daten läuft. In ihrer Techdoku (Kap. 11) beschreiben sie, was sie vom „Backend-Team (PowerOn)" brauchen — formuliert in **ihrer** Sprache (generische REST-API, OpenRouter-Proxy, „CI/CD einrichten", JWT-Felder usw.). Sie kennen unser Backend nicht und beschreiben deshalb eine **selbstgebaute Backend-Infrastruktur**.
Dieses Dokument **übersetzt ihre Wünsche in PORTA-Begriffe**: nicht die Schlagworte wörtlich umsetzen, sondern prüfen, was sie fachlich meinen — und es auf vorhandene PORTA-Plattform-Bausteine abbilden. Kernpunkt: **Fast alles, was sie als „muss noch gebaut werden" auflisten, ist in PORTA bereits Plattform-Standard.** Statt eines projektspezifischen Backends bekommen sie die PORTA-Plattform als Backend; ihr Frontend bleibt unverändert und spricht echte PORTA-Endpunkte statt Mock-Provider an.
**Business-Treiber:** Depoformance wird als Partner **nach unserem Standard-Partner-Modell** eingebunden — eigenes UI auf dem PORTA-Backend via API-Vertrag. Kein Sonderfall, sondern der reguläre Partner-Onboarding-Weg.
## Grundprinzip der Übersetzung
| Ihre Formulierung | Was sie meinen | PORTA-Realität |
|---|---|---|
| „Ihr müsst die REST-API für 18 Interfaces bauen" | Sie brauchen persistente, gesicherte CRUD-Endpunkte pro Entität | PORTA hat eine **generische, RBAC-gefilterte CRUD-/Tabellen-Schicht** — Endpunkte entstehen aus dem Datenmodell, werden nicht pro Entität handgeschrieben |
| „OpenRouter-Proxy `POST /api/ai/chat/completions`" | Sie brauchen serverseitigen, abgesicherten Modellzugang | PORTA hat ein **eigenes AI-Gateway** (`serviceAi`) über mehrere Provider — **unser** AI-Service, **kein** OpenRouter |
| „CI/CD müsst ihr entscheiden/einrichten" | Sie wollen Qualitäts-/Deploy-Sicherheit | PORTA hat **automatisierte Tests + Deploy-Pipeline** bereits etabliert — kein Thema für sie |
| „JWT mit `role`/`workspaces`/`organizationId`" | Sie wollen Identität + Mandantentrennung + Rollen | PORTA hat **JWT-Auth + 4-Stufen-RBAC + Mandantentrennung** — wird auf ihre Begriffe gemappt |
## Architektur: dedizierter Partner-Router
Wir bauen für Depoformance einen **eigenen Partner-Router** (z. B. unter `/api/v1/depoformance/*`), der genau die von ihnen benötigten Endpunkte exponiert und intern auf die bestehenden PORTA-Services **durchschleift**. Depoformance sieht nur diesen stabilen Vertrag und kennt unsere internen Routen nicht.
```
Depoformance-App
| Authorization: Bearer <service-token>
v
PORTA Partner-Router /api/v1/depoformance/* (eigene Routendatei)
| schleift durch auf ...
|-- AI -> serviceAi (Modell-Auswahl, Audit, Streaming)
|-- Daten/CRUD -> generische RBAC-CRUD-/Tabellen-Schicht
|-- Datenanbindung-> Konnektoren / serviceWeb / serviceKnowledge / serviceExtraction
|-- Messaging -> serviceMessaging (Mail/Notifications)
```
Vorteile:
- **Stabiler, versionierter Vertrag** — entkoppelt von internen Routenänderungen.
- **Response-Adapter** an genau ihr Format (`{data}` / `{data,total}` / `{code,message}`) an einer Stelle.
- **Pro-Partner Auth, Rate-Limit, Billing-Zuordnung** zentral im Router.
- Wiederverwendbar als Muster für weitere Partner.
## Mapping: Ihre Wünsche (Doku Kap. 11) → PORTA-Fähigkeit
### 11.1 / 11.2 — Persistenz + 18 Provider-Interfaces (CRUD)
Sie wollen pro Entität gespeicherte, abrufbare, gesicherte Daten. In PORTA wird das Property-Match-Domänenmodell als **Feature-Datenmodell** abgebildet (analog zu bestehenden Feature-Modulen wie Trustee/RealEstate). Daraus ergeben sich **automatisch**:
- **CRUD + Pagination**: generische, RBAC-gefilterte Endpunkte (`getRecordsetPaginatedWithRBAC`), `limit`/`offset` (deckt ihren Pagination-Wunsch aus 11.7).
- **Mandantentrennung**: serverseitiger SQL-Filter nach `mandateId` (= ihre `organizationId`), aus dem Token, nicht aus dem Request (deckt Security #2).
- **FK-Auflösung / Labels**, einheitliche Antwortstruktur.
Gruppierung ihrer 18 Interfaces nach PORTA-Baustein:
| Ihre Interfaces | PORTA-Baustein |
|---|---|
| Property, Need, Unit, Match, Inquiry, Offer, Shortlist, Pipeline, Reminder, ReviewQueue | Generische **RBAC-CRUD-Datentabellen** + domänenspezifische Aktions-Endpunkte (`approve`, `moveStage`, `addMessage`, `snooze` …) |
| FutureSignal, LatentNeed, MarktHinweis, MarketIntelligence, SignalPipeline, DataSource | **Datenanbindungen**: Konnektoren, Web-Scraping (`serviceWeb`/Tavily), RAG/semantische Suche (`serviceKnowledge`) → speisen diese „Signal"-Entitäten |
| Dashboard (`getSupplyStats`/`getDemandStats`) | **Aggregations-/Report-Endpunkte** (FormGenerator Report / Dashboard-Aggregation) |
| AIMonitoring (`getOutputs`, `updateReviewStatus`) | **AI-Audit-Log** (AI-Datenfluss-Log) — protokolliert ohnehin jede KI-Ausgabe |
> Domänenspezifische „Spezialmethoden" (z. B. `pipeline.moveStage`, `inquiry.addMessage`) werden als Feature-Endpunkte bzw. Workflow-Aktionen umgesetzt — nicht als handgeschriebene Einzel-APIs.
### 11.3 — Authentifizierung & Session → PORTA Auth + RBAC
PORTA stellt Login/Refresh/Logout/„me" und Session-Mechanik (Token-Refresh, Expiry, Idle-Timeout) bereits bereit. Ihre JWT-Felder werden gemappt:
| Ihr JWT-Feld | PORTA |
|---|---|
| `id` | User-ID |
| `role` (PROPERTY_MANAGER, TENANT, STAFF) | PORTA-Rollen (Mandant- bzw. Feature-Instanz-Rollen) |
| `workspaces` (SUPPLY, DEMAND) | Feature-Zugriff / UI-Sichtbarkeit (RBAC-UI-Items) |
| `organizationId` | `mandateId` (Mandantentrennung) |
Deckt Security #3 (echte Auth, Expiry) und #8 (Session-Mechanik).
### 11.4 — KI-Proxy → unser AI-Service (kein OpenRouter)
Statt OpenRouter bekommen sie **unseren AI-Service** (`serviceAi`): Modell-Auswahl über mehrere Provider (Anthropic, OpenAI, Mistral, Perplexity, Private LLM), Streaming, Billing und **KI-Audit-Log** (Model-ID, Prompt-Hash, User-ID — deckt Security #9), serverseitige Schlüsselhaltung (deckt #4) und Rate-Limiting (deckt #6). Optional steht der **Agent** (Tools, Memory) zur Verfügung.
- **Voller Modellzugang** — sie nutzen die Modelle, wie sie wollen. **Keine Neutralisierung** in diesem Pfad; Datenschutz/Datenminimierung verantwortet Depoformance selbst (bzgl. Security #7 gilt: CH-Datenhaltung garantiert, Provider-DPAs sind unsere).
- Ihre 9 KI-Funktionen (`parseNeed`, `generateMatchExplanation`, `summarizeTradeOffs`, `generateDecisionBrief`, `classifyMarketSignal`, `generateOfferEmail` …) rufen unseren AI-Endpunkt; Output validieren sie wie gehabt frontendseitig (Zod).
### 11.5 — Response-Format
Ihr erwartetes Format (`{data}` / `{data,total}` / `{code,message}`) wird vom PORTA-API-Vertrag bedient (PORTA liefert bereits paginierte `data`+`total`-Antworten; Fehlerhülle wird angeglichen).
### 11.7 — „Offene Punkte" → bereits PORTA-Plattformfunktionen
| Ihr offener Punkt | PORTA |
|---|---|
| Echtzeit-Updates (WebSocket/SSE) | **SSE wird in PORTA bereits eingesetzt** (Dashboard, Live-Sessions) — verfügbar statt Polling |
| Datei-Upload (Dokumente) | **Datei-/Ordner-Verwaltung + Dokument-Extraktion** (`serviceExtraction`: PDF/DOCX/XLSX) vorhanden |
| E-Mail-Versand | **`serviceMessaging`** (E-Mail-Versand) vorhanden — sie erzeugen Text, PORTA versendet |
| Benachrichtigungen | Notifications über `serviceMessaging` |
| Mehrsprachigkeit (i18n) | **DB-basiertes i18n mit AI-Übersetzung** vorhanden |
| Pagination (`limit/offset`) | Standard in der CRUD-Schicht |
| CI/CD | **Automatisierte Tests + Deploy-Pipeline** bereits Standard — kein Thema für sie |
### 11.8 — Deployment / Hosting → PORTA-Infrastruktur (CH)
Backend-REST, PostgreSQL, CORS, HTTPS stellt PORTA bereit; **Datenresidenz CH** garantiert. Ihr Frontend bleibt ein statisches Build und spricht die PORTA-API an.
### 11.9 — Security-Go-Live-Gate (10 Punkte) → weitgehend PORTA-Standard
| # | Anforderung | PORTA |
|---|---|---|
| 1 | Serverseitige Autorisierung pro Endpunkt | RBAC erzwingt das zentral (CRITICAL ✓) |
| 2 | Mandantentrennung aus dem Token | SQL-Filter nach `mandateId` aus dem Token (✓) |
| 3 | Echte Auth, JWT-Expiry, kein Demo-Login | JWT-Auth + Expiry vorhanden (✓) |
| 4 | KI-Key serverseitig | AI-Gateway, Keys serverseitig (✓) |
| 5 | Prompt-Injection-Härtung | im AI-Gateway adressierbar (Delimiter/Längen) |
| 6 | Rate-Limiting KI-Calls | Limiter vorhanden (✓) |
| 7 | Datenschutz/DPA bei KI | CH-Hosting + Provider-DPAs unsererseits; Private LLM für sensible Daten möglich |
| 8 | Session-Mechanik | Token-Refresh/Expiry vorhanden (✓) |
| 9 | KI-Audit-Log | AI-Datenfluss-Log vorhanden (✓) |
| 10 | Transport-/Browser-Härtung | HTTPS/CSP/SameSite/CSRF vorhanden (✓) |
## Was bei Depoformance bleibt
- **Frontend** (alle Seiten, UI-State) — unverändert.
- **Matching-Engine** (scoreCalculator, mustHaveScorer, rankingEngine, tradeOffAnalyzer) — läuft heute im Frontend; bleibt dort (sofern sie es nicht aktiv ins Backend verlagern wollen).
- **Domänenlogik der UI** — Darstellung, Workflows, Validierung im Frontend.
## Was Depoformance einhalten muss (Integrations-Standards)
1. **Authentifizierung gegen PORTA** (Login/Token); Aufrufe mit dem von PORTA ausgestellten Token. Secret nie im Browser-Code.
2. **Server-zu-Server** aus ihrer App; kein direkter Browser-Call gegen PORTA.
3. **Response-/Fehlerformat** und **Pagination** (`limit`/`offset`) gemäss PORTA-Vertrag konsumieren.
4. **Rate-Limits** beachten (429 mit Backoff).
5. **Async**: lange Operationen (Extraktion, Ingestion) als Job-ID → Polling.
6. **Versionierter Vertrag** `/api/v1/...`.
7. **Datenanbindungen spezifizieren** (welche Quellen) — Anbindung läuft über PORTAs Konnektor-Schicht, Datenhaltung CH.
## Billing / Pricing (selbst kalkuliert)
Zwei Komponenten: **einmalige Umsetzung** (Partner-Router + Anbindung) und **laufende API-Nutzung**.
### A) Einmalig — Umsetzung
Kalkulationsbasis: Aufwand für Partner-Router, Auth/Token, AI-Durchschleifung, Daten-/Konnektor-Endpunkte, Response-Adapter, OpenAPI-Doku, Tenant-/Billing-Setup, Tests und Integrationsbegleitung.
| Posten | Aufwand |
|---|---|
| Partner-Router + Auth/Token + Tenant-Setup | ~45 PT |
| AI-Endpunkt(e) durchschleifen (serviceAi) | ~34 PT |
| Daten-/Konnektor-Endpunkte + Response-Adapter | ~68 PT |
| OpenAPI-Doku + Integrationsbegleitung + Tests | ~34 PT |
| **Summe** | **~1621 PT** |
Bei einem Satz von CHF 180/h (8 h/PT = CHF 1'440/PT) ergibt das **CHF 23'00030'000** als T&M-Äquivalent.
> **Fixpreis-Paket Umsetzung: CHF 24'000 einmalig** (Planungssicherheit statt T&M).
> Founding-/Pilot-Option: **CHF 15'000** gegen Referenz/Case-Study.
### B) Laufend — API-Nutzung
| Position | Wert | Begründung |
|---|---|---|
| **API-Grundgebühr** | **CHF 600 / Monat** | Betrieb + Wartung Partner-Router, CH-Hosting, Verfügbarkeit, Support, Vertragspflege |
| inkl. API-Calls (Fair-Use) | bis **100'000 Calls/Monat** | im Grundpreis enthalten |
| API-Calls darüber | **CHF 0.40 / 1'000 Calls** | nutzungsbasiert |
| **AI-Verbrauch** | **pay-as-you-go in CHF**, +15 % Plattformaufschlag auf Modellkosten, Cost-Cap pro Mandant | transparent nach Verbrauch |
**Beispiel-Monat:** Grundgebühr 600 + 50k Calls (inkl.) + AI-Verbrauch CHF 200 + 15 % = **ca. CHF 830 / Monat**.
> Kein User-/Seat-/Subscription-Pricing. Depoformance verrechnet seinen Endkunden eigenständig.
> Alle Preise CHF, exkl. MWST, Vorschlag/freibleibend. Stand 30.05.2026.
## Betroffene Module
- **platform-core:**
- **Partner-Router** `/api/v1/depoformance/*` (eigene Routendatei) — exponiert ihre Endpunkte, schleift intern durch + Response-Adapter auf ihr Format.
- Property-Match **Feature-Datenmodell** + RBAC-Katalog (Entitäten, Aktions-Endpunkte) → nutzt generische CRUD-/Pagination-/RBAC-Schicht.
- AI-Zugang über `serviceAi` (Modell-Auswahl, Audit, Streaming) — **kein** OpenRouter.
- Datenanbindungen via Konnektoren / `serviceWeb` / `serviceKnowledge` / `serviceExtraction`.
- Wiederverwendung: `serviceMessaging` (Mail/Notifications), i18n, SSE, Auth/RBAC, Rate-Limiting, AI-Audit-Log.
- OpenAPI-Doku für den Partner-Router.
- **platform:** Mandant Depoformance + Feature-Instanz; CH-Residenz; Abrechnung (einmalig + API-Nutzung).
- **DB-Migration:** ja (Property-Match-Domänenmodell).
- **ui-nyla:** nicht betroffen.
- **Neutralisierung:** in diesem Pfad bewusst **nicht** aktiv.
## Entscheidungen
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
| 2026-05-30 | **Dedizierter Partner-Router** `/api/v1/depoformance/*`, der ihre Endpunkte durchschleift | Stabiler Vertrag, entkoppelt von internen Routen, pro-Partner Auth/Rate-Limit/Billing |
| 2026-05-30 | Ihre Wünsche auf PORTA-Plattformbausteine abbilden statt projektspezifisches Backend bauen | Fast alles ist bereits Plattform-Standard |
| 2026-05-30 | **Unser AI-Service statt OpenRouter** | Modell-Auswahl, Billing, Audit, Streaming bereits vorhanden |
| 2026-05-30 | Keine Neutralisierung in diesem Pfad | Freier Modellzugang; Datenschutz verantwortet Depoformance |
| 2026-05-30 | Kein End-User-Management/Subscription über PORTA | Steht nicht in ihrer Doku; ihr UI ist eigenständig |
| 2026-05-30 | **Pricing: einmalig CHF 24'000 + API-Grundgebühr CHF 600/Mo + AI pay-as-you-go** | Einmalaufwand gedeckt, laufend nutzungsbasiert |
| 2026-05-30 | CH-Datenresidenz garantiert | Kundenanforderung |
## Offene Punkte (Produkt-/Business — keine Backend-Technik)
- **Datenhoheit/Umfang**: Welche Entitäten hostet PORTA, was bleibt in ihrer App? Bleibt die **Matching-Engine** im Frontend oder soll sie ins Backend?
- Welche **Datenquellen** sollen angebunden werden (Konnektor-Aufwand)?
- Erwarteter **AI-Verbrauch** + Cost-Cap.
- **Vertragspartner** und **Go-Live-Termin**.
## Aufwand (grob, Richtwert, 1 Dev)
Siehe Kalkulation unter Pricing A) — **~1621 PT** für Partner-Router, AI-Durchschleifung, Daten-/Konnektor-Endpunkte, Response-Adapter, OpenAPI, Tenant-/Billing-Setup und Tests. Umfang skaliert mit dem Domänenanteil, den PORTA hostet (offener Punkt). Vorherige Detail-Schätzung:
- Property-Match-Datenmodell + RBAC-Katalog + Aktions-Endpunkte: ~815 PT (Umfang abhängig vom gehosteten Domänenanteil)
- AI-Zugang als `/api/v1`-Vertrag (Wrapper um `serviceAi`): ~35 PT
- Datenanbindungen produktisieren: ~48 PT
- OpenAPI-Doku + Tenant-/Billing-Setup: ~35 PT
## Links
- Depoformance Techdoku: `pamocreate/projects/poweron/customer-depoformance/Techdoku_Depoformance_Property Match_Mai_2026.pdf`
- Pricing-Grundmodell: `pamocreate/projects/poweron/product-pricing/20-pricing-20260530/20260530-pricing-modelle.md`
- Referenzen: `b-reference/platform-core/architecture.md`, `b-reference/platform/rbac.md`, `b-reference/platform-core/billing.md`, `b-reference/platform/audit.md`, `b-reference/ui-nyla/formgenerator.md`

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-05-14 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Lawyer Feature (Mandatsvorbereitung + Dashboards)
@ -37,11 +37,11 @@ Business-Treiber:
## Betroffene Module
- Gateway:
- Neues Feature-Modul `gateway/modules/features/lawyer/` mit `mainLawyer.py`, `datamodelLawyer.py`, `interfaceLawyer.py`, `routeFeatureLawyer*.py`.
- Workflow-Method `gateway/modules/workflows/methods/methodLawyer/` für `lawyer.prepareMatter`, `lawyer.queryData`.
- Konnektoren: prüfen, welche bestehen (`gateway/modules/connectors/`), welche neu (DMS, KYC).
- Neues Feature-Modul `platform-core/modules/features/lawyer/` mit `mainLawyer.py`, `datamodelLawyer.py`, `interfaceLawyer.py`, `routeFeatureLawyer*.py`.
- Workflow-Method `platform-core/modules/workflows/methods/methodLawyer/` für `lawyer.prepareMatter`, `lawyer.queryData`.
- Konnektoren: prüfen, welche bestehen (`platform-core/modules/connectors/`), welche neu (DMS, KYC).
- Frontend:
- Neue Komponenten `frontend_nyla/src/components/Lawyer/`.
- Neue Komponenten `ui-nyla/src/components/Lawyer/`.
- Dashboard-View mit Tabs.
- Matter-Preparation-View (analog Workspace, opinionated).
- DB-Migration: ja neue Tabellen `LawyerMatter`, `LawyerPreparation`, `LawyerDashboardSnapshot`, `LawyerKpi`.
@ -166,10 +166,10 @@ Business-Treiber:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | ja | gateway/tests/test_lawyer_prepare_matter.py | pending |
| T2 | 2 | integration | ja | gateway/tests/test_lawyer_neutralization.py | pending |
| T3 | 3,4 | api | ja | gateway/tests/test_lawyer_rbac.py | pending |
| T4 | 5 | integration | ja | gateway/tests/test_lawyer_dashboard_refresh.py | pending |
| T1 | 1 | api | ja | platform-core/tests/test_lawyer_prepare_matter.py | pending |
| T2 | 2 | integration | ja | platform-core/tests/test_lawyer_neutralization.py | pending |
| T3 | 3,4 | api | ja | platform-core/tests/test_lawyer_rbac.py | pending |
| T4 | 5 | integration | ja | platform-core/tests/test_lawyer_dashboard_refresh.py | pending |
| T5 | 1,6 | e2e | manuell | | pending |
## Demo-Asset Plan (für WW-Präsentation)
@ -182,14 +182,14 @@ Business-Treiber:
- WW-Kontext: `pamocreate/projects/poweron/customer-walderwyss/20-objectives/20260514-zusammenfassung-meeting-dv.md`
- WW-Präsentation: `pamocreate/projects/poweron/customer-walderwyss/30-presentation/`
- Bestehende Feature-Doku als Vorbild: `wiki/b-reference/gateway/features/trustee.md`
- Bestehende Feature-Doku als Vorbild: `wiki/b-reference/platform-core/features/trustee.md`
- Plattform-Bausteine: `wiki/b-reference/platform/neutralization.md`, `wiki/b-reference/platform/rbac.md`
- PR: (noch nicht)
- Issue: (noch nicht)
## Abschluss
- [ ] `b-reference/gateway/features/lawyer.md` als neue Kanon-Seite anlegen
- [ ] `b-reference/platform-core/features/lawyer.md` als neue Kanon-Seite anlegen
- [ ] `TOPICS.md` Eintrag für Lawyer-Feature
- [ ] Dieses Dokument → `2-build/``3-validate/``4-done/`
- [ ] Eintrag in `c-work/_CHANGELOG.md` pro Phase

View file

@ -1,6 +1,6 @@
<!-- status: validate -->
<!-- started: 2026-05-18 -->
<!-- component: frontend-nyla | gateway -->
<!-- component: ui-nyla | gateway -->
# UDB Sources Recovery: einheitliche Tree-Mechanik via FormGeneratorTree
@ -159,7 +159,7 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
## Betroffene Module
- **Gateway**:
- `gateway/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`:
- `platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`:
`_topLevel` umbauen, sodass es **eine** synthetische Wurzel `srcRoot` mit
zwei Sub-Knoten zurueckliefert (`personalRoot`, `mandateRoot`); Connections
werden Children von `personalRoot`, Mandate-Groups Children von `mandateRoot`.
@ -168,22 +168,22 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
- Optional: `getChildrenForParents` so erweitern, dass die drei neuen Synthese-
Keys gehandhabt werden (Dispatch).
- **Frontend**:
- `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`:
- `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx`:
komplett ersetzen (~555 LOC -> erwartet ~80-120 LOC), nur noch ein duenner
Wrapper um `FormGeneratorTree` mit eigenem Provider und Settings-Modal-Ankopplung.
- `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/types.ts`:
- `ui-nyla/src/components/FormGenerator/FormGeneratorTree/types.ts`:
Optional, je nach gewaehltem Approach (siehe Entscheidung E1):
- Variante A: `TreeNode.ragIndexEnabled?: boolean | 'mixed'` als drittes
First-Class-Feld + Provider-Methode `patchRagIndex?(ids, value)`.
- Variante B: RAG ueber `extraActions[]` mit `value: 'mixed'|true|false` --
schon heute unterstuetzt, Tree braucht nichts neues.
- `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`:
- `ui-nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`:
eine generische Prop `refreshAfterAction?: boolean` (Default: `false`,
backward-compatible), und ein generischer Refresh-Hook der nach
`_handleCycleScope`/`_handleToggleNeutralize`/`_handleExtraAction` (NUR
wenn aktiviert) `provider.loadChildren(...)` fuer **alle expandierten
Parents + `null`** aufruft und die Nodes ersetzt. Ohne UDB-Vokabular.
- Neuer Datei `frontend_nyla/src/components/UnifiedDataBar/UdbSourcesProvider.ts`:
- Neuer Datei `ui-nyla/src/components/UnifiedDataBar/UdbSourcesProvider.ts`:
`TreeNodeProvider`-Implementierung, die `POST /tree/children` aufruft und
Backend-`TreeNode` auf den generischen `FormGeneratorTree.TreeNode` mappt.
- **DB-Migration**: nein.
@ -348,15 +348,15 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1, 8 | unit | ja | `gateway/tests/unit/services/test_buildTree.py::TestSyntheticRoots` | DONE -- 7/7 |
| T2 | 8 | unit | ja | `gateway/tests/unit/services/test_buildTree.py::TestGetChildrenForParents` (regress.) | DONE -- 2/2 |
| T3 | 8 | unit | ja | `gateway/tests/unit/services/test_inheritFlags.py` (regress.) | DONE -- 72/72 |
| T1 | 1, 8 | unit | ja | `platform-core/tests/unit/services/test_buildTree.py::TestSyntheticRoots` | DONE -- 7/7 |
| T2 | 8 | unit | ja | `platform-core/tests/unit/services/test_buildTree.py::TestGetChildrenForParents` (regress.) | DONE -- 2/2 |
| T3 | 8 | unit | ja | `platform-core/tests/unit/services/test_inheritFlags.py` (regress.) | DONE -- 72/72 |
| T4 | 2, 3 | unit | ja | `FormGeneratorTree.test.tsx::refreshAfterAction` | DONE -- 2/2 |
| T5 | 5 | unit | ja | `FormGeneratorTree.test.tsx::RAG-Index toggle` (5) + `displayOrder` (3) | DONE -- 8/8 |
| T6 | 4 | unit | ja | bestehende `FormGeneratorTree.test.tsx` Tests (Regression) | DONE -- 38/38 |
| T7 | 6 | manual | nein | `SourcesTab.tsx` ist 75 LOC, kein rekursiver Renderer, kein Flag-Button-Code (nur `<FormGeneratorTree refreshAfterAction selectable={false} />` + Settings-Modal) | DONE |
| T8 | 1, 2, 3, 7 | manual | nein | Smoke-Test: lokale Instanz, Toggle-Cascade pruefen, Mixed-Klick pruefen, neuen Knoten toggeln | OPEN |
| T9 | 9 | build | ja | `cd frontend_nyla && npx tsc --noEmit --skipLibCheck && npm run build` | OPEN |
| T9 | 9 | build | ja | `cd ui-nyla && npx tsc --noEmit --skipLibCheck && npm run build` | OPEN |
## Links
@ -364,19 +364,19 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
- Vorgaenger-Plan (done, FE-Teil bricht): `wiki/c-work/4-done/2026-05-udb-generic-tree-refactor.md`
- Vorgaenger Cascade-Inherit: `wiki/c-work/4-done/2026-05-udb-cascade-inherit.md`
- Settings-Modal-Plan: `wiki/c-work/4-done/2026-05-udb-datasource-settings.md`
- Backend-Helpers (nicht antasten): `gateway/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py`, `_buildTree.py`
- Backend-Routes (nicht antasten): `gateway/modules/routes/routeDataSources.py`, `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- Tree-Komponente: `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`
- Referenz-Implementierung (nicht antasten): `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- Wegzuwerfender Code: `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- Backend-Helpers (nicht antasten): `platform-core/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py`, `_buildTree.py`
- Backend-Routes (nicht antasten): `platform-core/modules/routes/routeDataSources.py`, `platform-core/modules/features/workspace/routeFeatureWorkspace.py`
- Tree-Komponente: `ui-nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`
- Referenz-Implementierung (nicht antasten): `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- Wegzuwerfender Code: `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- PR: noch nicht erstellt.
## Abschluss
- [ ] `b-reference/frontend-nyla/formgenerator.md` aktualisieren: Abschnitt
- [ ] `b-reference/ui-nyla/formgenerator.md` aktualisieren: Abschnitt
"FormGeneratorTree" um die neuen Props (`refreshAfterAction`,
`node.ragIndexEnabled`, `provider.patchRagIndex`) ergaenzen.
- [ ] `b-reference/frontend-nyla/architecture.md` aktualisieren: UDB-Abschnitt
- [ ] `b-reference/ui-nyla/architecture.md` aktualisieren: UDB-Abschnitt
so umschreiben, dass SourcesTab als duenner Wrapper um FormGeneratorTree
beschrieben ist; Files-Tab bleibt unveraendert beschrieben.
- [ ] `b-reference/platform/neutralization.md` Querschnitt pruefen

View file

@ -16,39 +16,39 @@ Neues Feature "CodeEditor" -- Cursor-artiger AI-gestuetzter Text-Editor als eige
| Datei | Beschreibung |
|---|---|
| `gateway/modules/features/codeeditor/__init__.py` | Package init |
| `gateway/modules/features/codeeditor/datamodelCodeeditor.py` | Pydantic Models: FileContext, ResponseSegment, FileEditProposal, FileVersion, MIME-Type Validierung |
| `gateway/modules/features/codeeditor/mainCodeeditor.py` | Feature-Registration: RBAC UI/Resource Objects, Template Roles (Plug&Play) |
| `gateway/modules/features/codeeditor/fileContextManager.py` | Text-Dateien aus DB laden, MIME-Type filtern |
| `gateway/modules/features/codeeditor/promptAssembly.py` | System Prompt Builder mit Datei-Kontext und Format-Instruktionen |
| `gateway/modules/features/codeeditor/responseParser.py` | AI-Antwort in typisierte Segmente parsen (text, code_block, file_edit) |
| `gateway/modules/features/codeeditor/codeEditorProcessor.py` | Orchestrator: Files laden -> Prompt bauen -> AI call -> Parse -> SSE emit |
| `gateway/modules/features/codeeditor/routeFeatureCodeeditor.py` | 8 FastAPI Endpoints inkl. SSE Stream |
| `platform-core/modules/features/codeeditor/__init__.py` | Package init |
| `platform-core/modules/features/codeeditor/datamodelCodeeditor.py` | Pydantic Models: FileContext, ResponseSegment, FileEditProposal, FileVersion, MIME-Type Validierung |
| `platform-core/modules/features/codeeditor/mainCodeeditor.py` | Feature-Registration: RBAC UI/Resource Objects, Template Roles (Plug&Play) |
| `platform-core/modules/features/codeeditor/fileContextManager.py` | Text-Dateien aus DB laden, MIME-Type filtern |
| `platform-core/modules/features/codeeditor/promptAssembly.py` | System Prompt Builder mit Datei-Kontext und Format-Instruktionen |
| `platform-core/modules/features/codeeditor/responseParser.py` | AI-Antwort in typisierte Segmente parsen (text, code_block, file_edit) |
| `platform-core/modules/features/codeeditor/codeEditorProcessor.py` | Orchestrator: Files laden -> Prompt bauen -> AI call -> Parse -> SSE emit |
| `platform-core/modules/features/codeeditor/routeFeatureCodeeditor.py` | 8 FastAPI Endpoints inkl. SSE Stream |
### Frontend (Nyla UI)
| Datei | Beschreibung |
|---|---|
| `frontend_nyla/src/pages/views/codeeditor/CodeEditorPage.tsx` | Drei-Panel-Layout mit resizable Panels |
| `frontend_nyla/src/pages/views/codeeditor/FileListPanel.tsx` | Datei-Auswahl mit Checkboxen |
| `frontend_nyla/src/pages/views/codeeditor/DiffPreviewPanel.tsx` | Diff-Anzeige mit Accept/Reject |
| `frontend_nyla/src/pages/views/codeeditor/useCodeEditor.ts` | SSE Hook mit Auth/CSRF, File-Selection, Edit-State |
| `frontend_nyla/src/pages/views/codeeditor/CodeEditor.module.css` | Styling |
| `frontend_nyla/src/pages/views/codeeditor/index.ts` | Export |
| `ui-nyla/src/pages/views/codeeditor/CodeEditorPage.tsx` | Drei-Panel-Layout mit resizable Panels |
| `ui-nyla/src/pages/views/codeeditor/FileListPanel.tsx` | Datei-Auswahl mit Checkboxen |
| `ui-nyla/src/pages/views/codeeditor/DiffPreviewPanel.tsx` | Diff-Anzeige mit Accept/Reject |
| `ui-nyla/src/pages/views/codeeditor/useCodeEditor.ts` | SSE Hook mit Auth/CSRF, File-Selection, Edit-State |
| `ui-nyla/src/pages/views/codeeditor/CodeEditor.module.css` | Styling |
| `ui-nyla/src/pages/views/codeeditor/index.ts` | Export |
## Geaenderte Dateien
| Datei | Aenderung |
|---|---|
| `gateway/modules/datamodels/datamodelChat.py` | `WORKFLOW_CODEEDITOR = "CodeEditor"` zu `WorkflowModeEnum` hinzugefuegt |
| `gateway/modules/routes/routeSystem.py` | `codeeditor` in `_getFeatureUiObjects()` fuer Navigation API |
| `gateway/modules/system/mainSystem.py` | Store-Resource `resource.store.codeeditor` |
| `gateway/modules/interfaces/interfaceBootstrap.py` | `resource.store.codeeditor` in `storeResources` |
| `frontend_nyla/src/pages/FeatureView.tsx` | Import + `codeeditor` in `VIEW_COMPONENTS` Registry |
| `frontend_nyla/src/config/pageRegistry.tsx` | `feature.codeeditor` Icon (FaFileAlt) |
| `frontend_nyla/src/types/mandate.ts` | `codeeditor` in `FEATURE_REGISTRY` mit Views |
| `frontend_nyla/src/pages/Store.tsx` | Icon + Beschreibung fuer Feature Store |
| `frontend_nyla/src/App.tsx` | Route `editor` fuer CodeEditorPage |
| `platform-core/modules/datamodels/datamodelChat.py` | `WORKFLOW_CODEEDITOR = "CodeEditor"` zu `WorkflowModeEnum` hinzugefuegt |
| `platform-core/modules/routes/routeSystem.py` | `codeeditor` in `_getFeatureUiObjects()` fuer Navigation API |
| `platform-core/modules/system/mainSystem.py` | Store-Resource `resource.store.codeeditor` |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | `resource.store.codeeditor` in `storeResources` |
| `ui-nyla/src/pages/FeatureView.tsx` | Import + `codeeditor` in `VIEW_COMPONENTS` Registry |
| `ui-nyla/src/config/pageRegistry.tsx` | `feature.codeeditor` Icon (FaFileAlt) |
| `ui-nyla/src/types/mandate.ts` | `codeeditor` in `FEATURE_REGISTRY` mit Views |
| `ui-nyla/src/pages/Store.tsx` | Icon + Beschreibung fuer Feature Store |
| `ui-nyla/src/App.tsx` | Route `editor` fuer CodeEditorPage |
## API Endpoints

View file

@ -96,7 +96,7 @@ Fuer das Backend bauen wir denselben Mechanismus. Der Kontext wird automatisch a
### Neues Modul: `i18nRegistry.py`
```python
# gateway/modules/shared/i18nRegistry.py
# platform-core/modules/shared/i18nRegistry.py
_REGISTRY: Dict[str, I18nRegistryEntry] = {} # key -> {context, value}
_CACHE: Dict[str, Dict[str, str]] = {} # lang -> {key -> translation}
@ -299,7 +299,7 @@ Repetitive Arbeit nach klarem Pattern aus Phase 1: Decorator drauf, `json_schema
- [x] Nach jedem Batch: Gateway starten und pruefen
### Phase 3: HTTPException-Texte umstellen (~21 Dateien, ~150 Stellen) -- Cursor: **Auto / Fast**
Mechanische Arbeit: `detail="Text"` wird zu `detail=routeApiMsg("Text")` mit `routeApiMsg = apiRouteContext("route<Dateiname>")` (Shorthand fuer `t(key, "api.route<Dateiname>", "")`). Skript: `gateway/scripts/wrapRouteHttpDetails.py` (nur einzeilige `detail="..."`; mehrzeilige Imports und f-Strings manuell pruefen).
Mechanische Arbeit: `detail="Text"` wird zu `detail=routeApiMsg("Text")` mit `routeApiMsg = apiRouteContext("route<Dateiname>")` (Shorthand fuer `t(key, "api.route<Dateiname>", "")`). Skript: `platform-core/scripts/wrapRouteHttpDetails.py` (nur einzeilige `detail="..."`; mehrzeilige Imports und f-Strings manuell pruefen).
- [x] Alle UI-sichtbaren `HTTPException(detail="...")` in `modules/**/route*.py` auf `routeApiMsg(...)` umgestellt
- [x] Interne/technische Fehlermeldungen (`detail=str(e)`, `detail=f"...{e}..."`) unveraendert gelassen
@ -324,8 +324,8 @@ Reine Doku-Arbeit. Inhalte stehen bereits im Plan (siehe "Wiki-Anpassungen fuer
- [x] `d-guides/coding-conventions.md`: Backend-i18n-Regeln hinzugefuegt (t(), @i18nModel, json_schema_extra["label"], apiRouteContext)
- [x] `d-guides/coding-conventions.md`: Regel fuer HTTPException-Texte mit routeApiMsg()
- [x] `d-guides/coding-conventions.md`: Regel fuer neue Pydantic-Models (@i18nModel Pflicht)
- [x] `b-reference/gateway/architecture.md`: i18n-Architektur dokumentiert (i18nRegistry, Boot-Sync, Cache, Context-Namensraeume, Entry-Identitaet)
- [x] `b-reference/frontend-nyla/architecture.md`: TextMultilingual dynamisch + AdminLanguagesKeepAlive dokumentiert
- [x] `b-reference/platform-core/architecture.md`: i18n-Architektur dokumentiert (i18nRegistry, Boot-Sync, Cache, Context-Namensraeume, Entry-Identitaet)
- [x] `b-reference/ui-nyla/architecture.md`: TextMultilingual dynamisch + AdminLanguagesKeepAlive dokumentiert
- [x] `TOPICS.md`: Thema "i18n / Mehrsprachigkeit" hinzugefuegt (Cross-Cutting + Aktive Arbeiten)
### Abschluss
@ -434,12 +434,12 @@ in alle **anderen** Sprachfelder uebernimmt — dieselbe Logik wie die Admin-Spr
## Links
- Frontend i18n: `frontend_nyla/src/providers/language/LanguageContext.tsx`
- Frontend Key-Scanner: `frontend_nyla/vite.config.ts` (extractI18nKeys Plugin)
- Gateway Model-Labels: `gateway/modules/shared/attributeUtils.py`
- Gateway i18n API: `gateway/modules/routes/routeI18n.py`
- UiLanguageSet Model: `gateway/modules/datamodels/datamodelUiLanguage.py`
- TextMultilingual: `gateway/modules/datamodels/datamodelUtils.py`
- Frontend i18n: `ui-nyla/src/providers/language/LanguageContext.tsx`
- Frontend Key-Scanner: `ui-nyla/vite.config.ts` (extractI18nKeys Plugin)
- Gateway Model-Labels: `platform-core/modules/shared/attributeUtils.py`
- Gateway i18n API: `platform-core/modules/routes/routeI18n.py`
- UiLanguageSet Model: `platform-core/modules/datamodels/datamodelUiLanguage.py`
- TextMultilingual: `platform-core/modules/datamodels/datamodelUtils.py`
## Phase 7 (Vorschlag): RBAC-Labels & Quick Actions — Abgleich mit dem Code
@ -447,8 +447,8 @@ in alle **anderen** Sprachfelder uebernimmt — dieselbe Logik wie die Admin-Spr
| Mechanismus | Code / Pfad | Befund |
|-------------|-------------|--------|
| **TextMultilingual** | `gateway/modules/datamodels/datamodelUtils.py` | Pydantic-Modell: **`en` Pflicht**, `de`/`fr`/`it` optional; `get_text(lang)` mit Fallback auf `en`. |
| **Rollenbeschreibung in der DB** | `gateway/modules/datamodels/datamodelRbac.py` — `Role.description: TextMultilingual` | Feld ist **explizit mehrsprachig**; im Schema `frontend_type: "multilingual"`. |
| **TextMultilingual** | `platform-core/modules/datamodels/datamodelUtils.py` | Pydantic-Modell: **`en` Pflicht**, `de`/`fr`/`it` optional; `get_text(lang)` mit Fallback auf `en`. |
| **Rollenbeschreibung in der DB** | `platform-core/modules/datamodels/datamodelRbac.py` — `Role.description: TextMultilingual` | Feld ist **explizit mehrsprachig**; im Schema `frontend_type: "multilingual"`. |
| **Admin-Formular** | `FormGeneratorForm.tsx` | Felder mit Typ `multilingual` rendern **pro Sprache Eingaben** aus `availableLanguages` — passt zu **TextMultilingual-Objekten** (nicht zu einem einzelnen i18n-Key). |
| **Template-Rollen (Code)** | `mainTrustee.py` etc. — `TEMPLATE_ROLES[].description` | Im Python **Dict** `{en,de,fr}`; beim Sync in die DB als **TextMultilingual**/`Role`-Record. |
| **RBAC-Katalog (RAM)** | `rbacCatalog.py``registerDataObject` / `registerResourceObject` | Labels sind **lose Dicts** `{en,de,...}` im Speicher — **kein** Pydantic-TextMultilingual-Typ auf dem Katalog-Eintrag. |
@ -503,6 +503,6 @@ Button-Tooltip mit Hinweis optional.
## Abschluss
- [x] b-reference/ aktualisiert (gateway/architecture.md, frontend-nyla/architecture.md)
- [x] b-reference/ aktualisiert (platform-core/architecture.md, ui-nyla/architecture.md)
- [x] TOPICS.md aktualisiert (neues Thema: i18n/Mehrsprachigkeit)
- [ ] Dieses Dokument -> z-archive/ verschoben (nach finaler Validierung)

View file

@ -101,12 +101,12 @@ Beide sind Warnings, keine Errors. Wenn später benötigt, einfach auf
## Berührte Dateien
- `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`
- `gateway/modules/features/graphicalEditor/nodeDefinitions/email.py`
- `gateway/modules/features/graphicalEditor/nodeDefinitions/clickup.py`
- `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- `gateway/modules/features/graphicalEditor/nodeDefinitions/context.py`
- `gateway/tests/unit/graphicalEditor/test_adapter_validator.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/email.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/clickup.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/context.py`
- `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py`
Keine Action-Implementierungen geändert → kein Runtime-Regressionsrisiko.
@ -115,6 +115,6 @@ Keine Action-Implementierungen geändert → kein Runtime-Regressionsrisiko.
## Links
- Architektur-Plan: [../3-validate/2026-04-typed-action-architecture.md](../3-validate/2026-04-typed-action-architecture.md)
- Validator: `gateway/modules/features/graphicalEditor/adapterValidator.py`
- Snapshot-Test: `gateway/tests/unit/graphicalEditor/test_adapter_validator.py`
- Validator: `platform-core/modules/features/graphicalEditor/adapterValidator.py`
- Snapshot-Test: `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py`
- Konsolidierter Folge-Plan: [../1-plan/2026-04-typed-action-followups.md](../1-plan/2026-04-typed-action-followups.md)

View file

@ -3,7 +3,7 @@
<!-- implemented: 2026-04-29 -->
<!-- reviewed: 2026-04-29 (critical review passed, corrections applied) -->
<!-- completed: 2026-05-01 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# AI Reports: Generisches Style-Management, AI-Call-Konfiguration, Inline-Bilder
@ -98,38 +98,38 @@ explizit und auditierbar.
## Betroffene Module
- Gateway:
- `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`
- `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`
-- `_markdownToDocumentJson` (nested in `_registerMediaTools`, Z. 27-163)
entfernen, Aufruf auf `subDocumentUtility.markdownToDocumentJson`
umleiten. Image-Resolution-Logik (Z. 241-277, loest fileId -> base64
aus KnowledgeStore/Chat) VERBLEIBT in `_mediaTools` als Post-
Processing-Schritt nach dem Parser-Aufruf.
`renderDocument`-Tool-Schema ergaenzt um optionalen `style`-Parameter.
- `gateway/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`
- `platform-core/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`
-- alleinige MD->JSON-Funktion mit Inline-Run-Modell.
- `gateway/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py`
- `platform-core/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py`
-- `_resolveStyle(metadata.style) -> ResolvedStyle` (Defaults +
Agent-Overrides).
- `gateway/modules/serviceCenter/services/serviceGeneration/renderers/*`
- `platform-core/modules/serviceCenter/services/serviceGeneration/renderers/*`
-- alle 5 Renderer auf Style-Lookup umstellen, Inline-Run-Renderer.
NUR neues Format (InlineRun); altes String-Format wird nicht mehr
unterstuetzt.
- `gateway/modules/datamodels/datamodelJson.py` -- Schema-Erweiterung
- `platform-core/modules/datamodels/datamodelJson.py` -- Schema-Erweiterung
fuer Inline-Runs und `cellContent`.
- `gateway/modules/datamodels/datamodelAi.py` --
- `platform-core/modules/datamodels/datamodelAi.py` --
`AiCallOptions.allowedModels: Optional[List[str]]` (Whitelist;
analog `allowedProviders` Z. 164).
- `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`
- `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`
-- `_calculateEffectiveModels()` (Z. ~1196, analog zu
`_calculateEffectiveProviders`); Whitelist-Check vor Modellwahl,
Fail-fast wenn keiner uebrig. `_ServicesAdapter.__getattr__`
(Z. 88-90) um `"allowedModels"` ergaenzen.
- `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py`
-- Standardparameter `requireNeutralization` + `allowedModels` zu
allen `ai.*`-Nodes (gemeinsamer Helper `_AI_COMMON_PARAMS`).
- `gateway/modules/workflows/methods/methodAi/actions/*.py` -- Node-
- `platform-core/modules/workflows/methods/methodAi/actions/*.py` -- Node-
Parameter durchreichen in den `AiCallRequest`.
- `gateway/modules/serviceCenter/services/serviceAgent/conversationManager.py`
- `platform-core/modules/serviceCenter/services/serviceAgent/conversationManager.py`
-- Workspace-Kontext-Defaults fuer `requireNeutralization` /
`allowedModels` aus Workspace-Config in `ServiceCenterContext`
setzen.
@ -207,7 +207,7 @@ Bericht soll, gibt der Agent eine `fileId` an (Datei muss zuvor via
`generateImage`/`writeFile` oder DataSource-Download erzeugt sein und
liegt bereits als `FileItem` vor).
**Defaults (`gateway/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`):**
**Defaults (`platform-core/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`):**
neutrale Default-Werte fuer alle Felder. `_resolveStyle(agentStyle) ->
ResolvedStyle` macht ein deep-merge `defaults <- agentStyle`. Renderer
sieht immer eine vollstaendig aufgeloeste Struktur.
@ -261,7 +261,7 @@ zu einem `image`-Run. Listen-Items dasselbe.
- **`AiCallRequest.requireNeutralization`** existiert (`datamodelAi.py` Z. 177).
- **`AiCallOptions.allowedProviders`** existiert (`datamodelAi.py` Z. 164) --
Provider-Whitelist auf Anbieter-Ebene (z.B. `anthropic`, `openai`,
`private-llm`).
`service-llm-private`).
- **`Workflow.allowedProviders`** wird ueber `__getattr__` durchgereicht
(`mainServiceAi.py` Z. 89).
- **`_calculateEffectiveProviders()`** macht RBAC ∩ Workflow.allowedProviders
@ -321,7 +321,7 @@ nutzbar (z.B. Provider `openai` erlaubt, aber nur `gpt-5-mini` nicht
### Beispiel: AI-Node-Definition (gekuerzt)
```python
# in gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py
# in platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py
# (allowedProviders existiert bereits auf Workflow-Ebene; hier nur die
# zwei NEUEN Felder pro AI-Node)
_AI_COMMON_PARAMS = [
@ -414,7 +414,7 @@ flowchart LR
### Phase 2 -- Style-System
- [x] Defaults-Modul `gateway/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`
- [x] Defaults-Modul `platform-core/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`
mit neutralen Default-Werten fuer alle Style-Felder.
- [x] Style-Resolver in `mainServiceGeneration.py`:
`_resolveStyle(metadataStyle: dict | None) -> ResolvedStyle`
@ -471,15 +471,15 @@ flowchart LR
### Phase 5 -- AI-Call-Konfiguration pro Node (Datenmodell + Backend)
- [x] `gateway/modules/datamodels/datamodelAi.py`:
- [x] `platform-core/modules/datamodels/datamodelAi.py`:
- `AiCallOptions.allowedModels: Optional[List[str]] = None`
(analog zu `allowedProviders` in Z. 164 -- KEIN neues Feld in
`AiCallRequest`).
- [x] `gateway/modules/datamodels/datamodelAuto.py` (oder wo immer das
- [x] `platform-core/modules/datamodels/datamodelAuto.py` (oder wo immer das
`Workflow`-Modell liegt):
- `Workflow.allowedModels: Optional[List[str]] = None` (analog
`Workflow.allowedProviders`).
- [x] `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`:
- [x] `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`:
- Neue private Methode `_calculateEffectiveModels()` analog zu
`_calculateEffectiveProviders()` (Z. ~1196). RBAC-Modelle ∩
`Workflow.allowedModels``request.options.allowedModels`.
@ -540,12 +540,12 @@ flowchart LR
### Phase 5b -- AI-Nodes im FlowEditor
- [x] `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`:
- [x] `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py`:
- Modul-lokaler Helper `_AI_COMMON_PARAMS = [...]` mit den 2
neuen Parametern.
- In ALLE 8 Eintraege von `AI_NODES` als `*_AI_COMMON_PARAMS`
anhaengen.
- [x] `gateway/modules/workflows/methods/methodAi/actions/*.py`:
- [x] `platform-core/modules/workflows/methods/methodAi/actions/*.py`:
- In jeder Action (`process.py`, `webResearch.py`,
`summarizeDocument.py`, `translateDocument.py`,
`convertDocument.py`, `generateDocument.py`,
@ -612,37 +612,37 @@ flowchart LR
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1,2 | snapshot | ja | gateway/tests/serviceGeneration/test_agent_style_docx.py | done |
| T2 | 3 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_paragraph.py | done |
| T3 | 4 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_table_cell.py | done |
| T4 | 5 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_list_item_html.py | done |
| T5 | 6 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_pptx_fallback.py | done |
| T6 | 7 | integration | ja | gateway/tests/serviceAi/test_node_neutralization_flag.py | done |
| T7 | 8,9 | integration | ja | gateway/tests/serviceAi/test_allowed_models_whitelist.py | done |
| T8 | 10 | integration | ja | gateway/tests/features/workspace/test_user_settings_persistence.py | done |
| T9 | 11 | integration | ja | gateway/tests/serviceAi/test_workspace_propagates_settings.py | done |
| T10 | 12 | unit | ja | gateway/tests/serviceAi/test_effective_models_and_providers.py | done |
| T11 | 13 | unit | ja | gateway/tests/serviceCenter/test_md_to_json_consolidation.py | done |
| T12 | -- | unit | ja | frontend_nyla/src/components/flowEditor/__tests__/AiNodeProperties.test.tsx | deferred |
| T1 | 1,2 | snapshot | ja | platform-core/tests/serviceGeneration/test_agent_style_docx.py | done |
| T2 | 3 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_paragraph.py | done |
| T3 | 4 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_table_cell.py | done |
| T4 | 5 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_list_item_html.py | done |
| T5 | 6 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_pptx_fallback.py | done |
| T6 | 7 | integration | ja | platform-core/tests/serviceAi/test_node_neutralization_flag.py | done |
| T7 | 8,9 | integration | ja | platform-core/tests/serviceAi/test_allowed_models_whitelist.py | done |
| T8 | 10 | integration | ja | platform-core/tests/features/workspace/test_user_settings_persistence.py | done |
| T9 | 11 | integration | ja | platform-core/tests/serviceAi/test_workspace_propagates_settings.py | done |
| T10 | 12 | unit | ja | platform-core/tests/serviceAi/test_effective_models_and_providers.py | done |
| T11 | 13 | unit | ja | platform-core/tests/serviceCenter/test_md_to_json_consolidation.py | done |
| T12 | -- | unit | ja | ui-nyla/src/components/flowEditor/__tests__/AiNodeProperties.test.tsx | deferred |
## Links
- Aktuelle Pipeline-Architektur: Subagent-Report 2026-04-29.
- Renderer-Code: `gateway/modules/serviceCenter/services/serviceGeneration/renderers/`.
- Renderer-Code: `platform-core/modules/serviceCenter/services/serviceGeneration/renderers/`.
- MD->JSON-Code:
`gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`,
`gateway/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`.
- AI-Gate: `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`.
`platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`,
`platform-core/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`.
- AI-Gate: `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`.
- Neutralisierung: `wiki/b-reference/platform/neutralization.md`.
- Wiki: `wiki/b-reference/gateway/ai-agent.md`,
`wiki/b-reference/gateway/agent-file-bridge.md`,
`wiki/b-reference/gateway/workflow.md`.
- Wiki: `wiki/b-reference/platform-core/ai-agent.md`,
`wiki/b-reference/platform-core/agent-file-bridge.md`,
`wiki/b-reference/platform-core/workflow.md`.
## Abschluss
- [ ] `wiki/b-reference/gateway/ai-agent.md` -- Style-System + per-call
- [ ] `wiki/b-reference/platform-core/ai-agent.md` -- Style-System + per-call
Konfiguration ergaenzen (TODO: bei naechster Wiki-Review-Runde)
- [ ] `wiki/b-reference/gateway/workflow.md` -- AI-Node-Standardparameter
- [ ] `wiki/b-reference/platform-core/workflow.md` -- AI-Node-Standardparameter
dokumentieren (TODO: bei naechster Wiki-Review-Runde)
- [ ] `wiki/b-reference/platform/neutralization.md` -- per-Node-Trigger
ergaenzen (TODO: bei naechster Wiki-Review-Runde)

View file

@ -1,6 +1,6 @@
<!-- status: validate -->
<!-- started: 2026-04-12 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# Automatisierung — Zentrale Administration aller Workflows
@ -78,6 +78,6 @@ Die Seite "Automatisierung" in "Meine Sicht" zeigt aktuell nur ein Dashboard mit
## Abschluss
- [x] b-reference/ aktualisiert — [`b-reference/gateway/automation.md`](../../b-reference/gateway/automation.md) (Abschnitt System-Automatisierung)
- [x] b-reference/ aktualisiert — [`b-reference/platform-core/automation.md`](../../b-reference/platform-core/automation.md) (Abschnitt System-Automatisierung)
- [x] TOPICS.md — Verweis unter „Aktive Arbeiten“ ergänzt
- [ ] Dieses Dokument → `z-archive/` verschieben (nach Abnahme / wenn kein offenes Follow-up)

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- status: done -->
<!-- started: 2026-04-05 -->
<!-- completed: 2026-04-07 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Automation Unification -- Konsolidierung v1/v2/Workspace
@ -915,7 +915,7 @@ User konfiguriert Schedule im Editor (via trigger.schedule Node oder Invocation)
## Backend Code-Struktur (Ziel)
```
gateway/modules/
platform-core/modules/
|
+-- features/
| +-- graphicalEditor/ <-- NEUES FEATURE (ersetzt automation2)
@ -964,7 +964,7 @@ gateway/modules/
## Frontend Code-Struktur (umgesetzt)
```
frontend_nyla/src/
ui-nyla/src/
|
+-- components/ <-- SHARED COMPONENTS
| +-- UnifiedDataBar/ <-- BLEIBT (Files + Sources Tabs, Mandate-gefiltert)
@ -1152,11 +1152,11 @@ frontend_nyla/src/
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | gateway/tests/test_automation2_scheduler.py | pending |
| T2 | 2 | integration | ja | gateway/tests/test_agent_toolbox.py | pending |
| T3 | 3 | api | ja | gateway/tests/test_workflow_pause_resume.py | pending |
| T4 | 4 | integration | ja | gateway/tests/test_editor_chat_graph.py | pending |
| T5 | 5 | unit | ja | gateway/tests/test_workflow_versioning.py | pending |
| T1 | 1 | integration | ja | platform-core/tests/test_automation2_scheduler.py | pending |
| T2 | 2 | integration | ja | platform-core/tests/test_agent_toolbox.py | pending |
| T3 | 3 | api | ja | platform-core/tests/test_workflow_pause_resume.py | pending |
| T4 | 4 | integration | ja | platform-core/tests/test_editor_chat_graph.py | pending |
| T5 | 5 | unit | ja | platform-core/tests/test_workflow_versioning.py | pending |
## Glossar
@ -1182,7 +1182,7 @@ frontend_nyla/src/
- Detail-Spec (Business): z-archive/b-reference/automation-business-spec.md
- Detail-Spec (Datenmodell): z-archive/b-reference/automation-data-model.md
- Referenz (Ist-Zusammenfassung): b-reference/gateway/automation.md
- Referenz (Ist-Zusammenfassung): b-reference/platform-core/automation.md
## Abschluss
@ -1201,6 +1201,6 @@ frontend_nyla/src/
- Custom Script Node (Python Sandbox)
- Sub-Agent Pattern fuer weitere Features
- [ ] b-reference/gateway/automation.md aktualisiert
- [ ] b-reference/platform-core/automation.md aktualisiert
- [ ] TOPICS.md aktualisiert
- [ ] Dieses Dokument -> z-archive/ verschoben

View file

@ -3,7 +3,7 @@
<!-- completed: 2026-04-29 -->
<!-- component: gateway -->
<!-- lastReviewed: 2026-04-29 -->
<!-- verifiedAgainst: gateway/modules/interfaces/interfaceBootstrap.py @ HEAD, audit dev 2026-04-29 -->
<!-- verifiedAgainst: platform-core/modules/interfaces/interfaceBootstrap.py @ HEAD, audit dev 2026-04-29 -->
# Bootstrap-Migrations-Cleanup (idempotente Boot-Routinen)
@ -22,12 +22,12 @@ warnt im Boot-Log falls je doch noch Restbestand auftauchen sollte.
## Was wurde gemacht (chronologisch)
1. **Verifikation pro Kandidat** -- Code-Pfade in
`gateway/modules/interfaces/interfaceBootstrap.py` und
`gateway/modules/interfaces/interfaceDbKnowledge.py` neu vermessen.
`platform-core/modules/interfaces/interfaceBootstrap.py` und
`platform-core/modules/interfaces/interfaceDbKnowledge.py` neu vermessen.
Ergebnis: Plan-Annahmen waren teils ungenau (Pfad `system/` statt
`interfaces/`, ganze Funktionen statt einzelner Bloecke); Plan-Tabelle in
`1-plan/` korrigiert vor Removal.
2. **Audit-Skript** `gateway/scripts/script_db_audit_legacy_state.py` (NEU)
2. **Audit-Skript** `platform-core/scripts/script_db_audit_legacy_state.py` (NEU)
- Lese-only fuer 4 Mandate-/Role-Checks (App-DB) + 1 RAG-Check (Knowledge-DB).
- Optional `--purge-rag-orphans` Flag fuer den einzigen Daten-Cleanup.
- Exit-Code 0=GREEN / 1=RED / 2=ERROR fuer CI-Gating.
@ -37,10 +37,10 @@ warnt im Boot-Log falls je doch noch Restbestand auftauchen sollte.
- 1 Check RED: 20 `FileContentIndex`-Rows ohne `mandateId`+`featureInstanceId`
(alte Test-Datei-Reste).
4. **Purge der 20 RAG-Orphans** via `--purge-rag-orphans`. Re-Audit: 5/5 GREEN.
5. **Telemetrie-Helper** `gateway/modules/interfaces/_legacyMigrationTelemetry.py`
5. **Telemetrie-Helper** `platform-core/modules/interfaces/_legacyMigrationTelemetry.py`
(NEU) -- 4 nicht-blockierende SELECT-Checks (gleiche Logik wie Audit-Skript),
prozessweit gecached, Aufruf am Ende von `initBootstrap`. WARN-Log bei Restbestand.
6. **Code-Removals** in `gateway/modules/interfaces/interfaceBootstrap.py`:
6. **Code-Removals** in `platform-core/modules/interfaces/interfaceBootstrap.py`:
- `_migrateMandateDescriptionToLabel` (Funktion + Aufruf) -- weg.
- `_migrateMandateNameLabelSlugRules` (Funktion + Aufruf) -- weg.
- `initRootMandate` Legacy-Block (`recordFilter={"name":"Root"}` + recordModify) -- weg.
@ -50,9 +50,9 @@ warnt im Boot-Log falls je doch noch Restbestand auftauchen sollte.
weg. Funktion bleibt aktiv (4 Caller).
7. **Test-Cleanup** -- folgende Test-Files geloescht (referenzierten entfernte
Funktionen, wuerden ImportError werfen):
- `gateway/tests/unit/bootstrap/test_mandateNameMigration.py` (8 Tests)
- `gateway/tests/unit/rbac/test_sysadmin_migration.py` (5 Tests)
- Verzeichnis `gateway/tests/unit/bootstrap/` ist jetzt leer und entfernt.
- `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py` (8 Tests)
- `platform-core/tests/unit/rbac/test_sysadmin_migration.py` (5 Tests)
- Verzeichnis `platform-core/tests/unit/bootstrap/` ist jetzt leer und entfernt.
8. **Smoke-Tests:** `python -m pytest tests/unit/rbac` -- 17/17 GREEN.
Import-Smoke fuer alle 3 geaenderten Module GREEN.
9. **Telemetrie-Aufruf** in `initBootstrap` als letzten Schritt nach
@ -63,12 +63,12 @@ warnt im Boot-Log falls je doch noch Restbestand auftauchen sollte.
| Datei | Aenderung |
|-------|----------|
| `gateway/modules/interfaces/interfaceBootstrap.py` | -3 Funktionen (~120 Zeilen), -3 Aufrufe, +6 Zeilen Telemetrie-Hook |
| `gateway/modules/interfaces/interfaceDbKnowledge.py` | -27 Zeilen Fallback-Block, vereinfachtes Log-Format |
| `gateway/modules/interfaces/_legacyMigrationTelemetry.py` | NEU (~145 Zeilen) |
| `gateway/scripts/script_db_audit_legacy_state.py` | NEU (~290 Zeilen) |
| `gateway/tests/unit/bootstrap/test_mandateNameMigration.py` | GELOESCHT |
| `gateway/tests/unit/rbac/test_sysadmin_migration.py` | GELOESCHT |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | -3 Funktionen (~120 Zeilen), -3 Aufrufe, +6 Zeilen Telemetrie-Hook |
| `platform-core/modules/interfaces/interfaceDbKnowledge.py` | -27 Zeilen Fallback-Block, vereinfachtes Log-Format |
| `platform-core/modules/interfaces/_legacyMigrationTelemetry.py` | NEU (~145 Zeilen) |
| `platform-core/scripts/script_db_audit_legacy_state.py` | NEU (~290 Zeilen) |
| `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py` | GELOESCHT |
| `platform-core/tests/unit/rbac/test_sysadmin_migration.py` | GELOESCHT |
## Audit-Befund (Dev-DB, 2026-04-29 19:50)
@ -101,7 +101,7 @@ mit Routine-Name + IDs. Dann manuell mit dem Audit-Skript untersuchen.
## Folgearbeiten
- **Scripts-Cleanup -- erledigt 2026-04-29:** 5 one-shot-Scripts in
`gateway/scripts/_archive/` mit README, `_listMandates.py` geloescht.
`platform-core/scripts/_archive/` mit README, `_listMandates.py` geloescht.
Aktiv-Bestand: 21 Scripts inkl. dem neuen `script_db_audit_legacy_state.py`.
- **Telemetrie-Lebenszyklus:** in 30+ Tagen pruefen ob Telemetrie-Helper
Treffer hatte. Wenn 0, `_legacyMigrationTelemetry.py` komplett entfernen.
@ -127,7 +127,7 @@ mit Routine-Name + IDs. Dann manuell mit dem Audit-Skript untersuchen.
## Links
- Audit-Skript: `gateway/scripts/script_db_audit_legacy_state.py`
- Telemetrie: `gateway/modules/interfaces/_legacyMigrationTelemetry.py`
- Audit-Skript: `platform-core/scripts/script_db_audit_legacy_state.py`
- Telemetrie: `platform-core/modules/interfaces/_legacyMigrationTelemetry.py`
- Verwandte Done-Plans: `wiki/c-work/4-done/2026-04-mandate-name-label-logic.md`,
`wiki/c-work/4-done/2026-04-sysadmin-authority-split.md`.

View file

@ -1,7 +1,7 @@
<!-- status: build -->
<!-- started: 2026-04-29 -->
<!-- verified: 2026-05-03 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# ComCoach Greenfield-IA: TrainingModule + Sessions
@ -12,7 +12,7 @@ Die ComCoach-UI ist gewachsen und chaotisch:
- 4 Sidebar-Eintraege (`dashboard`, `coaching`, `dossier`, `settings`),
aber `coaching` und `dossier` rendern die **identische** Komponente
`CommcoachDossierView`
(`frontend_nyla/src/pages/FeatureView.tsx` 168-173).
(`ui-nyla/src/pages/FeatureView.tsx` 168-173).
- RBAC-Definition kennt nur 3 UI-Keys
(`mainCommcoach.py` 19-34) -> Inkonsistenz mit Sidebar.
- Das Dashboard verlinkt mit `?context={id}`, die Dossier-View liest
@ -39,7 +39,7 @@ ComCoach erst zum vermarktbaren Produkt.
ist es immer ein `TrainingModule`. Im UI je nach `moduleType` das
Label anpassen ("Coaching", "Training", "Pruefung", "E-Learning").
- KeepAlive-Mechanismus
(`frontend_nyla/src/pages/views/commcoach/CommcoachKeepAlive.tsx`)
(`ui-nyla/src/pages/views/commcoach/CommcoachKeepAlive.tsx`)
beibehalten -- die Voice-Session darf nicht gekillt werden bei
Sidebar-Wechsel.
- **Bestehendes `goals`-Feld**: `CoachingContext.goals` existiert bereits
@ -66,22 +66,22 @@ ComCoach erst zum vermarktbaren Produkt.
## Betroffene Module
- Gateway:
- `gateway/modules/features/commcoach/datamodelCommcoach.py` --
- `platform-core/modules/features/commcoach/datamodelCommcoach.py` --
`CoachingContext` -> `TrainingModule` (Rename + neue Felder
`kpiTargets jsonb`, `moduleType enum`, `goals text`).
- `gateway/modules/features/commcoach/interfaceFeatureCommcoach.py` --
- `platform-core/modules/features/commcoach/interfaceFeatureCommcoach.py` --
Methoden umbenennen (intern), DB-Migration anwenden.
- `gateway/modules/features/commcoach/routeFeatureCommcoach.py` --
- `platform-core/modules/features/commcoach/routeFeatureCommcoach.py` --
Routes umbenennen `/contexts` -> `/modules` (oder Alias-Periode).
- `gateway/modules/features/commcoach/mainCommcoach.py` -- RBAC-Keys
- `platform-core/modules/features/commcoach/mainCommcoach.py` -- RBAC-Keys
auf neue Tab-Struktur (5 Keys: dashboard, assistant, modules,
session, settings).
- Frontend:
- `frontend_nyla/src/types/mandate.ts` 277-286 -- Sidebar 4 -> 5
- `ui-nyla/src/types/mandate.ts` 277-286 -- Sidebar 4 -> 5
Eintraege.
- `frontend_nyla/src/pages/FeatureView.tsx` 168-173 -- View-Mapping
- `ui-nyla/src/pages/FeatureView.tsx` 168-173 -- View-Mapping
aktualisieren.
- `frontend_nyla/src/pages/views/commcoach/` -- bestehende
- `ui-nyla/src/pages/views/commcoach/` -- bestehende
`CommcoachDossierView` zerlegen in:
- `CommcoachDashboardView` (existiert, KPIs ergaenzen).
- `CommcoachAssistantView` (NEU): Wizard-Flow neues Modul + erste
@ -90,8 +90,8 @@ ComCoach erst zum vermarktbaren Produkt.
- `CommcoachSessionView` (NEU, ehem. coaching-Tab): aktive
Session.
- `CommcoachSettingsView` (existiert, Statistik raus).
- `frontend_nyla/src/api/commcoachApi.ts` -- API-Wrapper aktualisieren.
- `frontend_nyla/src/pages/views/commcoach/CommcoachKeepAlive.tsx` --
- `ui-nyla/src/api/commcoachApi.ts` -- API-Wrapper aktualisieren.
- `ui-nyla/src/pages/views/commcoach/CommcoachKeepAlive.tsx` --
Komponenten-Mapping aktualisieren (Session bleibt KeepAlive).
- DB-Migration: ja -- Rename `CoachingContext` -> `TrainingModule`,
additive Felder.
@ -191,11 +191,11 @@ flowchart LR
### Phase 2 -- Frontend Routing & Sidebar
- [ ] `frontend_nyla/src/types/mandate.ts` 277-286 ComCoach-Eintraege
- [ ] `ui-nyla/src/types/mandate.ts` 277-286 ComCoach-Eintraege
auf 5 Eintraege umstellen.
- [ ] `frontend_nyla/src/App.tsx` 185-187 Routes ergaenzen (`assistant`,
- [ ] `ui-nyla/src/App.tsx` 185-187 Routes ergaenzen (`assistant`,
`modules`, `session`).
- [ ] `frontend_nyla/src/pages/FeatureView.tsx` 168-173 View-Mapping
- [ ] `ui-nyla/src/pages/FeatureView.tsx` 168-173 View-Mapping
auf neue Komponenten.
- [ ] KeepAlive nur noch fuer `session`-Tab konfigurieren.
@ -223,7 +223,7 @@ flowchart LR
### Phase 5 -- Doku
- [ ] Neue b-reference `wiki/b-reference/gateway/features/commcoach.md`
- [ ] Neue b-reference `wiki/b-reference/platform-core/features/commcoach.md`
anlegen.
- [ ] `wiki/TOPICS.md` Eintrag "ComCoach Architecture".
@ -244,22 +244,22 @@ flowchart LR
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | frontend_nyla/src/types/__tests__/mandate.test.ts | pending |
| T2 | 2 | e2e | ja | frontend_nyla/tests/e2e/commcoach-assistant.spec.ts | pending |
| T3 | 3,4 | e2e | ja | frontend_nyla/tests/e2e/commcoach-modules-crud.spec.ts | pending |
| T4 | 5 | e2e | ja | frontend_nyla/tests/e2e/commcoach-dashboard-link.spec.ts | pending |
| T5 | 6 | unit | ja | frontend_nyla/src/pages/views/commcoach/__tests__/CommcoachSettingsView.test.tsx | pending |
| T6 | 7 | integration | ja | gateway/tests/features/commcoach/test_migration_rename.py | pending |
| T1 | 1 | unit | ja | ui-nyla/src/types/__tests__/mandate.test.ts | pending |
| T2 | 2 | e2e | ja | ui-nyla/tests/e2e/commcoach-assistant.spec.ts | pending |
| T3 | 3,4 | e2e | ja | ui-nyla/tests/e2e/commcoach-modules-crud.spec.ts | pending |
| T4 | 5 | e2e | ja | ui-nyla/tests/e2e/commcoach-dashboard-link.spec.ts | pending |
| T5 | 6 | unit | ja | ui-nyla/src/pages/views/commcoach/__tests__/CommcoachSettingsView.test.tsx | pending |
| T6 | 7 | integration | ja | platform-core/tests/features/commcoach/test_migration_rename.py | pending |
| T7 | 8 | manual | nein | -- | pending |
## Links
- Audit-Quelle: Subagent-Report 2026-04-29.
- Aktueller Code:
`gateway/modules/features/commcoach/`,
`frontend_nyla/src/pages/views/commcoach/`.
`platform-core/modules/features/commcoach/`,
`ui-nyla/src/pages/views/commcoach/`.
- Aktuelles Konzept (veraltet):
`gateway/modules/features/commcoach/CONCEPT.md`.
`platform-core/modules/features/commcoach/CONCEPT.md`.
## Iteration: Persona-Management (2026-05-04)
@ -287,20 +287,20 @@ Personas (Gespraechspartner) sind jetzt voll konfigurierbar:
Zeigt Hinweis wenn modulspezifisch konfiguriert.
### Dateien
- `gateway/modules/features/commcoach/serviceCommcoachPersonas.py` (5 neue Personas)
- `gateway/modules/features/commcoach/datamodelCommcoach.py` (ModulePersonaMapping, SetModulePersonasRequest)
- `gateway/modules/features/commcoach/interfaceFeatureCommcoach.py` (3 neue Methoden)
- `gateway/modules/features/commcoach/routeFeatureCommcoach.py` (2 neue Endpoints)
- `gateway/modules/features/commcoach/mainCommcoach.py` (DATA_OBJECTS, RESOURCE_OBJECTS, Migration M8)
- `frontend_nyla/src/api/commcoachApi.ts` (updatePersonaApi, getModulePersonasApi, setModulePersonasApi)
- `frontend_nyla/src/pages/views/commcoach/CommcoachSettingsView.tsx` (Tab-Layout, Persona CRUD)
- `frontend_nyla/src/pages/views/commcoach/CommcoachSettingsView.module.css` (Tab-Styles, Modal)
- `frontend_nyla/src/pages/views/commcoach/CommcoachModulesView.tsx` (Persona-Multi-Select im Edit)
- `frontend_nyla/src/pages/views/commcoach/CommcoachSessionView.tsx` (Persona-Filter nach Modul)
- `platform-core/modules/features/commcoach/serviceCommcoachPersonas.py` (5 neue Personas)
- `platform-core/modules/features/commcoach/datamodelCommcoach.py` (ModulePersonaMapping, SetModulePersonasRequest)
- `platform-core/modules/features/commcoach/interfaceFeatureCommcoach.py` (3 neue Methoden)
- `platform-core/modules/features/commcoach/routeFeatureCommcoach.py` (2 neue Endpoints)
- `platform-core/modules/features/commcoach/mainCommcoach.py` (DATA_OBJECTS, RESOURCE_OBJECTS, Migration M8)
- `ui-nyla/src/api/commcoachApi.ts` (updatePersonaApi, getModulePersonasApi, setModulePersonasApi)
- `ui-nyla/src/pages/views/commcoach/CommcoachSettingsView.tsx` (Tab-Layout, Persona CRUD)
- `ui-nyla/src/pages/views/commcoach/CommcoachSettingsView.module.css` (Tab-Styles, Modal)
- `ui-nyla/src/pages/views/commcoach/CommcoachModulesView.tsx` (Persona-Multi-Select im Edit)
- `ui-nyla/src/pages/views/commcoach/CommcoachSessionView.tsx` (Persona-Filter nach Modul)
## Abschluss
- [ ] `wiki/b-reference/gateway/features/commcoach.md` neu anlegen
- [ ] `wiki/b-reference/platform-core/features/commcoach.md` neu anlegen
- [ ] `wiki/TOPICS.md` Eintrag "ComCoach"
- [ ] `gateway/modules/features/commcoach/CONCEPT.md` aktualisieren
- [ ] `platform-core/modules/features/commcoach/CONCEPT.md` aktualisieren
- [ ] Dieses Dokument -> `z-archive/` verschoben

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-13 -->
<!-- completed: 2026-04-14 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Compliance & Audit View + Navigations-Rubrik "Übersichten"
@ -19,7 +19,7 @@
- Datenschutzbeauftragte brauchen eine Übersicht über alle AI-Datenflüsse pro Mandant.
**Abhängigkeiten:**
- Bestehendes `AuditLogEntry`-System (`gateway/modules/shared/auditLogger.py`) — schreibt bereits Security/GDPR/Permission-Events.
- Bestehendes `AuditLogEntry`-System (`platform-core/modules/shared/auditLogger.py`) — schreibt bereits Security/GDPR/Permission-Events.
- Bestehendes Billing-System (`serviceBilling.recordUsage`) — zeichnet AI-Usage pro Call auf (Provider, Model, Kosten, Bytes).
- Bestehende Integrationsseite (`IntegrationsOverviewPage.tsx`) — wird in neue Rubrik verschoben.
- Navigation-System (`mainSystem.py` → `NAVIGATION_SECTIONS`) — muss um Subgroup erweitert werden.
@ -244,23 +244,23 @@ class AiAuditLogEntry(BaseModel):
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | e2e | nein | Manuell: Navigation prüfen | pending |
| T2 | 2, 3 | api | ja | gateway/tests/audit/test_ai_audit_log.py | pending |
| T3 | 4 | api | ja | gateway/tests/audit/test_audit_log_api.py | pending |
| T2 | 2, 3 | api | ja | platform-core/tests/audit/test_ai_audit_log.py | pending |
| T3 | 4 | api | ja | platform-core/tests/audit/test_audit_log_api.py | pending |
| T4 | 5 | e2e | nein | Manuell: Charts prüfen | pending |
| T5 | 6 | api | ja | gateway/tests/audit/test_audit_rbac.py | pending |
| T6 | 7 | integration | ja | gateway/tests/audit/test_ai_audit_neutralization.py | pending |
| T5 | 6 | api | ja | platform-core/tests/audit/test_audit_rbac.py | pending |
| T6 | 7 | integration | ja | platform-core/tests/audit/test_ai_audit_neutralization.py | pending |
| T7 | 8 | performance | nein | Manuell: Load-Test mit >10k Einträgen | pending |
## Links
- Bestehendes Audit-System: `gateway/modules/shared/auditLogger.py`
- Audit-Datenmodell: `gateway/modules/datamodels/datamodelAudit.py`
- AI-Datenmodell: `gateway/modules/datamodels/datamodelAi.py`
- Billing-Service: `gateway/modules/serviceCenter/services/serviceBilling/mainServiceBilling.py`
- AI-Service: `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`
- Navigation: `gateway/modules/system/mainSystem.py`
- Integrationsseite: `frontend_nyla/src/pages/IntegrationsOverviewPage.tsx`
- Navigation-Rendering: `frontend_nyla/src/components/Navigation/MandateNavigation.tsx`
- Bestehendes Audit-System: `platform-core/modules/shared/auditLogger.py`
- Audit-Datenmodell: `platform-core/modules/datamodels/datamodelAudit.py`
- AI-Datenmodell: `platform-core/modules/datamodels/datamodelAi.py`
- Billing-Service: `platform-core/modules/serviceCenter/services/serviceBilling/mainServiceBilling.py`
- AI-Service: `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`
- Navigation: `platform-core/modules/system/mainSystem.py`
- Integrationsseite: `ui-nyla/src/pages/IntegrationsOverviewPage.tsx`
- Navigation-Rendering: `ui-nyla/src/components/Navigation/MandateNavigation.tsx`
## Abschluss

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-09 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Customer Demo Enablement — Bling, PWG, Quid/ServiceHunter
@ -318,13 +318,13 @@ Das Feature ist vollständig: Playground, Text/Datei-Neutralisierung, Private-LL
- PWG Trustee-Tooling (parallel): `c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md`
- UI-Enhancements (parallel): `c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md`
- INT-Stabilität (parallel): `c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`
- CommCoach-Feature: `gateway/modules/features/commcoach/`
- Neutralisierung-Feature: `gateway/modules/features/neutralization/`
- Trustee-Feature: `gateway/modules/features/trustee/`
- Workspace-Feature: `gateway/modules/features/workspace/`
- CommCoach-Feature: `platform-core/modules/features/commcoach/`
- Neutralisierung-Feature: `platform-core/modules/features/neutralization/`
- Trustee-Feature: `platform-core/modules/features/trustee/`
- Workspace-Feature: `platform-core/modules/features/workspace/`
## Abschluss
- [ ] b-reference/ aktualisiert (ggf. neue Feature-Docs unter `b-reference/gateway/features/`)
- [ ] b-reference/ aktualisiert (ggf. neue Feature-Docs unter `b-reference/platform-core/features/`)
- [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -1,6 +1,6 @@
<!-- status: build -->
<!-- started: 2026-04-09 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Quick Actions — Feature-Dashboard mit One-Click-Aktionen
@ -21,7 +21,7 @@ Treuhandbüros (Bling, PWG) und andere Kunden wünschen sich ein **Cockpit**, vo
### Ist-Zustand: Trustee Dashboard
`frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` zeigt aktuell:
`ui-nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` zeigt aktuell:
- **Stats-Grid:** 4 Kacheln (Positionen, Dokumente, Buchhaltungs-Sync, Rollen)
- **Info-Sektion:** Instanz-Label, Mandant, Buchhaltungssystem
@ -395,7 +395,7 @@ const _navigateToWorkspaceWithPrompt = async (config: QuickActionConfig) => {
| ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status |
|----|----|-----|--------------|---------------------|--------|
| T1 | 1, 5 | api | ja | `gateway/tests/features/trustee/test_quick_actions_api.py` — Endpoint liefert gefilterte Actions pro Rolle | pending |
| T1 | 1, 5 | api | ja | `platform-core/tests/features/trustee/test_quick_actions_api.py` — Endpoint liefert gefilterte Actions pro Rolle | pending |
| T2 | 2 | e2e | nein | Manuell: Card klicken → Workspace öffnet mit Prompt → Agent startet | pending |
| T3 | 3 | e2e | nein | Manuell: Workflow-Card klicken → Workflow läuft → Bestätigung sichtbar | pending |
| T4 | 4 | e2e | nein | Manuell: Link-Card klicken → korrekte Navigation | pending |
@ -419,18 +419,18 @@ const _navigateToWorkspaceWithPrompt = async (config: QuickActionConfig) => {
- Kundenwünsche: `local/notes/use-cases-inputs-customers.md`
- Customer Demo Enablement: `c-work/1-plan/2026-04-customer-demo-enablement.md`
- Trustee Tooling: `c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md`
- Trustee Dashboard (Frontend): `frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx`
- Trustee Feature (Gateway): `gateway/modules/features/trustee/mainTrustee.py`
- Trustee Routes (Gateway): `gateway/modules/features/trustee/routeFeatureTrustee.py`
- Workspace Routes (Gateway): `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- Workspace Page (Frontend): `frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx`
- FeatureView Registry (Frontend): `frontend_nyla/src/pages/FeatureView.tsx`
- Quick Action Board (Frontend, neu): `frontend_nyla/src/components/QuickActionBoard/`
- Trustee Dashboard (Frontend): `ui-nyla/src/pages/views/trustee/TrusteeDashboardView.tsx`
- Trustee Feature (Gateway): `platform-core/modules/features/trustee/mainTrustee.py`
- Trustee Routes (Gateway): `platform-core/modules/features/trustee/routeFeatureTrustee.py`
- Workspace Routes (Gateway): `platform-core/modules/features/workspace/routeFeatureWorkspace.py`
- Workspace Page (Frontend): `ui-nyla/src/pages/views/workspace/WorkspacePage.tsx`
- FeatureView Registry (Frontend): `ui-nyla/src/pages/FeatureView.tsx`
- Quick Action Board (Frontend, neu): `ui-nyla/src/components/QuickActionBoard/`
- Navigation API: `wiki/b-reference/platform/navigation.md`
## Abschluss
- [ ] b-reference/ aktualisiert (`b-reference/gateway/features/trustee.md` — neu anlegen mit Quick Actions)
- [ ] b-reference/frontend-nyla/architecture.md aktualisiert (QuickActionBoard-Komponente)
- [ ] b-reference/ aktualisiert (`b-reference/platform-core/features/trustee.md` — neu anlegen mit Quick Actions)
- [ ] b-reference/ui-nyla/architecture.md aktualisiert (QuickActionBoard-Komponente)
- [ ] TOPICS.md aktualisiert (neues Thema "Quick Actions")
- [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -190,40 +190,40 @@ Der Hauptgrund für die langsame Query-Performance:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | nein (manuell mit Abacus-Sandbox) | — | pending |
| T2 | 2 | api | ja | gateway/tests/features/trustee/test_refresh_tool.py | pending |
| T3 | 3 | api | ja | gateway/tests/features/trustee/test_aggregate_table.py | pending |
| T4 | 4 | api | ja | gateway/tests/serviceAgent/test_feature_data_cache.py | pending |
| T2 | 2 | api | ja | platform-core/tests/features/trustee/test_refresh_tool.py | pending |
| T3 | 3 | api | ja | platform-core/tests/features/trustee/test_aggregate_table.py | pending |
| T4 | 4 | api | ja | platform-core/tests/serviceAgent/test_feature_data_cache.py | pending |
| T5 | 5 | ui | nein (manuell) | — | pending |
| T6 | 6 | e2e | nein (manuell) | — | pending |
| T7 | 7 | api | ja | gateway/tests/workflows/graphicalEditor/test_node_chaining.py | pending |
| T7 | 7 | api | ja | platform-core/tests/workflows/graphicalEditor/test_node_chaining.py | pending |
| T8 | 8 | e2e | nein (manuell) | — | pending |
## Links
- Use Cases: `pamocreate/projects/poweron/customer-pwg/20260407 use-cases-workshop.md`
- Automation Unification (done): `wiki/c-work/3-validate/2026-04-automation-unification.md`
- Trustee Accounting Bridge: `gateway/modules/features/trustee/accounting/accountingBridge.py`
- Accounting Data Sync: `gateway/modules/features/trustee/accounting/accountingDataSync.py`
- Feature Data Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Feature Data Provider: `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py`
- Feature Sub-Agent Tool: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py`
- Toolbox Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- Abacus Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Node Registry: `gateway/modules/features/graphicalEditor/nodeRegistry.py`
- Trustee Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- SharePoint Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- Flow Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/flow.py`
- Action Node Executor: `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py`
- Execution Engine: `gateway/modules/workflows/automation2/executionEngine.py`
- Scheduler: `gateway/modules/workflows/scheduler/mainScheduler.py`
- Trustee Workflow Method: `gateway/modules/workflows/methods/methodTrustee/methodTrustee.py`
- Graphical Editor Feature: `gateway/modules/features/graphicalEditor/mainGraphicalEditor.py`
- Graphical Editor Datenmodell: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
- Trustee Accounting Bridge: `platform-core/modules/features/trustee/accounting/accountingBridge.py`
- Accounting Data Sync: `platform-core/modules/features/trustee/accounting/accountingDataSync.py`
- Feature Data Agent: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Feature Data Provider: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataProvider.py`
- Feature Sub-Agent Tool: `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py`
- Toolbox Registry: `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- Abacus Connector: `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Node Registry: `platform-core/modules/features/graphicalEditor/nodeRegistry.py`
- Trustee Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- SharePoint Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- Flow Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/flow.py`
- Action Node Executor: `platform-core/modules/workflows/automation2/executors/actionNodeExecutor.py`
- Execution Engine: `platform-core/modules/workflows/automation2/executionEngine.py`
- Scheduler: `platform-core/modules/workflows/scheduler/mainScheduler.py`
- Trustee Workflow Method: `platform-core/modules/workflows/methods/methodTrustee/methodTrustee.py`
- Graphical Editor Feature: `platform-core/modules/features/graphicalEditor/mainGraphicalEditor.py`
- Graphical Editor Datenmodell: `platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
## Abschluss
- [x] b-reference/gateway/workflow.md aktualisiert (neue Action `trustee.refreshAccountingData`)
- [x] b-reference/gateway/ai-agent.md aktualisiert (`aggregateTable` Tool im Sub-Agent, Trustee-Toolbox)
- [x] b-reference/gateway/automation.md aktualisiert (neue Trustee-Nodes + Kategorie in Node-Palette)
- [x] b-reference/platform-core/workflow.md aktualisiert (neue Action `trustee.refreshAccountingData`)
- [x] b-reference/platform-core/ai-agent.md aktualisiert (`aggregateTable` Tool im Sub-Agent, Trustee-Toolbox)
- [x] b-reference/platform-core/automation.md aktualisiert (neue Trustee-Nodes + Kategorie in Node-Palette)
- [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-14 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
<!-- merged-from: 2026-04-customer-trustee-demo-enablement.md, 2026-04-customer-trustee-tooling-and-demo-prep.md -->
# Demo2 — Merged Plan: Customer Demo Enablement + Trustee Tooling
@ -90,8 +90,8 @@ Drei potenzielle Kunden haben konkrete Use Cases formuliert. Parallel wurde das
| # | Item | Status | Evidenz in Codebase |
|---|------|--------|---------------------|
| E1 | Fiktives Mieterdossier (PDF) für Neutralisierung | ✅ done | `gateway/demoData/neutralizer/tenant-dossier.pdf` + Generator `_generateTenantDossierPdf.py` |
| E2 | Knowledge-Base Demo-Dateien | ✅ done | `gateway/demoData/knowledge-base/` — 4 Dateien (investor-orientiert) |
| E1 | Fiktives Mieterdossier (PDF) für Neutralisierung | ✅ done | `platform-core/demoData/neutralizer/tenant-dossier.pdf` + Generator `_generateTenantDossierPdf.py` |
| E2 | Knowledge-Base Demo-Dateien | ✅ done | `platform-core/demoData/knowledge-base/` — 4 Dateien (investor-orientiert) |
| E3 | Budget-Excel (Soll-Werte) | ❌ offen | Kein `.xlsx` im gesamten Repo |
| E4 | Musterbelege (Rechnung, Spesen, Bank, Versicherung) | ❌ offen | `demoData/invoices/`, `demoData/expenses/`, `demoData/trustee/` fehlen (Tests erwarten sie) |
| E5 | Quid-Testdaten (CSV: Umsatz, Kunden, Support) | ❌ offen | Keine kundenspezifischen CSV/Excel-Testdaten |
@ -197,7 +197,7 @@ Drei potenzielle Kunden haben konkrete Use Cases formuliert. Parallel wurde das
- Persona `new_tenant_move_in_m`: Luca Steiner, Erstbezug, viele Fragen, kooperativ
- Persona `difficult_neighbor_noise_m`: Kurt Zürcher, Lärmprotokoll, droht mit Mietminderung, Deeskalation nötig
- [ ] **D4: Demo-Config `pwgDemo2026.py`** in `gateway/modules/demoConfigs/`
- [ ] **D4: Demo-Config `pwgDemo2026.py`** in `platform-core/modules/demoConfigs/`
- Mandant "PWG Demo" mit Features: Trustee (Abacus), CommCoach, Neutralisierung, Workspace, Graph-Editor
- Demo-User mit passenden Rollen
- Neutralisierungs-Config analog zu investorDemo
@ -223,15 +223,15 @@ Drei potenzielle Kunden haben konkrete Use Cases formuliert. Parallel wurde das
- [ ] **E3: Budget-Excel** erstellen
- Soll-Werte 2026, 1015 Konten, passend zu Demo-Buchhaltungsdaten
- Ablage: `gateway/demoData/trustee/budget-2026.xlsx`
- Ablage: `platform-core/demoData/trustee/budget-2026.xlsx`
- [ ] **E4: Musterbelege** (PDFs) erstellen
- Handwerkerrechnung, Nebenkostenabrechnung, Bankbeleg, Versicherungsbeleg, Spesenbeleg
- Ablage: `gateway/demoData/invoices/`, `gateway/demoData/expenses/`
- Ablage: `platform-core/demoData/invoices/`, `platform-core/demoData/expenses/`
- [ ] **E5: Quid-Testdaten** (CSV)
- Umsatzdaten 6 Monate, Kundenliste mit Margen, Support-Zeiterfassung
- Ablage: `gateway/demoData/quid/`
- Ablage: `platform-core/demoData/quid/`
### Phase 4: Demo-Workflow & Skripte
@ -304,11 +304,11 @@ Drei potenzielle Kunden haben konkrete Use Cases formuliert. Parallel wurde das
- INT-Stabilität (parallel): `wiki/c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`
- Original-Plan 1: `wiki/c-work/1-plan/2026-04-customer-trustee-demo-enablement.md`
- Original-Plan 2: `wiki/c-work/1-plan/2026-04-customer-trustee-tooling-and-demo-prep.md`
- Investor-Demo (Referenz): `gateway/modules/demoConfigs/investorDemo2026.py`
- CommCoach Personas: `gateway/modules/features/commcoach/serviceCommcoachPersonas.py`
- Trustee Main (Prompts + Quick Actions): `gateway/modules/features/trustee/mainTrustee.py`
- Neutralisierung: `gateway/modules/features/neutralization/`
- Demo-Daten: `gateway/demoData/`
- Investor-Demo (Referenz): `platform-core/modules/demoConfigs/investorDemo2026.py`
- CommCoach Personas: `platform-core/modules/features/commcoach/serviceCommcoachPersonas.py`
- Trustee Main (Prompts + Quick Actions): `platform-core/modules/features/trustee/mainTrustee.py`
- Neutralisierung: `platform-core/modules/features/neutralization/`
- Demo-Daten: `platform-core/demoData/`
## Abschluss

View file

@ -48,7 +48,7 @@ mitgenommen werden:
- Filter `featureCode` Pflicht (sonst 400, sonst Datenflut)
- [x] `_LEGACY_RENDERERS_THAT_HANDLE_BINDINGS` (`NodeConfigPanel.tsx`) erweitert: `'featureInstance'`
#### B2. Trustee-Nodes (5 Stuck) — `gateway/.../nodeDefinitions/trustee.py`
#### B2. Trustee-Nodes (5 Stuck) — `platform-core/.../nodeDefinitions/trustee.py`
| Node | aktuell | neu |
|-------------------------------------|--------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
@ -62,7 +62,7 @@ Alle 5 Nodes umgesetzt via wiederverwendbarem `_TRUSTEE_INSTANCE_PARAM`-Dict
(siehe `trustee.py`). Bestaetigt durch
`tests/unit/graphicalEditor/test_featureInstanceRef_node_definitions.py`.
#### B3. Redmine-Nodes (6 Stuck) — `gateway/.../nodeDefinitions/redmine.py`
#### B3. Redmine-Nodes (6 Stuck) — `platform-core/.../nodeDefinitions/redmine.py`
- [x] `redmine.readTicket`
- [x] `redmine.listTickets`
@ -149,15 +149,15 @@ Alle 6 via `_REDMINE_INSTANCE_PARAM`-Dict, `featureInstanceId` ->
### G. Tests
- [x] `gateway/tests/unit/graphicalEditor/test_featureInstanceRef_node_definitions.py`:
- [x] `platform-core/tests/unit/graphicalEditor/test_featureInstanceRef_node_definitions.py`:
parametrized fuer alle Trustee+Redmine-Nodes — Typ ist
`FeatureInstanceRef[<code>]`, frontendType `featureInstance`,
`frontendOptions.featureCode` korrekt; plus Regression-Guard gegen
Re-Einfuehrung der `string + hidden`-Form (13 Testfaelle)
- [x] `gateway/tests/unit/graphicalEditor/test_route_options_feature_instance.py`:
- [x] `platform-core/tests/unit/graphicalEditor/test_route_options_feature_instance.py`:
Smoke-Test, dass der Endpoint `GET /api/workflows/{instanceId}/options/feature.instance`
registriert ist und `featureCode` Pflicht ist (2 Testfaelle)
- [x] `frontend_nyla/.../paramValidation.test.ts`: neuer Fall
- [x] `ui-nyla/.../paramValidation.test.ts`: neuer Fall
_"skips required params with frontendType='hidden' (UI safety net)"_
- [ ] (Optional, Folge-Iteration) FeatureInstancePicker.test.tsx mit msw
fur 0/1/N-Antworten; aktuell durch das Renderer-Pattern abgedeckt
@ -167,6 +167,6 @@ Alle 6 via `_REDMINE_INSTANCE_PARAM`-Dict, `featureInstanceId` ->
- [x] Track-Doc nach `c-work/4-done/` verschieben
- [x] Eintrag in `c-work/_CHANGELOG.md`
- [ ] (Folge-Aufgabe) `b-reference/gateway/workflow.md` um Abschnitt
- [ ] (Folge-Aufgabe) `b-reference/platform-core/workflow.md` um Abschnitt
_"FeatureInstanceRef adapter binding"_ erweitern; eigenes Mini-Track
oder bei naechster Workflow-Doku-Iteration mitnehmen

View file

@ -1,7 +1,7 @@
<!-- status: done (superseded) -->
<!-- started: 2026-04-29 -->
<!-- completed: 2026-05-15 -->
<!-- component: frontend-nyla | gateway -->
<!-- component: ui-nyla | gateway -->
<!-- note: Original plan (saveGroupTree/groupId/handleGroupingInRequest) was superseded by
View-based GroupLayout strategy (TableListView with groupByLevels + GroupBand response).
The implemented approach uses datamodelPagination.GroupByLevel/GroupBand/GroupLayout
@ -406,8 +406,8 @@ Pro Route: `handleGroupingInRequest` am Anfang + `applyGroupScopeFilter` vor Pag
- [ ] i18n: alle neuen UI-Texte mit `t('...')` getaggt
- [ ] CSS Modules für alle neuen Komponenten
- [ ] `b-reference/frontend-nyla/formgenerator.md` aktualisieren
- [ ] `b-reference/gateway/architecture.md` — `PaginationParams`/`PaginatedResponse`-Erweiterung dokumentieren
- [ ] `b-reference/ui-nyla/formgenerator.md` aktualisieren
- [ ] `b-reference/platform-core/architecture.md` — `PaginationParams`/`PaginatedResponse`-Erweiterung dokumentieren
---
@ -431,8 +431,8 @@ Pro Route: `handleGroupingInRequest` am Anfang + `applyGroupScopeFilter` vor Pag
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|----|--------------|-----------|--------|
| T1 | 1, 2 | api | ja | `gateway/tests/test_grouping_helpers.py` | pending |
| T2 | 3, 4, 5, 6 | api | ja | `gateway/tests/test_grouping_helpers.py` | pending |
| T1 | 1, 2 | api | ja | `platform-core/tests/test_grouping_helpers.py` | pending |
| T2 | 3, 4, 5, 6 | api | ja | `platform-core/tests/test_grouping_helpers.py` | pending |
| T3 | 7 | component | nein | manuell | pending |
| T4 | 8 | api + component | nein | manuell | pending |
| T5 | 9 | component | nein | manuell | pending |
@ -451,8 +451,8 @@ Pro Route: `handleGroupingInRequest` am Anfang + `applyGroupScopeFilter` vor Pag
## Links
- PR: —
- Referenz FormGenerator: `b-reference/frontend-nyla/formgenerator.md`
- Referenz Gateway-Architektur: `b-reference/gateway/architecture.md`
- Referenz FormGenerator: `b-reference/ui-nyla/formgenerator.md`
- Referenz Gateway-Architektur: `b-reference/platform-core/architecture.md`
- Referenz DB-Architektur: `b-reference/platform/database-architecture.md`
---

View file

@ -18,7 +18,7 @@ Beim Aufräumen der `@i18nModel`-Migration (Phase 2) wurde festgestellt, dass me
## Vollständige Liste der Duplikate
Ermittelt per AST-Scan über `gateway/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen):
Ermittelt per AST-Scan über `platform-core/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen):
### Kritisch: Pydantic-Modelle mit `@i18nModel` (i18n-Dict-Kollision)

View file

@ -49,7 +49,7 @@ flowchart LR
### A.1 Inhalt
1. In `gateway/modules/shared/i18nRegistry.py` Funktion **`_registerRbacLabels()`** implementieren (falls noch nicht vorhanden):
1. In `platform-core/modules/shared/i18nRegistry.py` Funktion **`_registerRbacLabels()`** implementieren (falls noch nicht vorhanden):
- Alle Feature-Module mit `DATA_OBJECTS` / `RESOURCE_OBJECTS` durchlaufen (gleiche Modulliste wie bei `_registerFeatureUiLabels` oder erweitern).
- Pro Eintrag: `label` ist **Dict**`key = label.get("de") or label.get("en")` (nicht-leer); `context`:
- `rbac.data` fuer DATA_OBJECTS
@ -63,9 +63,9 @@ flowchart LR
| Datei | Aenderung |
|-------|-----------|
| `gateway/modules/shared/i18nRegistry.py` | `_registerRbacLabels`, Aufruf in `_syncRegistryToDb` |
| `gateway/modules/system/mainSystem.py` | Nur falls DATA/RESOURCE dort noch nicht importiert werden — Scan |
| `gateway/modules/routes/routeI18n.py` | Nur falls Sync-Logik `rbac.*` explizit filtern muss — pruefen |
| `platform-core/modules/shared/i18nRegistry.py` | `_registerRbacLabels`, Aufruf in `_syncRegistryToDb` |
| `platform-core/modules/system/mainSystem.py` | Nur falls DATA/RESOURCE dort noch nicht importiert werden — Scan |
| `platform-core/modules/routes/routeI18n.py` | Nur falls Sync-Logik `rbac.*` explizit filtern muss — pruefen |
### A.3 Abnahme
@ -123,7 +123,7 @@ flowchart LR
### D.1 Inhalt
1. Neuer Endpoint in `gateway/modules/routes/routeI18n.py`, z. B.:
1. Neuer Endpoint in `platform-core/modules/routes/routeI18n.py`, z. B.:
- `POST /api/i18n/translate-field`
- Body: `{ "sourceText": string, "sourceLang": string, "targetLangs": string[] }`
- Response: `{ "translations": { "de": "...", "fr": "..." } }` (ohne Source-Lang)
@ -203,8 +203,8 @@ Rollback: WP-A durch Entfernen des Aufrufs `_registerRbacLabels()` deaktivieren;
## 12. Links
- Konzept & Phase-7-Text: `c-work/2-build/2026-04 gateway-i18n-unified.md`
- i18n Registry: `gateway/modules/shared/i18nRegistry.py`
- i18n API: `gateway/modules/routes/routeI18n.py`
- Formular: `frontend_nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx`
- i18n Registry: `platform-core/modules/shared/i18nRegistry.py`
- i18n API: `platform-core/modules/routes/routeI18n.py`
- Formular: `ui-nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx`

View file

@ -13,7 +13,7 @@ Beim Testen der Applikation auf der **Integrations-Instanz (INT)** mit **mehrere
**Risiko bei Nicht-Umsetzung:** Weiterhin nicht reproduzierbar wirkende Permission-Fehler nach erfolgreicher Verarbeitung, fehlgeschlagene OpenAI-Streaming-Calls wegen Tool-Schema, nutzloser Outlook-Tool-Flow bei UUID-Referenzen, Crashes/Fail-Safe-Sprünge bei Bild-only-Indexierung.
**Abhängigkeiten:** Änderungen betreffen primär `gateway`; keine zwingende Frontend-Änderung, ausser Tool-Beschreibungen/UX explizit angepasst werden.
**Abhängigkeiten:** Änderungen betreffen primär `platform-core`; keine zwingende Frontend-Änderung, ausser Tool-Beschreibungen/UX explizit angepasst werden.
## Fokus und kritische Details
@ -21,14 +21,14 @@ Beim Testen der Applikation auf der **Integrations-Instanz (INT)** mit **mehrere
- **Fragil:** `interfaceDbManagement.getInterface()` liefert eine **gemeinsame** `ComponentObjects`-Instanz (`"default"`); jeder Aufruf setzt `setUserContext` auf demselben Objekt.
- **Edge Case:** Async-Pfade (z. B. `_autoIndexFile` mit `await knowledgeService.indexFile`) — zwischen Start und `updateFile` kann ein anderer Request den Kontext überschreiben → `PermissionError` auf `FileItem.update` trotz erfolgreicher Indexierung.
- **Code:** `gateway/modules/interfaces/interfaceDbManagement.py`, `gateway/modules/routes/routeDataFiles.py` (`_autoIndexFile`).
- **Code:** `platform-core/modules/interfaces/interfaceDbManagement.py`, `platform-core/modules/routes/routeDataFiles.py` (`_autoIndexFile`).
- **Fix:** `_autoIndexFile` holt `mgmtInterface` nach dem letzten `await` frisch. Singleton bleibt bestehen — vollständige Ablösung ist separates Architektur-Thema.
### Thema B — Agent-Tool-JSON-Schema: Arrays ohne `items`
- **Fragil:** `ActionToolAdapter` mappt `List[str]` auf JSON-Schema `type: array` **ohne** `items`.
- **Edge Case:** OpenAI lehnt Tools mit HTTP 400 ab (*array schema missing items*); Failover zu anderen Providern maskiert das Problem.
- **Code:** `gateway/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py`; betroffene Aktion u. a. `ai.process` (`methodAi.py`, Parameter `documentList`).
- **Code:** `platform-core/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py`; betroffene Aktion u. a. `ai.process` (`methodAi.py`, Parameter `documentList`).
- **Fix:** Neues `_ARRAY_ITEMS_MAPPING` ordnet Python-Array-Typen dem korrekten `items`-Schema zu. `_convertParameterSchema` setzt bei `type: "array"` automatisch `items` (Fallback: `{"type": "string"}`).
### Thema C — Outlook: Referenzformat vs. Lookup
@ -41,21 +41,21 @@ Beim Testen der Applikation auf der **Integrations-Instanz (INT)** mit **mehrere
### Thema D — Knowledge: `_neutralSvc` bei nur Bildern
- **Bug:** `_neutralSvc` wird nur im Zweig mit Textobjekten gesetzt; Bild-Neutralisierung nutzt `_neutralSvc` danach — bei **keinen** Textobjekten → `UnboundLocalError` (im Log als fail-safe sichtbar).
- **Code:** `gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` (`indexFile`).
- **Code:** `platform-core/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` (`indexFile`).
- **Fix:** `_neutralSvc` wird vor Text- und Bild-Block initialisiert (`None`), sobald `_shouldNeutralize` wahr ist. Bild-Block prüft `_neutralSvc` in der Bedingung.
### Thema E — Workspace: Mandats-Kontext aus zwei Quellen
- **Fragil:** `_getChatInterface` nutzt `context.mandateId`; `ServiceCenterContext` für den Agent nutzt Mandat aus `_validateInstanceAccess` (Instanz).
- **Edge Case:** Unterschiedliche `interfaceDbChat`-Cache-Keys für „denselben" Workspace → seltene Inkonsistenzen (Workflow sichtbar / nicht sichtbar).
- **Code:** `gateway/modules/features/workspace/routeFeatureWorkspace.py`.
- **Code:** `platform-core/modules/features/workspace/routeFeatureWorkspace.py`.
- **Fix:** `_getChatInterface` akzeptiert optionalen `mandateId`-Parameter. **Alle 34** `_validateInstanceAccess`-Aufrufe entpacken den Return-Wert. Alle `_getChatInterface`- und `ServiceCenterContext`-Aufrufe nutzen die validierte Instanz-`mandateId`.
### Thema F — Chat: `createMessage` / `getWorkflow` → None
- **Fragil:** `getWorkflow` liefert `None` bei leerem RBAC-Recordset **und** bei Exceptions beim Validieren des `ChatWorkflow`-Modells; `createMessage` meldet pauschal „No access to workflow".
- **Edge Case:** Agent-Lauf endet „complete", Persistenz der Assistant-Message schlägt fehl — Ursache ohne besseres Logging schwer trennbar.
- **Code:** `gateway/modules/interfaces/interfaceDbChat.py`.
- **Code:** `platform-core/modules/interfaces/interfaceDbChat.py`.
- **Fix:** `getWorkflow` unterscheidet RBAC-leer (`debug`: "RBAC filter or not found") vs. Validierungsfehler (`error`: "data validation failed"). `createMessage` loggt `warning` mit Verweis auf Ursache.
## Ziel und Nicht-Ziele
@ -111,7 +111,7 @@ Weitere Checkliste aus Template:
| ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status |
|----|----|-----|--------------|---------------------|--------|
| T1 | AC1 | unit | ja | `gateway/tests/...` — `indexFile` mit Mock neutralization, nur image `contentObjects` | pending |
| T1 | AC1 | unit | ja | `platform-core/tests/...` — `indexFile` mit Mock neutralization, nur image `contentObjects` | pending |
| T2 | AC2 | unit | ja | Test: `_buildToolDefinition` / Schema für `ai_process` → assert `properties.documentList.items` | pending |
| T3 | AC3 | unit/integration | ja/teils | `getUserConnectionFromConnectionReference(uuid)` vs. `connection:msft:user@…` | pending |
| T4 | AC4 | integration | empfohlen | Zwei parallele Requests gegen INT oder lokaler Stress-Skript + assert File-Status | pending |
@ -127,5 +127,5 @@ Weitere Checkliste aus Template:
## Abschluss
- [x] Alle Themen AF umgesetzt (2026-04-11)
- [ ] b-reference/ aktualisiert — z. B. `b-reference/gateway/architecture.md` nur wenn Architektur-Entscheid (Singleton) dauerhaft geändert wird
- [ ] b-reference/ aktualisiert — z. B. `b-reference/platform-core/architecture.md` nur wenn Architektur-Entscheid (Singleton) dauerhaft geändert wird
- [ ] TOPICS.md aktualisiert (falls neues Thema)

View file

@ -47,7 +47,7 @@ Jede Node deklariert **typisierte Ports** für Ein- und Ausgänge sowie **Parame
### 2.2 Port-Schema Pydantic-Modelle
**Neue Datei:** `gateway/modules/features/graphicalEditor/portTypes.py`
**Neue Datei:** `platform-core/modules/features/graphicalEditor/portTypes.py`
```python
class PortField(BaseModel):
@ -386,7 +386,7 @@ function GenericNodeConfig({ node, nodeType }) {
## 7 Execution Plan — Backend
### 7.1 NEU: `gateway/modules/features/graphicalEditor/portTypes.py`
### 7.1 NEU: `platform-core/modules/features/graphicalEditor/portTypes.py`
Erstellen. Inhalt:
@ -398,7 +398,7 @@ Erstellen. Inhalt:
- Transit-Envelope-Helpers: `_wrapTransit(data, meta)`, `_unwrapTransit(output)`, `_resolveTransitChain(nodeId, nodeOutputs, connectionMap)`
- Schema-Ableitungsfunktionen: `_deriveFormPayloadSchema(node)`, `_deriveTransformSchema(node)` (Abschnitt 2.5)
### 7.2 ÄNDERN: `gateway/modules/shared/frontendTypes.py`
### 7.2 ÄNDERN: `platform-core/modules/shared/frontendTypes.py`
**Aktuell:** `FrontendType` Enum mit 14 Werten (Zeilen 1663).
@ -420,7 +420,7 @@ Hinzufügen:
`CUSTOM_TYPE_OPTIONS_API` und `CUSTOM_TYPE_DESCRIPTIONS` entsprechend erweitern.
### 7.3 NEU SCHREIBEN: `gateway/modules/features/graphicalEditor/nodeDefinitions/*.py`
### 7.3 NEU SCHREIBEN: `platform-core/modules/features/graphicalEditor/nodeDefinitions/*.py`
Alle 10 Dateien (`triggers.py`, `flow.py`, `input.py`, `ai.py`, `email.py`, `sharepoint.py`, `clickup.py`, `file.py`, `trustee.py`, `__init__.py`) **komplett neu**.
@ -436,7 +436,7 @@ NEU: `data.py` mit `data.aggregate`, `data.transform`, `data.filter`.
`__init__.py`: `STATIC_NODE_TYPES` um `DATA_NODES` erweitern; `flow.py` um `flow.merge` erweitern.
### 7.4 ÄNDERN: `gateway/modules/features/graphicalEditor/nodeRegistry.py`
### 7.4 ÄNDERN: `platform-core/modules/features/graphicalEditor/nodeRegistry.py`
**Funktion `getNodeTypesForApi`** (Zeile 5475):
@ -446,7 +446,7 @@ NEU: `data.py` mit `data.aggregate`, `data.transform`, `data.filter`.
**Funktion `getNodeTypeToMethodAction`** (Zeile 7889): bleibt, `_method`/`_action` weiterhin verwendet.
### 7.5 ÄNDERN: `gateway/modules/workflows/automation2/graphUtils.py`
### 7.5 ÄNDERN: `platform-core/modules/workflows/automation2/graphUtils.py`
**Funktion `resolveParameterReferences`** (Zeile 185243):
@ -461,7 +461,7 @@ if isinstance(value, dict) and value.get("type") == "system":
**Funktion `validateGraph`** (Zeile 86120): erweitern um Port-Kompatibilitäts-Check (soft — Warnings sammeln, nicht hart ablehnen).
### 7.6 NEU SCHREIBEN: `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py`
### 7.6 NEU SCHREIBEN: `platform-core/modules/workflows/automation2/executors/actionNodeExecutor.py`
**Komplett neu.** Die ~860 Zeilen mit heuristischen Merge-Funktionen (`_extractEmailContentFromUpstream`, `_getContextFromUpstream`, `_gatherAttachmentDocumentsFromUpstream`, `_formatEmailOutputAsContext`, `_unpackIncomingEmail`, `_getIncomingEmailFromUpstream`, `_buildActionParams`, `_paramMap`-Logik, etc.) werden **ersetzt** durch:
@ -475,7 +475,7 @@ if isinstance(value, dict) and value.get("type") == "system":
**Keine** node-type-spezifische Logik mehr im Executor.
### 7.7 NEU: `gateway/modules/workflows/automation2/executors/dataExecutor.py`
### 7.7 NEU: `platform-core/modules/workflows/automation2/executors/dataExecutor.py`
Neuer Executor für `data.aggregate`, `data.transform`, `data.filter`:
@ -483,7 +483,7 @@ Neuer Executor für `data.aggregate`, `data.transform`, `data.filter`:
- `data.transform`: wendet `mappings` an (jedes Mapping löst eine DataRef/Static-Referenz auf)
- `data.filter`: evaluiert `condition` pro Item der Input-Liste, gibt gefilterte Liste zurück
### 7.8 ÄNDERN: `gateway/modules/workflows/automation2/executors/flowExecutor.py`
### 7.8 ÄNDERN: `platform-core/modules/workflows/automation2/executors/flowExecutor.py`
**Funktion `_ifElse`** (Zeile 5565): Output ändern zu Transit-Envelope:
@ -501,11 +501,11 @@ return {"_transit": True, "_meta": {"branch": 0 if ok else 1, "conditionResult":
**NEU: `_merge`** Funktion: sammelt Outputs aller verbundenen Input-Ports aus `nodeOutputs`, wendet Modus an (first/all/append), gibt `MergeResult` zurück.
### 7.9 ÄNDERN: `gateway/modules/workflows/automation2/executors/__init__.py`
### 7.9 ÄNDERN: `platform-core/modules/workflows/automation2/executors/__init__.py`
`DataExecutor` importieren und exportieren.
### 7.10 ÄNDERN: `gateway/modules/workflows/automation2/executionEngine.py`
### 7.10 ÄNDERN: `platform-core/modules/workflows/automation2/executionEngine.py`
**Funktion `_getExecutor`** (Zeile 7185): Case für `data.*` hinzufügen → `DataExecutor`.
@ -519,7 +519,7 @@ return {"_transit": True, "_meta": {"branch": 0 if ok else 1, "conditionResult":
**Pause/Resume:** Resume-Handler (`initialNodeOutputs`) — Validierung der User-Eingabe gegen Output-Schema der pausierten Node (in `executeGraph` nach Empfang von `initialNodeOutputs`).
### 7.11 ÄNDERN: `gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
### 7.11 ÄNDERN: `platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
**Funktion `get_node_types`** (Zeile 146168): Response-Struktur erweitern:
@ -540,7 +540,7 @@ return {
## 8 Execution Plan — Frontend
### 8.1 ÄNDERN: `frontend_nyla/src/api/workflowApi.ts`
### 8.1 ÄNDERN: `ui-nyla/src/api/workflowApi.ts`
**Interface `NodeTypeParameter`** (Zeile 1420): erweitern um `frontendType`, `frontendOptions`, `options`, `validation`.
@ -548,7 +548,7 @@ return {
**Interface `NodeTypesResponse`** (Zeile 4649): erweitern um `portTypeCatalog`, `systemVariables`.
### 8.2 LÖSCHEN + NEU: `frontend_nyla/src/components/FlowEditor/nodes/configs/`
### 8.2 LÖSCHEN + NEU: `ui-nyla/src/components/FlowEditor/nodes/configs/`
**Löschen:** `index.ts`, `AiNodeConfig.tsx`, `EmailNodeConfig.tsx`, `SharePointNodeConfig.tsx`, `ClickUpNodeConfig.tsx`, `ApprovalNodeConfig.tsx`, `UploadNodeConfig.tsx`, `CommentNodeConfig.tsx`, `ReviewNodeConfig.tsx`, `SelectionNodeConfig.tsx`, `ConfirmationNodeConfig.tsx`, `FileCreateNodeConfig.tsx`, `TrusteeNodeConfig.tsx`, `types.ts`.
@ -558,7 +558,7 @@ return {
Bestehende Logik aus den gelöschten Config-Components (z.B. ConnectionPicker aus `EmailNodeConfig`, CaseEditor aus `SwitchNodeConfig`, FieldBuilder aus `FormNodeConfig`) wird in die entsprechenden FrontendType-Renderer extrahiert.
### 8.3 ÄNDERN: `frontend_nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx`
### 8.3 ÄNDERN: `ui-nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx`
**Komplett neu.** Statt `NODE_CONFIG_REGISTRY`-Lookup:
@ -572,7 +572,7 @@ nodeType.parameters.map(param => {
});
```
### 8.4 LÖSCHEN: `frontend_nyla/src/components/FlowEditor/nodes/shared/outputPreviewRegistry.ts`
### 8.4 LÖSCHEN: `ui-nyla/src/components/FlowEditor/nodes/shared/outputPreviewRegistry.ts`
Komplett entfernen. Ersetzen durch generische Funktion die aus dem `portTypeCatalog` + `outputPorts` Schema den Preview-Baum baut:
@ -590,7 +590,7 @@ function buildPreviewFromSchema(
}
```
### 8.5 ÄNDERN: `frontend_nyla/src/components/FlowEditor/nodes/shared/dataRef.ts`
### 8.5 ÄNDERN: `ui-nyla/src/components/FlowEditor/nodes/shared/dataRef.ts`
**`DynamicValue` Union** (Zeile 20): erweitern um `SystemVarRef`:
@ -605,23 +605,23 @@ type DynamicValue = DataRef | DataValue | SystemVarRef;
`isRef`, `isValue` etc. ergänzen um `isSystemVar` Type Guard.
### 8.6 ÄNDERN: `frontend_nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx`
### 8.6 ÄNDERN: `ui-nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx`
- `buildPickablePaths` (Zeile 2040): **Schema-basiert** statt aus Preview-Daten. Erhält `portTypeCatalog` und baut Baum aus Schema-Feldern.
- Transit-Auflösung: wenn Output-Schema = Transit, folge connectionMap rückwärts bis zum echten Produzenten.
- Neue Sektion **„System"** mit allen Variablen aus `systemVariables`, gruppiert (Datum/Zeit, User, Workflow).
- Bei Pick eines System-Werts: `onPick` liefert `SystemVarRef` statt `DataRef`.
### 8.7 ÄNDERN: `frontend_nyla/src/components/FlowEditor/context/Automation2DataFlowContext.tsx`
### 8.7 ÄNDERN: `ui-nyla/src/components/FlowEditor/context/Automation2DataFlowContext.tsx`
- `Automation2DataFlowContextValue` (Zeile 1019): erweitern um `portTypeCatalog`, `systemVariables`.
- `nodeOutputsPreview` Berechnung: aus Schema statt aus `outputPreviewRegistry`.
### 8.8 ÄNDERN: `frontend_nyla/src/components/FlowEditor/nodes/shared/graphUtils.ts`
### 8.8 ÄNDERN: `ui-nyla/src/components/FlowEditor/nodes/shared/graphUtils.ts`
`fromApiGraph` / `toApiGraph`: `inputPorts` und `outputPorts` mitserialisieren in `CanvasNode`.
### 8.9 ÄNDERN: `frontend_nyla/src/components/FlowEditor/editor/FlowCanvas` (Verbindungs-Validierung)
### 8.9 ÄNDERN: `ui-nyla/src/components/FlowEditor/editor/FlowCanvas` (Verbindungs-Validierung)
Beim Verbinden zweier Ports: prüfe `sourceNode.outputPorts[outputIdx].schema` gegen `targetNode.inputPorts[inputIdx].accepts`. Bei Mismatch: Kante gelb/orange markieren (Soft-Warnung).
@ -633,62 +633,62 @@ Beim Verbinden zweier Ports: prüfe `sourceNode.outputPorts[outputIdx].schema` g
| Datei | Inhalt |
|-------|--------|
| `gateway/.../graphicalEditor/portTypes.py` | PortSchema, Katalog, Normalizer, Extraktoren, System-Variablen |
| `gateway/.../automation2/executors/dataExecutor.py` | Executor für data.aggregate, data.transform, data.filter |
| `gateway/.../nodeDefinitions/data.py` | Node-Definitionen: data.aggregate, data.transform, data.filter |
| `frontend_nyla/.../nodes/frontendTypeRenderers/index.ts` | FRONTEND_TYPE_RENDERERS Registry |
| `frontend_nyla/.../nodes/frontendTypeRenderers/*.tsx` | Ein Renderer pro FrontendType |
| `platform-core/.../graphicalEditor/portTypes.py` | PortSchema, Katalog, Normalizer, Extraktoren, System-Variablen |
| `platform-core/.../automation2/executors/dataExecutor.py` | Executor für data.aggregate, data.transform, data.filter |
| `platform-core/.../nodeDefinitions/data.py` | Node-Definitionen: data.aggregate, data.transform, data.filter |
| `ui-nyla/.../nodes/frontendTypeRenderers/index.ts` | FRONTEND_TYPE_RENDERERS Registry |
| `ui-nyla/.../nodes/frontendTypeRenderers/*.tsx` | Ein Renderer pro FrontendType |
### Komplett neu geschriebene Dateien
| Datei | Grund |
|-------|-------|
| `gateway/.../automation2/executors/actionNodeExecutor.py` | Heuristische Merge-Logik → Normalizer + Extraktor |
| `gateway/.../nodeDefinitions/triggers.py` | + inputPorts, outputPorts, frontendType |
| `gateway/.../nodeDefinitions/flow.py` | + flow.merge, Transit-Ports |
| `gateway/.../nodeDefinitions/input.py` | + dynamische FormPayload-Schemas |
| `gateway/.../nodeDefinitions/ai.py` | + AiResult-Ports, outputFormat-Param |
| `gateway/.../nodeDefinitions/email.py` | + EmailDraft/EmailList-Ports |
| `gateway/.../nodeDefinitions/sharepoint.py` | + FileList/DocumentList-Ports |
| `gateway/.../nodeDefinitions/clickup.py` | + TaskList/TaskResult-Ports |
| `gateway/.../nodeDefinitions/file.py` | + DocumentList-Ports |
| `gateway/.../nodeDefinitions/trustee.py` | + Ports |
| `gateway/.../nodeDefinitions/__init__.py` | + DATA_NODES Import |
| `frontend_nyla/.../editor/NodeConfigPanel.tsx` | Generischer Renderer statt NODE_CONFIG_REGISTRY |
| `platform-core/.../automation2/executors/actionNodeExecutor.py` | Heuristische Merge-Logik → Normalizer + Extraktor |
| `platform-core/.../nodeDefinitions/triggers.py` | + inputPorts, outputPorts, frontendType |
| `platform-core/.../nodeDefinitions/flow.py` | + flow.merge, Transit-Ports |
| `platform-core/.../nodeDefinitions/input.py` | + dynamische FormPayload-Schemas |
| `platform-core/.../nodeDefinitions/ai.py` | + AiResult-Ports, outputFormat-Param |
| `platform-core/.../nodeDefinitions/email.py` | + EmailDraft/EmailList-Ports |
| `platform-core/.../nodeDefinitions/sharepoint.py` | + FileList/DocumentList-Ports |
| `platform-core/.../nodeDefinitions/clickup.py` | + TaskList/TaskResult-Ports |
| `platform-core/.../nodeDefinitions/file.py` | + DocumentList-Ports |
| `platform-core/.../nodeDefinitions/trustee.py` | + Ports |
| `platform-core/.../nodeDefinitions/__init__.py` | + DATA_NODES Import |
| `ui-nyla/.../editor/NodeConfigPanel.tsx` | Generischer Renderer statt NODE_CONFIG_REGISTRY |
### Geänderte Dateien
| Datei | Änderung |
|-------|----------|
| `gateway/.../shared/frontendTypes.py` | FrontendType Enum erweitern (+10 Werte) |
| `gateway/.../automation2/graphUtils.py` | `resolveParameterReferences` + SystemVar, `validateGraph` + Port-Check |
| `gateway/.../automation2/executors/flowExecutor.py` | ifElse/switch → Transit-Envelope, + _merge |
| `gateway/.../automation2/executors/__init__.py` | + DataExecutor Export |
| `gateway/.../automation2/executionEngine.py` | + DataExecutor, Transit-_meta, aggregate-Akkumulator, merge-Wartelogik |
| `gateway/.../graphicalEditor/nodeRegistry.py` | API-Response + portTypeCatalog, systemVariables |
| `gateway/.../graphicalEditor/routeFeatureGraphicalEditor.py` | Response-Struktur erweitern |
| `frontend_nyla/.../api/workflowApi.ts` | Interfaces erweitern (inputPorts, outputPorts, frontendType) |
| `frontend_nyla/.../nodes/shared/dataRef.ts` | + SystemVarRef |
| `frontend_nyla/.../nodes/shared/DataPicker.tsx` | Schema-basiert, Transit-Auflösung, System-Sektion |
| `frontend_nyla/.../nodes/shared/graphUtils.ts` | inputPorts/outputPorts serialisieren |
| `frontend_nyla/.../context/Automation2DataFlowContext.tsx` | + portTypeCatalog, systemVariables |
| `frontend_nyla/.../editor/FlowCanvas` | Verbindungs-Validierung |
| `platform-core/.../shared/frontendTypes.py` | FrontendType Enum erweitern (+10 Werte) |
| `platform-core/.../automation2/graphUtils.py` | `resolveParameterReferences` + SystemVar, `validateGraph` + Port-Check |
| `platform-core/.../automation2/executors/flowExecutor.py` | ifElse/switch → Transit-Envelope, + _merge |
| `platform-core/.../automation2/executors/__init__.py` | + DataExecutor Export |
| `platform-core/.../automation2/executionEngine.py` | + DataExecutor, Transit-_meta, aggregate-Akkumulator, merge-Wartelogik |
| `platform-core/.../graphicalEditor/nodeRegistry.py` | API-Response + portTypeCatalog, systemVariables |
| `platform-core/.../graphicalEditor/routeFeatureGraphicalEditor.py` | Response-Struktur erweitern |
| `ui-nyla/.../api/workflowApi.ts` | Interfaces erweitern (inputPorts, outputPorts, frontendType) |
| `ui-nyla/.../nodes/shared/dataRef.ts` | + SystemVarRef |
| `ui-nyla/.../nodes/shared/DataPicker.tsx` | Schema-basiert, Transit-Auflösung, System-Sektion |
| `ui-nyla/.../nodes/shared/graphUtils.ts` | inputPorts/outputPorts serialisieren |
| `ui-nyla/.../context/Automation2DataFlowContext.tsx` | + portTypeCatalog, systemVariables |
| `ui-nyla/.../editor/FlowCanvas` | Verbindungs-Validierung |
### Gelöschte Dateien
| Datei | Grund |
|-------|-------|
| `frontend_nyla/.../nodes/configs/index.ts` | Ersetzt durch FRONTEND_TYPE_RENDERERS |
| `frontend_nyla/.../nodes/configs/AiNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/EmailNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/SharePointNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/ClickUpNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/ApprovalNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/UploadNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/CommentNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/ReviewNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/SelectionNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/ConfirmationNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/FileCreateNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/configs/TrusteeNodeConfig.tsx` | Generischer Renderer |
| `frontend_nyla/.../nodes/shared/outputPreviewRegistry.ts` | Schema-basierte Preview |
| `ui-nyla/.../nodes/configs/index.ts` | Ersetzt durch FRONTEND_TYPE_RENDERERS |
| `ui-nyla/.../nodes/configs/AiNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/EmailNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/SharePointNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ClickUpNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ApprovalNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/UploadNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/CommentNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ReviewNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/SelectionNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ConfirmationNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/FileCreateNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/TrusteeNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/shared/outputPreviewRegistry.ts` | Schema-basierte Preview |

View file

@ -1,7 +1,7 @@
<!-- status: build -->
<!-- started: 2026-04-16 -->
<!-- lastReviewed: 2026-04-24 -->
<!-- component: gateway | platform | frontend-nyla -->
<!-- component: gateway | platform | ui-nyla -->
# Unified Knowledge Indexing — One RAG Corpus for All Platform Information
@ -23,7 +23,7 @@
We distinguish **ingestion** (chunking, embedding, persisting into **`interfaceDbKnowledge`**) from **retrieval** (semantic search + `buildAgentContext` for the LLM). **Retrieval** for the **unified knowledge store** is consumed primarily through **`serviceAgent`** / `runAgent` (workspace, graphical editor, CommCoach). Other products (e.g. **chatbot**, **teamsbot**) may use **different** LLM stacks—**Teil 3** maps who gets platform RAG vs who does not. This plan does **not** mandate one global retrieval path for every feature; it **does** mandate a **single ingestion story** into the same corpus where that corpus is used. The gap we address is **how and when** the corpus is **filled**, not how every LLM entry point **reads** it.
### Terminology (Gateway — see `wiki/b-reference/gateway/architecture.md`)
### Terminology (Gateway — see `wiki/b-reference/platform-core/architecture.md`)
This concept separates **feature modules**, **services**, **connectors**, and **interfaces**. Conflating them produces wrong ownership (e.g. treating “SharePoint” as a `modules/features/` product, or treating “mail” as if it were `serviceKnowledge`).
@ -176,9 +176,9 @@ The first end-to-end AC4 test on a 500-page PDF revealed **three** independent b
### 2.2 User connections (added by the user) as first-class ingestion sources — lifecycle and **what to index per connection type**
**Conceptual focus:** The trigger is OAuth success, saved credential, or linked account in **`UserConnection`** that grants access to an external system. **Implementation** still flows through provider code under `gateway/modules/connectors/` (e.g. **`providerMsft`**, **`providerGoogle`**, **`providerClickup`**); that mapping is **technical**, not the product wording.
**Conceptual focus:** The trigger is OAuth success, saved credential, or linked account in **`UserConnection`** that grants access to an external system. **Implementation** still flows through provider code under `platform-core/modules/connectors/` (e.g. **`providerMsft`**, **`providerGoogle`**, **`providerClickup`**); that mapping is **technical**, not the product wording.
**Scope — what counts as a user connection here:** `gateway/modules/routes/routeDataConnections.py` only allows **creating** connections with `type` **`msft`**, **`google`**, or **`clickup`** (`create_connection` → OAuth via `connect_service`). The **authorities options** endpoint also lists **`local`**, but that path is **not** wired in `create_connection`. **This subsection only covers those user-connection authorities** (plus the surfaces each OAuth integration can reach, e.g. Graph mail for Microsoft). Other Gateway connector packages (FTP, Jira, preprocessor, outbound-only mail, geo APIs, …) are **out of scope** in §2.2 until they are exposed the same way as **`UserConnection`** rows.
**Scope — what counts as a user connection here:** `platform-core/modules/routes/routeDataConnections.py` only allows **creating** connections with `type` **`msft`**, **`google`**, or **`clickup`** (`create_connection` → OAuth via `connect_service`). The **authorities options** endpoint also lists **`local`**, but that path is **not** wired in `create_connection`. **This subsection only covers those user-connection authorities** (plus the surfaces each OAuth integration can reach, e.g. Graph mail for Microsoft). Other Gateway connector packages (FTP, Jira, preprocessor, outbound-only mail, geo APIs, …) are **out of scope** in §2.2 until they are exposed the same way as **`UserConnection`** rows.
**Cross-cutting rules (every user-added connection):**
@ -272,7 +272,7 @@ Snapshots should be stored with the same **scope model** as file chunks (`person
**Goal:** The user **explicitly** chooses whether this connection may feed the **shared knowledge store** used for AI/RAG — and **how much**. Without consent, **no** knowledge bootstrap is started for that connection (OAuth may still unlock other product features; that split must be obvious in the UI).
**Frontend (`frontend_nyla`):** extend the **add connection** flow (and later **connection settings**) with the dialog and controls below; persist choices via Gateway API **before** or **when** triggering knowledge ingestion.
**Frontend (`ui-nyla`):** extend the **add connection** flow (and later **connection settings**) with the dialog and controls below; persist choices via Gateway API **before** or **when** triggering knowledge ingestion.
#### UX when adding a connection
@ -356,7 +356,7 @@ These domains **do not** call **`runAgent`** in their **`modules/features/*`** t
### 3.3 Summary matrix (per `modules/features/` domain)
*Matrix verified by audit on 2026-04-21 (P0):* Under `gateway/modules/features/`, only `workspace`, `graphicalEditor`, and `commcoach` resolve `getService("agent")` / `getService("knowledge")` or call `runAgent`; only `commcoach/serviceCommcoachIndexer.py` and `commcoach/serviceCommcoach.py` touch `indexFile` / `buildAgentContext` inside the feature tree. All other domains (`chatbot`, `trustee`, `realEstate`, `teamsbot`, `neutralization`) match the "No" rows below.
*Matrix verified by audit on 2026-04-21 (P0):* Under `platform-core/modules/features/`, only `workspace`, `graphicalEditor`, and `commcoach` resolve `getService("agent")` / `getService("knowledge")` or call `runAgent`; only `commcoach/serviceCommcoachIndexer.py` and `commcoach/serviceCommcoach.py` touch `indexFile` / `buildAgentContext` inside the feature tree. All other domains (`chatbot`, `trustee`, `realEstate`, `teamsbot`, `neutralization`) match the "No" rows below.
| Feature | **`AgentService.runAgent`** | **Retrieval injection** (platform RAG prompt) | **Corpus injection** (typical today) | **Likely gap** (this document) |
|---------|----------------------------|-----------------------------------------------|-------------------------------------|--------------------------------|
@ -414,7 +414,7 @@ Phases align with **Teil 1** (façade), **Teil 2** (connector + trigger catalog)
| **P1a — User-connection hooks (Microsoft `msft`)** *(done, 2026-04-21)* | **`connection.established`** / **`connection.revoked`** emitted from **Microsoft** data-OAuth success paths and from **disconnect/delete** when the row is **`msft`** (incl. **`ConnectionStatus.REVOKED`** fix where **`INACTIVE`** was invalid). Central **`KnowledgeIngestionConsumer`** (`subConnectorIngestConsumer.py`, **`app.py`** lifespan) maps **`established`** → **`connection.bootstrap`** BackgroundJob and **`revoked`** → synchronous **`KnowledgeService.purgeConnection`** → **`interfaceDbKnowledge.deleteFileContentIndexByConnectionId`**. **`FileContentIndex.connectionId`** + **`sourceKind`** (and **`IngestionJob`** carrying both) make connector-sourced rows purgeable. **Bootstrap modules live for Microsoft:** **`subConnectorSyncSharepoint.py`** (`sourceKind="sharepoint_item"`, **`eTag`** as `contentVersion`, **`SharepointAdapter.browse`** with **`@odata.nextLink`** pagination) and **`subConnectorSyncOutlook.py`** (virtual **`outlook_message`** docs — header / snippet / cleaned body via **`cleanEmailBody`**, **`changeKey`** revisions, optional **`outlook_attachment`** child jobs). Dispatcher **`_bootstrapJobHandler`** runs **SharePoint + Outlook in parallel** for **`msft`**. Structured logs: **§ Structured ingestion logs**. **Retrieval threshold calibration (2026-04-21):** **`buildAgentContext`** **`minScore`** layers lowered to **`0.35`** so **`text-embedding-3-small`** matches real cosine scores; validated on **Outlook/SharePointindexed** content. **Tests (P1a):** purge, consumer **msft** dispatch, **`cleanEmailBody`**, **`bootstrapSharepoint`**, **`bootstrapOutlook`**. |
| **P1b — User-connection hooks (Google + ClickUp)** *(done, 2026-04)* | Parity with **`msft`**: **`routeSecurityGoogle`** / **`routeSecurityClickup`** call **`KnowledgeIngestionConsumer.onConnectionEstablished`** after token save; **`routeDataConnections`** disconnect/delete call **`onConnectionRevoked`** for **all** authorities. **`_bootstrapJobHandler`** fans out **google → `bootstrapGdrive` + `bootstrapGmail`** in parallel and **clickup → `bootstrapClickup`**. Walkers: `subConnectorSyncGdrive.py`, `subConnectorSyncGmail.py`, `subConnectorSyncClickup.py` + `subTextClean.py`. Unit tests: `test_bootstrap_gdrive.py`, `test_bootstrap_gmail.py`, `test_bootstrap_clickup.py`, extended `test_knowledge_ingest_consumer.py`. |
| **P1c — Connection refresh (lifecycle v1)** *(next)* | **Daily** (or nightly) **scheduled** re-run of the same bootstrap walkers for connections with **knowledge ingestion enabled** (**§2.6**). Reuses idempotency + fast-path; closes the **post-connect delta gap** without webhooks in v1. Observability: same log family as bootstrap; optional `event` suffix or `reason=scheduled_refresh` for shippers. |
| **P1d — Consent + preferences + UI** *(next)* | Persist **§2.6** settings **per `connectionId`**; Gate **`onConnectionEstablished`** / P1c jobs on user choice; **`frontend_nyla`** connection wizard + settings screen; walkers honor mail/file/ClickUp depth and **neutralization** flag. |
| **P1d — Consent + preferences + UI** *(next)* | Persist **§2.6** settings **per `connectionId`**; Gate **`onConnectionEstablished`** / P1c jobs on user choice; **`ui-nyla`** connection wizard + settings screen; walkers honor mail/file/ClickUp depth and **neutralization** flag. |
| **~~P2 — Profile & mandate snapshots~~** | **Removed from active roadmap** (focus: connections + feature corpus + scale). Target content remains documented in **§2.3** for a future re-entry when needed. |
| **P3 — Event bus** | Move direct calls to async consumer where load requires it (**Teil 2.4** scalable target). Remains in scope. |
@ -438,7 +438,7 @@ Phases align with **Teil 1** (façade), **Teil 2** (connector + trigger catalog)
- [x] **`subConnectorPrefs.py`** — `loadConnectionPrefs(connectionId)` helper + `ConnectionIngestionPrefs` dataclass with safe defaults for all §2.6 keys.
- [x] **All five walkers** (Gmail, GDrive, ClickUp, Outlook, SharePoint) load prefs at bootstrap start; limits structs gain `mailContentDepth` + `neutralize` (mail walkers), `filesIndexBinaries` (Drive), `clickupScope` (ClickUp), and `neutralize` (all).
- [x] **Unit tests** (`test_p1d_consent_prefs.py` — 10 tests): consent gate no-op, prefs defaults + full mapping, Gmail depth modes (metadata/snippet/full), ClickUp scope (titles vs description).
- [x] **Frontend** (`frontend_nyla`): `AddConnectionWizard` 4-step modal (connector → consent → preferences → summary + OAuth); old three-button row replaced with single „Verbindung hinzufügen“ button; `createConnectionAndAuth` hook method; `KnowledgePreferences` type in `connectionApi.ts`.
- [x] **Frontend** (`ui-nyla`): `AddConnectionWizard` 4-step modal (connector → consent → preferences → summary + OAuth); old three-button row replaced with single „Verbindung hinzufügen“ button; `createConnectionAndAuth` hook method; `KnowledgePreferences` type in `connectionApi.ts`.
**Default policy (document for deploy):** `knowledgeIngestionEnabled` defaults to `False` for all new connections. Existing connections (before P1d deploy) have the column `NULL`/`False` — **no bootstrap is triggered retroactively**. Users must explicitly opt in via the wizard or connection settings. If the team decides to migrate existing connections to `True`, a one-time migration script must be run and communicated via release note.
@ -466,8 +466,8 @@ Phases align with **Teil 1** (façade), **Teil 2** (connector + trigger catalog)
- **Gateway:** `serviceKnowledge`, file upload routes, connector OAuth handlers, sync workers, possibly new `serviceKnowledgeIngest` or package under `modules/serviceCenter/services/`.
- **Interfaces:** `interfaceDbKnowledge` extensions for source metadata if needed; **`interfaceDbApp`** (or adjacent) for **per-`connectionId`** ingestion preferences from **§2.6**.
- **Frontend:** `frontend_nyla` — connection wizard + connection detail settings (consent, depth toggles, neutralization, time window).
- **Wiki / Reference:** `b-reference/gateway/ai-agent.md` (ingestion vs. retrieval) after implementation.
- **Frontend:** `ui-nyla` — connection wizard + connection detail settings (consent, depth toggles, neutralization, time window).
- **Wiki / Reference:** `b-reference/platform-core/ai-agent.md` (ingestion vs. retrieval) after implementation.
---
@ -505,12 +505,12 @@ All events should keep field naming consistent with the existing `ingestion.queu
## Links
- **How-to / orientation:** [Unified knowledge & RAG ingestion (guide)](../../d-guides/unified-knowledge-rag.md)
- **Gateway reference (retrieval + knowledge):** `wiki/b-reference/gateway/architecture.md`, `wiki/b-reference/gateway/ai-agent.md`
- **Implementation touchpoints (indicative):** `gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py`, `gateway/modules/routes/routeDataFiles.py`, `gateway/modules/features/commcoach/serviceCommcoachIndexer.py`, agent `coreTools` `_documentTools` / `_workspaceTools`, `gateway/modules/datamodels/datamodelExtraction.py` (`ExtractionOptions.mergeStrategy: Optional[MergeStrategy]`).
- **Unit tests (P0 guardrails):** `gateway/tests/unit/services/test_ingestion_hash_stability.py`, `gateway/tests/unit/services/test_extraction_merge_strategy.py`.
- **Unit tests (P1a — Microsoft, done):** `gateway/tests/unit/services/test_connection_purge.py`, `gateway/tests/unit/services/test_knowledge_ingest_consumer.py` (incl. **msft** fan-out), `gateway/tests/unit/services/test_clean_email_body.py`, `gateway/tests/unit/services/test_bootstrap_sharepoint.py`, `gateway/tests/unit/services/test_bootstrap_outlook.py`.
- **Gateway reference (retrieval + knowledge):** `wiki/b-reference/platform-core/architecture.md`, `wiki/b-reference/platform-core/ai-agent.md`
- **Implementation touchpoints (indicative):** `platform-core/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py`, `platform-core/modules/routes/routeDataFiles.py`, `platform-core/modules/features/commcoach/serviceCommcoachIndexer.py`, agent `coreTools` `_documentTools` / `_workspaceTools`, `platform-core/modules/datamodels/datamodelExtraction.py` (`ExtractionOptions.mergeStrategy: Optional[MergeStrategy]`).
- **Unit tests (P0 guardrails):** `platform-core/tests/unit/services/test_ingestion_hash_stability.py`, `platform-core/tests/unit/services/test_extraction_merge_strategy.py`.
- **Unit tests (P1a — Microsoft, done):** `platform-core/tests/unit/services/test_connection_purge.py`, `platform-core/tests/unit/services/test_knowledge_ingest_consumer.py` (incl. **msft** fan-out), `platform-core/tests/unit/services/test_clean_email_body.py`, `platform-core/tests/unit/services/test_bootstrap_sharepoint.py`, `platform-core/tests/unit/services/test_bootstrap_outlook.py`.
- **Unit tests (P1b — Google + ClickUp, done):** **`test_knowledge_ingest_consumer`** (google / clickup fan-out), **`test_bootstrap_gmail.py`**, **`test_bootstrap_gdrive.py`**, **`test_bootstrap_clickup.py`**. **P1d (done):** **`test_p1d_consent_prefs.py`** (10 tests: consent gate, prefs parsing, Gmail depth modes, ClickUp scope). **P1c:** add scheduler tests when implemented.
- **P1 implementation touchpoints:** `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncSharepoint.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncOutlook.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncGdrive.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncGmail.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncClickup.py`, `gateway/modules/serviceCenter/services/serviceKnowledge/subTextClean.py`, `gateway/modules/interfaces/interfaceDbKnowledge.py` (`deleteFileContentIndexByConnectionId`), `gateway/modules/datamodels/datamodelKnowledge.py` (`FileContentIndex.connectionId` + `sourceKind`), `gateway/modules/connectors/providerMsft/connectorMsft.py` (`@odata.nextLink`-loop in `SharepointAdapter.browse`, `eTag` in `_graphItemToExternalEntry`), `gateway/modules/connectors/providerGoogle/connectorGoogle.py` (P1b: Drive + Gmail revision keys and download/export paths), `gateway/modules/routes/routeSecurityMsft.py` (P1a callbacks), `gateway/modules/routes/routeSecurityGoogle.py` and `gateway/modules/routes/routeSecurityClickup.py` (P1b: parity callbacks), `gateway/modules/routes/routeDataConnections.py` (revoke for **all** authorities), `gateway/app.py` (consumer registration in lifespan).
- **P1 implementation touchpoints:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncSharepoint.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncOutlook.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncGdrive.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncGmail.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSyncClickup.py`, `platform-core/modules/serviceCenter/services/serviceKnowledge/subTextClean.py`, `platform-core/modules/interfaces/interfaceDbKnowledge.py` (`deleteFileContentIndexByConnectionId`), `platform-core/modules/datamodels/datamodelKnowledge.py` (`FileContentIndex.connectionId` + `sourceKind`), `platform-core/modules/connectors/providerMsft/connectorMsft.py` (`@odata.nextLink`-loop in `SharepointAdapter.browse`, `eTag` in `_graphItemToExternalEntry`), `platform-core/modules/connectors/providerGoogle/connectorGoogle.py` (P1b: Drive + Gmail revision keys and download/export paths), `platform-core/modules/routes/routeSecurityMsft.py` (P1a callbacks), `platform-core/modules/routes/routeSecurityGoogle.py` and `platform-core/modules/routes/routeSecurityClickup.py` (P1b: parity callbacks), `platform-core/modules/routes/routeDataConnections.py` (revoke for **all** authorities), `platform-core/app.py` (consumer registration in lifespan).
## Akzeptanzkriterien (Plan-Ebene)

View file

@ -4,7 +4,7 @@
<!-- pivoted: 2026-04-28 (Mail-Endpoint nicht PAT-faehig -> Calendar als zweiter aktiver Service) -->
<!-- pivoted: 2026-04-28 (Contacts-PIM-Endpoint funktioniert -> Contacts als dritter aktiver Service) -->
<!-- pivoted: 2026-04-29 (kDrive-Listing fuer non-admin-User leer -> `/2/drive/init?with=drives` als Discovery) -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Infomaniak Connector (kDrive + Calendar + Contacts today; Mail reserved) + UDB-Integration
@ -195,7 +195,7 @@ aussortiert wurde:
- `modules/routes/routeSecurityInfomaniak.py` (komplett neu: PAT-Submit-Endpoint)
- `modules/routes/routeDataConnections.py` (`connect_service` antwortet bei
Infomaniak mit 400 + Hinweis)
- `gateway/.env` + `env_dev/int/prod[_forgejo].env` (Service_INFOMANIAK_* raus)
- `platform-core/.env` + `env_dev/int/prod[_forgejo].env` (Service_INFOMANIAK_* raus)
- Frontend:
- `src/api/connectionApi.ts` (`submitInfomaniakToken` neu)
- `src/hooks/useConnections.ts` (`createInfomaniakConnection` +

View file

@ -1,6 +1,6 @@
<!-- status: build -->
<!-- started: 2026-04-12 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Investor-Demo Dienstag — Live Product Demo (20 Min)
@ -173,7 +173,7 @@
### Phase 1: Demo-Daten (Mo Vormittag)
- [ ] RMA-Credentials in `gateway/config.ini`
- [ ] RMA-Credentials in `platform-core/config.ini`
- [ ] Demo-Config laden: `/admin/demo-config` → Load
- [ ] Testdaten prüfen:
- `demoData/invoices/` — 3 Muster-Rechnungen (PDF)
@ -228,7 +228,7 @@
### Architektur
```
gateway/tests/demo/
platform-core/tests/demo/
├── conftest.py # Demo-Fixtures, DB-Setup
├── test_demo_bootstrap.py # Bootstrap idempotent
├── test_demo_uc1_trustee.py # Beleg → Extraktion → Kontierung
@ -240,7 +240,7 @@ gateway/tests/demo/
```
```bash
cd gateway/
cd platform-core/
# Alle (ohne AI-Calls):
pytest tests/demo/ -v -m "not expensive"
@ -268,9 +268,9 @@ pytest tests/demo/ -v
## Links
- Keynote: `local/notes/use-cases-DEMO-TUE.md`
- Bootstrap: `gateway/modules/interfaces/interfaceBootstrap.py`
- Demo-Config: `gateway/modules/demoConfigs/investorDemo2026.py`
- Test-Suite: `gateway/tests/demo/`
- Bootstrap: `platform-core/modules/interfaces/interfaceBootstrap.py`
- Demo-Config: `platform-core/modules/demoConfigs/investorDemo2026.py`
- Test-Suite: `platform-core/tests/demo/`
## Abschluss

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-18 -->
<!-- completed: 2026-04-18 -->
<!-- component: gateway, frontend-nyla, platform -->
<!-- component: gateway, ui-nyla, platform -->
# Mandate `name` (Kurzzeichen) und `label` (Voller Name) Logik
@ -30,7 +30,7 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
- **`isSystem`-Mandate:** Root-Mandant darf nicht versehentlich umbenannt werden — bestehende Sicherung greift bereits über `frontend_readonly` und das Warning-Banner.
- **UI-Stellen mit `mandate.name` als technischer Identifier** (Delete-Confirm, X-Confirm-Name) bleiben semantisch korrekt — `name` IST hier der technische Identifier und das ist gewollt.
- **i18n:** Die Label-Texte ("Kurzzeichen", "Voller Name") müssen via `t()` übersetzbar bleiben; kein hartkodiertes Deutsch in Frontend-Komponenten.
- **TypeScript-Typen:** `frontend_nyla/src/types/mandate.ts` und `useMandates`-Hook müssen mitgepflegt werden.
- **TypeScript-Typen:** `ui-nyla/src/types/mandate.ts` und `useMandates`-Hook müssen mitgepflegt werden.
## Ziel und Nicht-Ziele
@ -55,18 +55,18 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
## Betroffene Module
- **Gateway:**
- `gateway/modules/datamodels/datamodelUam.py` (`Mandate` Pydantic-Klasse)
- `gateway/modules/interfaces/interfaceDbApp.py` (`createMandate`, `_provisionMandateForUser`, `updateMandate`, NEU: `_generateUniqueMandateName`)
- `gateway/modules/routes/routeDataMandates.py` (POST/PUT-Validierung)
- `gateway/modules/routes/routeSecurityLocal.py` (3 Aufrufstellen `_provisionMandateForUser`)
- `gateway/modules/interfaces/interfaceBootstrap.py` (Migrations-Hook beim Boot)
- NEU: `gateway/modules/shared/mandateNameUtils.py` (Slug-Helpers, Validierung, Transliteration)
- `platform-core/modules/datamodels/datamodelUam.py` (`Mandate` Pydantic-Klasse)
- `platform-core/modules/interfaces/interfaceDbApp.py` (`createMandate`, `_provisionMandateForUser`, `updateMandate`, NEU: `_generateUniqueMandateName`)
- `platform-core/modules/routes/routeDataMandates.py` (POST/PUT-Validierung)
- `platform-core/modules/routes/routeSecurityLocal.py` (3 Aufrufstellen `_provisionMandateForUser`)
- `platform-core/modules/interfaces/interfaceBootstrap.py` (Migrations-Hook beim Boot)
- NEU: `platform-core/modules/shared/mandateNameUtils.py` (Slug-Helpers, Validierung, Transliteration)
- **Frontend:**
- `frontend_nyla/src/types/mandate.ts`
- `frontend_nyla/src/hooks/useMandates.ts`
- `frontend_nyla/src/pages/admin/AdminMandatesPage.tsx` (Modal-Texte, Subtitle)
- `frontend_nyla/src/pages/admin/AdminUserAccessOverviewPage.tsx` (Anzeige `name (label)``label (name)`)
- `frontend_nyla/src/components/FormGenerator/...` (Live-strict-Validierung für Slug-Type, falls neuer `frontend_type: "slug"` eingeführt)
- `ui-nyla/src/types/mandate.ts`
- `ui-nyla/src/hooks/useMandates.ts`
- `ui-nyla/src/pages/admin/AdminMandatesPage.tsx` (Modal-Texte, Subtitle)
- `ui-nyla/src/pages/admin/AdminUserAccessOverviewPage.tsx` (Anzeige `name (label)``label (name)`)
- `ui-nyla/src/components/FormGenerator/...` (Live-strict-Validierung für Slug-Type, falls neuer `frontend_type: "slug"` eingeführt)
- Display-Audit aller `m.label || m.name`-Stellen (Sicherstellen, dass Reihenfolge korrekt ist)
- **DB-Migration:** ja (idempotent in Bootstrap, kein Alembic — passt zum Projekt-Pattern)
- **Andere Komponenten:** keine
@ -90,8 +90,8 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
## Umsetzungs-Checkliste
### Phase 1 — Shared Utilities
- [x] `gateway/modules/shared/mandateNameUtils.py` mit Transliteration, Slugify, Validierung
- [x] Tests: `gateway/tests/unit/shared/test_mandateNameUtils.py`
- [x] `platform-core/modules/shared/mandateNameUtils.py` mit Transliteration, Slugify, Validierung
- [x] Tests: `platform-core/tests/unit/shared/test_mandateNameUtils.py`
### Phase 2 — Pydantic-Modell
- [x] `Mandate.name`: json_schema_extra `Kurzzeichen`, `frontend_type: "slug"`, `pattern`, `min_length`/`max_length`
@ -111,7 +111,7 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
### Phase 5 — Migration in Bootstrap
- [x] `_migrateMandateNameLabelSlugRules` idempotent in `initBootstrap`
- [x] Tests: `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`
- [x] Tests: `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`
### Phase 6 — Frontend Modell + Hook
- [x] `types/mandate.ts`: `label: string` (mandatory) + Doc
@ -121,7 +121,7 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
### Phase 7 — FormGenerator: `slug`-Type
- [x] `slug` in `attributeTypeMapper.ts` (mapped auf `text`)
- [x] `FormGeneratorForm` Slug-Render: Live-Masking, Hint, Validierung, Auto-Vorschlag aus konfigurierbarer `slugSource` (default `label`)
- [x] **Korrektur**: generische Logik in `frontend_nyla/src/utils/slugUtils.ts` ausgelagert; `mandateNameUtils.ts` ist dünner Wrapper. FormGenerator bleibt domain-agnostisch.
- [x] **Korrektur**: generische Logik in `ui-nyla/src/utils/slugUtils.ts` ausgelagert; `mandateNameUtils.ts` ist dünner Wrapper. FormGenerator bleibt domain-agnostisch.
### Phase 8 — UI Display Konsistenz
- [x] `mandateDisplayUtils.ts` (`mandateDisplayLabel`, `mandateDisplayLineLabelThenSlug`)
@ -161,13 +161,13 @@ Heute existieren am `Mandate`-Modell die Felder `name` und `label` ohne klare Tr
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|---------------|-----------|--------|
| T1 | -- | unit | ja | `gateway/tests/unit/shared/test_mandateNameUtils.py` | done (7) |
| T2 | 1, 2 | integration | ja | `gateway/tests/integration/mandates/test_createMandate.py` | done (12) |
| T3 | 3, 4 | integration | ja | `gateway/tests/integration/mandates/test_updateMandate.py` | done (12) |
| T4 | 5, 6 | integration | ja | `gateway/tests/unit/bootstrap/test_mandateNameMigration.py` | done (9) |
| T1 | -- | unit | ja | `platform-core/tests/unit/shared/test_mandateNameUtils.py` | done (7) |
| T2 | 1, 2 | integration | ja | `platform-core/tests/integration/mandates/test_createMandate.py` | done (12) |
| T3 | 3, 4 | integration | ja | `platform-core/tests/integration/mandates/test_updateMandate.py` | done (12) |
| T4 | 5, 6 | integration | ja | `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py` | done (9) |
| T5 | 7, 8 | manual | nein | Frontend Smoke-Test AdminMandatesPage | done |
| T6 | 9 | manual | nein | Frontend Smoke-Test AdminUserAccessOverviewPage | done |
| T7 | 10 | integration | ja | `gateway/tests/integration/mandates/test_provisionMandate.py` | done (9) |
| T7 | 10 | integration | ja | `platform-core/tests/integration/mandates/test_provisionMandate.py` | done (9) |
| T8 | -- | covered by T2/T3 | -- | -- | n/a (Pydantic-Validators implizit getestet) |
## Links

View file

@ -1,6 +1,6 @@
<!-- status: build -->
<!-- started: 2026-04-28 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# MSFT- und Google-Connector: CalendarAdapter + ContactsAdapter, plus Reconnect-Button

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-20 -->
<!-- finished: 2026-04-20 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Statistik-Endpunkte: Clean-Cut auf `dateFrom`/`dateTo` + `bucketSize`
@ -44,7 +44,7 @@ kein toleranter Fallback im Backend.
`dateFrom` -> `00:00:00 UTC` desselben Tages, `dateTo` -> `23:59:59.999 UTC`
desselben Tages (inklusive). Sonst fehlt der letzte Tag in der Aggregation.
→ Ein gemeinsamer Helper `_isoDateRangeToUtcEpoch(dateFrom, dateTo)` in
`gateway/modules/shared/dateRange.py`.
`platform-core/modules/shared/dateRange.py`.
- **Validierung im Backend**: `dateFrom <= dateTo`, beide Pflicht (kein
optional/None), `bucketSize` aus geschlossenem Enum. Bei Verletzung HTTP 400
mit klarer Message. Keine impliziten Defaults.
@ -79,30 +79,30 @@ kein toleranter Fallback im Backend.
## Betroffene Module
- **Gateway:**
- `gateway/modules/routes/routeAudit.py` (`getAuditStats`, Z. 303-317)
- `gateway/modules/shared/aiAuditLogger.py` (`getAiAuditStats`, Z. 195-249)
- `gateway/modules/routes/routeBilling.py`
- `platform-core/modules/routes/routeAudit.py` (`getAuditStats`, Z. 303-317)
- `platform-core/modules/shared/aiAuditLogger.py` (`getAiAuditStats`, Z. 195-249)
- `platform-core/modules/routes/routeBilling.py`
(`getStatistics` Z. 526-604, `getUserViewStatistics` Z. 1619 ff.,
`UsageReportResponse` Z. 260)
- `gateway/modules/interfaces/interfaceBilling.py` (oder konkrete Impl):
- `platform-core/modules/interfaces/interfaceBilling.py` (oder konkrete Impl):
`calculateStatisticsFromTransactions` (akzeptiert bereits `startDate`/`endDate`
→ keine Aenderung), `getTransactionStatisticsAggregated`
(`period` → `bucketSize`).
- **Neu**: `gateway/modules/shared/dateRange.py` - kleiner Helper
- **Neu**: `platform-core/modules/shared/dateRange.py` - kleiner Helper
`parseIsoDateRange(dateFrom, dateTo) -> (date, date)` mit Validierung,
`isoDateRangeToUtcEpoch(dateFrom, dateTo) -> (float, float)`.
- **Frontend:**
- `frontend_nyla/src/api/billingApi.ts` (`fetchStatistics`,
- `ui-nyla/src/api/billingApi.ts` (`fetchStatistics`,
`fetchViewStatistics`)
- `frontend_nyla/src/hooks/useBilling.ts` (`loadStatistics` Signatur
- `ui-nyla/src/hooks/useBilling.ts` (`loadStatistics` Signatur
aendern)
- `frontend_nyla/src/pages/billing/BillingDashboard.tsx` (Selects raus,
- `ui-nyla/src/pages/billing/BillingDashboard.tsx` (Selects raus,
PeriodPicker rein, optional separater `bucketSize`-Toggle)
- `frontend_nyla/src/pages/billing/BillingDataView.tsx`
- `ui-nyla/src/pages/billing/BillingDataView.tsx`
(FormGeneratorReport: `periodSelector` raus, `dateRangeSelector` rein)
- `frontend_nyla/src/pages/ComplianceAuditPage.tsx`: `_periodToDays`
- `ui-nyla/src/pages/ComplianceAuditPage.tsx`: `_periodToDays`
entfernen, `_loadStats({ dateFrom, dateTo })`.
- `frontend_nyla/src/api/auditApi.ts` (oder direkt in der Page, je nach
- `ui-nyla/src/api/auditApi.ts` (oder direkt in der Page, je nach
aktueller Struktur).
- **DB-Migration:** nein.
- **Tests:** Vorhandene Tests auf den 3 Endpunkten mitziehen (siehe
@ -111,12 +111,12 @@ kein toleranter Fallback im Backend.
## Externe Konsumenten - Pruefung
Vor Clean-Cut explizit verifizieren, dass keine externen Aufrufer
(Webhooks, Skripte, Excel-Reports, Teams-Bot, private-llm) die Endpunkte
(Webhooks, Skripte, Excel-Reports, Teams-Bot, service-llm-private) die Endpunkte
direkt nutzen:
- [ ] `rg "billing/statistics" gateway/ private-llm/ teams-bot/`
- [ ] `rg "audit/stats" gateway/ private-llm/ teams-bot/`
- [ ] `rg "/api/billing/statistics|/api/audit/stats" frontend_nyla/`
- [ ] `rg "billing/statistics" platform-core/ service-llm-private/ teams-bot/`
- [ ] `rg "audit/stats" platform-core/ service-llm-private/ teams-bot/`
- [ ] `rg "/api/billing/statistics|/api/audit/stats" ui-nyla/`
Wenn Treffer ausserhalb des Frontends auftauchen, werden sie im selben PR
mitgezogen. Wenn nicht, kann der Clean-Cut erfolgen.
@ -137,7 +137,7 @@ mitgezogen. Wenn nicht, kann der Clean-Cut erfolgen.
### A. Vorbereitung (~30 min)
- [ ] Konsumenten-Pruefung wie oben (drei `rg`-Aufrufe).
- [ ] `gateway/modules/shared/dateRange.py` anlegen mit
- [ ] `platform-core/modules/shared/dateRange.py` anlegen mit
`parseIsoDateRange(dateFrom: str, dateTo: str) -> tuple[date, date]`
(HTTP 400 bei ungueltig oder `from > to`) und
`isoDateRangeToUtcEpoch(dateFrom: str, dateTo: str) -> tuple[float, float]`.
@ -199,10 +199,10 @@ mitgezogen. Wenn nicht, kann der Clean-Cut erfolgen.
### E. Tests (~1 h)
- [ ] `gateway/tests/test_routeAudit.py` aktualisieren: alte `timeRange`-Tests
- [ ] `platform-core/tests/test_routeAudit.py` aktualisieren: alte `timeRange`-Tests
ersetzen durch `dateFrom`/`dateTo`-Tests (positiv + 400 bei from>to + 400
bei missing).
- [ ] `gateway/tests/test_routeBilling.py` aktualisieren: alte `period+year+month`-Tests
- [ ] `platform-core/tests/test_routeBilling.py` aktualisieren: alte `period+year+month`-Tests
ersetzen.
- [ ] Unit-Tests fuer `dateRange.py`-Helper (Parsing, Timezone, Inklusivitaet
des letzten Tages).
@ -224,12 +224,12 @@ mitgezogen. Wenn nicht, kann der Clean-Cut erfolgen.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 2 | api | ja | `gateway/tests/test_routeBilling.py::test_getStatistics_dateRange_dayBucket` | pending |
| T2 | 3 | api | ja | `gateway/tests/test_routeBilling.py::test_getStatistics_invertedRange_400` | pending |
| T3 | 4 | api | ja | `gateway/tests/test_routeBilling.py::test_getStatistics_missingBucketSize_400` | pending |
| T4 | 5 | api | ja | `gateway/tests/test_routeAudit.py::test_getAuditStats_dateRange` | pending |
| T5 | 6 | api | ja | `gateway/tests/test_routeAudit.py::test_getAuditStats_legacyParam_rejected` | pending |
| T6 | - | unit | ja | `gateway/tests/test_dateRange.py::test_inclusive_endOfDay` | pending |
| T1 | 2 | api | ja | `platform-core/tests/test_routeBilling.py::test_getStatistics_dateRange_dayBucket` | pending |
| T2 | 3 | api | ja | `platform-core/tests/test_routeBilling.py::test_getStatistics_invertedRange_400` | pending |
| T3 | 4 | api | ja | `platform-core/tests/test_routeBilling.py::test_getStatistics_missingBucketSize_400` | pending |
| T4 | 5 | api | ja | `platform-core/tests/test_routeAudit.py::test_getAuditStats_dateRange` | pending |
| T5 | 6 | api | ja | `platform-core/tests/test_routeAudit.py::test_getAuditStats_legacyParam_rejected` | pending |
| T6 | - | unit | ja | `platform-core/tests/test_dateRange.py::test_inclusive_endOfDay` | pending |
| T7 | 1, 8 | manuell | nein | `BillingDashboard` smoke | pending |
| T8 | 7 | manuell | nein | `ComplianceAuditPage` smoke + grep `_periodToDays` muss leer sein | pending |
@ -250,17 +250,17 @@ Commit). Empfohlene lokale Arbeits-Reihenfolge:
- Vorarbeit: PeriodPicker-Komponente + Schritt-1+2-Rollout (Changelog
2026-04-20)
- Code-Anker:
- `gateway/modules/routes/routeAudit.py:303`
- `gateway/modules/shared/aiAuditLogger.py:195`
- `gateway/modules/routes/routeBilling.py:526`
- `gateway/modules/routes/routeBilling.py:1619`
- `frontend_nyla/src/pages/billing/BillingDashboard.tsx` (`selectedPeriod`)
- `frontend_nyla/src/pages/billing/BillingDataView.tsx` (`_loadViewStatistics`)
- `frontend_nyla/src/pages/ComplianceAuditPage.tsx` (`_periodToDays`)
- `platform-core/modules/routes/routeAudit.py:303`
- `platform-core/modules/shared/aiAuditLogger.py:195`
- `platform-core/modules/routes/routeBilling.py:526`
- `platform-core/modules/routes/routeBilling.py:1619`
- `ui-nyla/src/pages/billing/BillingDashboard.tsx` (`selectedPeriod`)
- `ui-nyla/src/pages/billing/BillingDataView.tsx` (`_loadViewStatistics`)
- `ui-nyla/src/pages/ComplianceAuditPage.tsx` (`_periodToDays`)
## Abschluss
- [ ] `b-reference/gateway/billing.md` Statistik-Section neu schreiben
- [ ] `b-reference/platform-core/billing.md` Statistik-Section neu schreiben
(`dateFrom`/`dateTo`/`bucketSize`).
- [ ] `b-reference/platform/audit.md` Stats-Section neu schreiben.
- [ ] TOPICS.md - keine Aenderung noetig.

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-07 -->
<!-- component: frontend-nyla | platform -->
<!-- component: ui-nyla | platform -->
# PORTA UI-Enhancements (Team-Meeting Inputs, 2026-04-07)
@ -59,13 +59,13 @@
- **Frontend Nyla:** AI-Workspace-Layout, globale Shell (Login/Landing), Navigation/Empty States, ggf. Trust-Strip-Komponente, Breakpoints.
- **Gateway:** nur falls neue/angereicherte Felder für Trust-Copy (Hosting-Text) oder Billing-Summary für Dashboard nötig — zunächst statische/config-gestützte Copy prüfen.
- **DB-Migration:** nein (voraussichtlich).
- **Platform / Wiki:** nach Release `b-reference/frontend-nyla/architecture.md` oder `platform/navigation.md` bei Routing-Änderungen.
- **Platform / Wiki:** nach Release `b-reference/ui-nyla/architecture.md` oder `platform/navigation.md` bei Routing-Änderungen.
---
## Codebase-Audit (Ist-Zustand, `frontend_nyla`)
## Codebase-Audit (Ist-Zustand, `ui-nyla`)
Stand: Abgleich mit Repo-Pfaden unter `poweron/frontend_nyla/src/`. Tiefergehende Systemregeln: [b-reference/frontend-nyla/architecture.md](../../b-reference/frontend-nyla/architecture.md), Navigation: [b-reference/platform/navigation.md](../../b-reference/platform/navigation.md).
Stand: Abgleich mit Repo-Pfaden unter `poweron/ui-nyla/src/`. Tiefergehende Systemregeln: [b-reference/ui-nyla/architecture.md](../../b-reference/ui-nyla/architecture.md), Navigation: [b-reference/platform/navigation.md](../../b-reference/platform/navigation.md).
### Bereits vorhanden (positiv)
@ -136,7 +136,7 @@ Ziele: Issues I1I9 adressieren, **ohne** Billing-Logik oder Gateway-Tarife ne
|------|-----------|-------------------|
| D1 | Nach Login: **einmaliger** Banner oder Home-Teaser «Guthaben & Nutzung» mit Link zu `/billing/transactions` (nur wenn Route erlaubt — Permission prüfen wie andere Nav-Items) | `MainLayout.tsx`, `App.tsx` Home-Route, oder dedizierte `HomePage` — je nachdem wo Landing liegt |
| D2 | Optional: **kleine Balance-Zahl** in UserSection neben Avatar (nur wenn API schon geladen wird und Mandate eindeutig) — Performance/UX mit `useBilling` prüfen | `UserSection.tsx` |
| D3 | Gateway: Navigations-**Label/Reihenfolge** für Billing in «Meine Sicht» nach oben ziehen (wenn gewünscht) — **kein** Frontend-Workaround ohne Backend | `gateway` `NAVIGATION_SECTIONS` / `mainSystem.py` (siehe Wiki navigation.md) |
| D3 | Gateway: Navigations-**Label/Reihenfolge** für Billing in «Meine Sicht» nach oben ziehen (wenn gewünscht) — **kein** Frontend-Workaround ohne Backend | `platform-core` `NAVIGATION_SECTIONS` / `mainSystem.py` (siehe Wiki navigation.md) |
### Phase E — Feinschliff (laufend)
@ -144,7 +144,7 @@ Ziele: Issues I1I9 adressieren, **ohne** Billing-Logik oder Gateway-Tarife ne
|------|-----------|
| E1 | `WorkspaceInput`: optional natives **File** im Prompt-`onDragOver`/`Drop` spiegeln (gleiche Logik wie `WorkspacePage._uploadAndAttach`) — dann expliziter Drop auf Eingabe |
| E2 | i18n: alle neuen Strings in `locales/` |
| E3 | Nach Merge: `b-reference/frontend-nyla/architecture.md` um Workspace-UX-Notizen ergänzen |
| E3 | Nach Merge: `b-reference/ui-nyla/architecture.md` um Workspace-UX-Notizen ergänzen |
### Abhängigkeiten & Risiken
@ -159,7 +159,7 @@ Ziele: Issues I1I9 adressieren, **ohne** Billing-Logik oder Gateway-Tarife ne
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
| 2026-04-07 | Plan aus Meeting-Transkript abgeleitet; Fokus UI/UX, nicht Pricing-Tarife | Entscheidungen zu Tarifen und Modellen sind separat zu treffen |
| 2026-04-07 | Codebase-Audit gegen `frontend_nyla` — Umsetzung in Phasen AE | Issues I1I9 und bestehende Bausteine im Dokument festgehalten |
| 2026-04-07 | Codebase-Audit gegen `ui-nyla` — Umsetzung in Phasen AE | Issues I1I9 und bestehende Bausteine im Dokument festgehalten |
*Weitere Einträge nach UX-Review und Abstimmung Partner/Hosting-Formulierung.*
@ -195,7 +195,7 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
- [ ] E1: optional File-Drop auf Prompt synchron zu `WorkspacePage`
- [ ] E2: `locales/*` für neue Strings
- [ ] E3: Wiki `b-reference/frontend-nyla/architecture.md` aktualisieren
- [ ] E3: Wiki `b-reference/ui-nyla/architecture.md` aktualisieren
**Querschnitt**
@ -221,7 +221,7 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1,2 | e2e / manuell Viewports | teilweise | `frontend_nyla` — `WorkspacePage.tsx` bei 1100/1200/1280/1440px | pending |
| T1 | 1,2 | e2e / manuell Viewports | teilweise | `ui-nyla` — `WorkspacePage.tsx` bei 1100/1200/1280/1440px | pending |
| T2 | 3 | manuell UX-Review | nein | — | pending |
| T3 | 4 | manuell Rolle Admin | nein | — | pending |
| T4 | 5,6 | manuell Explorer/Safari/Edge | nein | — | pending |
@ -230,12 +230,12 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
- Input: [input2026-04-ui-enhancement-inbputs.txt](./input2026-04-ui-enhancement-inbputs.txt)
- Produkt-Überblick: [README.md](../../README.md)
- Frontend-Referenz: [b-reference/frontend-nyla/architecture.md](../../b-reference/frontend-nyla/architecture.md)
- Frontend-Referenz: [b-reference/ui-nyla/architecture.md](../../b-reference/ui-nyla/architecture.md)
- Navigation API: [b-reference/platform/navigation.md](../../b-reference/platform/navigation.md)
- Billing (Backend-Kontext): [b-reference/gateway/billing.md](../../b-reference/gateway/billing.md)
- Billing (Backend-Kontext): [b-reference/platform-core/billing.md](../../b-reference/platform-core/billing.md)
- Compliance (Copy-Grundlage): [e-compliance/security-overview.md](../../e-compliance/security-overview.md)
**Code (Haupt-Einstiegspunkte, Repo `frontend_nyla`)**
**Code (Haupt-Einstiegspunkte, Repo `ui-nyla`)**
- `src/pages/views/workspace/WorkspacePage.tsx` — Layout, Mobile, Drag-Drop, UDB
- `src/pages/views/workspace/WorkspaceInput.tsx` — Prompt, Anhänge, STT
@ -251,6 +251,6 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
## Abschluss
- [ ] b-reference/ aktualisiert (`frontend-nyla/architecture.md`, ggf. `platform/navigation.md`)
- [ ] b-reference/ aktualisiert (`ui-nyla/architecture.md`, ggf. `platform/navigation.md`)
- [ ] TOPICS.md aktualisiert (falls neues Thema «Trust-UI» o. ä.)
- [ ] Dieses Dokument → `z-archive/` verschoben (nach Release)

View file

@ -1,7 +1,7 @@
<!-- status: build (Phase 1, 3, 4, 5, 6, 2-toolbar done; FilesTab integration deferred) -->
<!-- started: 2026-04-16 -->
<!-- updated: 2026-04-19 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
<!-- relatedTo: c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md (1.9c) -->
# PWG-Pilot: Jahresmietzinsbestätigungs-Workflow + Workflow-File-IO
@ -65,10 +65,10 @@
- `pages/views/workflow/` (Graph-Editor-View) — Buttons "Aus Datei importieren" + "Als Datei exportieren" (Editor-Toolbar).
- `api/workflowApi.ts` (oder analog) — neue Endpoint-Wrapper.
- **DB-Migration:** **nein**.
- **Repo-Asset:** `gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` (NEU).
- **Demo-Config:** `gateway/modules/demoConfigs/pwgDemo2026.py` (NEU) — Subklasse von `_BaseDemoConfig`, wird automatisch von `_getAvailableDemoConfigs()` gefunden.
- **Demo-Seed-Daten:** `gateway/demoData/pwg/scans/` (NEU, 3 fiktive Scan-PDFs) und `gateway/demoData/pwg/_seedTrusteeData.json` (NEU, fiktive Mieter + Mietzins-Buchungen).
- **Andere:** Step-5-Prompt-Template als Konstante in `gateway/modules/features/trustee/promptTemplates/_pwgMietzinsCheck.py` oder direkt im Workflow-File (Decision unten).
- **Repo-Asset:** `platform-core/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` (NEU).
- **Demo-Config:** `platform-core/modules/demoConfigs/pwgDemo2026.py` (NEU) — Subklasse von `_BaseDemoConfig`, wird automatisch von `_getAvailableDemoConfigs()` gefunden.
- **Demo-Seed-Daten:** `platform-core/demoData/pwg/scans/` (NEU, 3 fiktive Scan-PDFs) und `platform-core/demoData/pwg/_seedTrusteeData.json` (NEU, fiktive Mieter + Mietzins-Buchungen).
- **Andere:** Step-5-Prompt-Template als Konstante in `platform-core/modules/features/trustee/promptTemplates/_pwgMietzinsCheck.py` oder direkt im Workflow-File (Decision unten).
## Entscheidungen
@ -86,8 +86,8 @@
| 2026-04-16 | E-Mail mit Attachment via Erweiterung von `email.draftEmail` (neuer optionaler `attachments`-Parameter), kein neuer Node | Minimal-invasiv; `email.draftEmail` ist bereits gemappt auf `methodOutlook.composeAndDraftEmailWithContext` und kann erweitert werden. Im Pilot wird ein Draft erstellt (kein Auto-Versand), das passt zur "Sicherheits-Default-keine-Auto-Aktion"-Linie |
| 2026-04-16 | Eigene Demo-Bootstrap-Config `pwgDemo2026.py` (analog zu `investorDemo2026.py`) statt Erweiterung von Investor-Demo | Saubere Trennung; PWG-Pilot ist kunden-/branchenspezifisch; nutzt das bestehende Auto-Discovery-System aus `demoConfigs/__init__.py` |
| 2026-04-16 (DEFAULT, zu bestätigen) | Demo-Scope = 1 Mandant "Stiftung PWG" mit Trustee + GraphEditor + Workspace + Neutralization | Analog zu HappyLife im Investor-Demo; deckt den Pilot vollständig ab ohne unnötige Komplexität durch zweiten Mandanten |
| 2026-04-16 (DEFAULT, zu bestätigen) | Seed-Daten: 5 fiktive Mieter + je 12 Monate Mietzins-Journal-Lines, im Repo unter `gateway/demoData/pwg/_seedTrusteeData.json` | Minimal-Set damit alle 3 Test-Scans matchen können (1× ok, 1× Abweichung, 1× ohne Unterschrift), kein Abacus-Connector nötig für lokale Demo |
| 2026-04-16 (DEFAULT, zu bestätigen) | 3 Test-Scan-PDFs im Repo unter `gateway/demoData/pwg/scans/` + lokaler Folder-Connector statt SharePoint | Reproduzierbar ohne externe Abhängigkeiten; SharePoint-Variante als optionale Phase-7-Erweiterung |
| 2026-04-16 (DEFAULT, zu bestätigen) | Seed-Daten: 5 fiktive Mieter + je 12 Monate Mietzins-Journal-Lines, im Repo unter `platform-core/demoData/pwg/_seedTrusteeData.json` | Minimal-Set damit alle 3 Test-Scans matchen können (1× ok, 1× Abweichung, 1× ohne Unterschrift), kein Abacus-Connector nötig für lokale Demo |
| 2026-04-16 (DEFAULT, zu bestätigen) | 3 Test-Scan-PDFs im Repo unter `platform-core/demoData/pwg/scans/` + lokaler Folder-Connector statt SharePoint | Reproduzierbar ohne externe Abhängigkeiten; SharePoint-Variante als optionale Phase-7-Erweiterung |
| 2026-04-16 (DEFAULT, zu bestätigen) | Pilot-Workflow wird beim `load()` automatisch importiert (active=false) | Demo-User klickt nach Bootstrap nur noch "Manueller Trigger" — minimaler Klickpfad zum Wow-Effekt |
---
@ -165,7 +165,7 @@ Implementierung: alle neuen Tools rufen die neuen Routen / Interface-Methoden au
## Pilot-Workflow: Inhalt
### Datei: `gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json`
### Datei: `platform-core/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json`
**Knoten-Übersicht (10 Nodes — basierend auf real verfügbaren Nodes nach Codebase-Audit):**
@ -307,11 +307,11 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
- ✅ `ai.prompt` mit `outputFormat: "json"` und `context`-Parameter ist passgenau für Step 5.
**Sub-Task 4a — Neuer Node `trustee.queryData`: ✅ DONE (2026-04-19)**
- [x] Definition in `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py` ergänzt (Pattern wie `trustee.refreshAccountingData`).
- [x] Definition in `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py` ergänzt (Pattern wie `trustee.refreshAccountingData`).
- Parameter: `featureInstanceId` (hidden), `mode` (select: `lookup`, `aggregate`, `raw`), `entity` (select: `tenantWithRent`, `contact`, `journalLines`, `accounts`), `tenantNameRef`/`tenantAddressRef`/`period` (text, optional je nach mode), `extraFilter` (json, optional).
- Inputs: 1, Outputs: 1, `outputPorts: { 0: { schema: "QueryResult" } }`.
- `_method: "trustee"`, `_action: "queryData"`.
- [x] Action-Implementierung `gateway/modules/workflows/methods/methodTrustee/actions/queryData.py`:
- [x] Action-Implementierung `platform-core/modules/workflows/methods/methodTrustee/actions/queryData.py`:
- Mode `lookup` mit Entity `tenantWithRent` → fuzzy match in `TrusteeDataContact` (Adresse + Name normalisiert, einfache Token-Overlap-Score), dann Summe der Credit-Beträge in `TrusteeDataJournalLine` mit `_accountMatcher` (Pattern wie `6000-6099` oder `6*`) im angegebenen Zeitraum.
- Mode `raw` → liest direkt aus den 5 Trustee-Tabellen (Filter via `filterJson`).
- Mode `aggregate` → Sum/Count über JournalLines, gruppiert per `groupBy` aus `filterJson`.
@ -321,7 +321,7 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
**Sub-Task 4b — Attachment-Support in `email.draftEmail`: ✅ DONE (2026-04-19)**
- [x] In `nodeDefinitions/email.py` optionalen Parameter `attachments` (json, `frontendType: attachmentBuilder`) ergänzt.
- [x] In `gateway/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py` Attachment-Handling implementiert (Helper `_resolveAttachmentSpec`):
- [x] In `platform-core/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py` Attachment-Handling implementiert (Helper `_resolveAttachmentSpec`):
- `contentRef` → resolved aus `parameters[<contentRef>]` (z. B. CSV vom `data.consolidate`-Node), als String.
- `csvFromVariable` → Shorthand für CSV-Ref, hängt `.csv` an, MIME `text/csv`.
- `base64Content` → direkt verwendet, MIME aus `mimeType` oder Default.
@ -336,7 +336,7 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
### Phase 5 — Pilot-Workflow als File ✅ DONE (2026-04-19)
- [x] Datei `gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` erstellt — 10 Nodes (`trigger.manual` → `sharepoint.listFiles``flow.loop``sharepoint.downloadFile``trustee.extractFromFiles``trustee.queryData``ai.prompt``data.aggregate``data.consolidate``email.draftEmail`), AI-Prompt für Klassifikation (`bestaetigt` / `abweichung_betrag` / `keine_unterschrift` / `mieterwechsel` / `unklar`), CSV-Attachment via `csvFromVariable: "csv"`.
- [x] Datei `platform-core/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` erstellt — 10 Nodes (`trigger.manual` → `sharepoint.listFiles``flow.loop``sharepoint.downloadFile``trustee.extractFromFiles``trustee.queryData``ai.prompt``data.aggregate``data.consolidate``email.draftEmail`), AI-Prompt für Klassifikation (`bestaetigt` / `abweichung_betrag` / `keine_unterschrift` / `mieterwechsel` / `unklar`), CSV-Attachment via `csvFromVariable: "csv"`.
- [x] Lokale Validierung gegen `validateFileEnvelope()` — keine Errors, keine Warnungen.
- [ ] **OFFEN — Smoke-Import**: wird mit dem Demo-Bootstrap (Phase 6) erfolgen — der lädt das File und prüft, dass alle Nodes existieren.
- [ ] **OFFEN — CSV-Output-Smoke**: braucht einen Live-Run im Editor mit den 3 Test-Scans aus Phase 6.
@ -345,11 +345,11 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
**Ziel:** Per Klick (oder API-Call auf `routeAdminDemoConfig`) entsteht in einer leeren Dev-/Demo-Umgebung ein vollständig lauffähiges PWG-Setup, in dem der Pilot-Workflow direkt ausgeführt werden kann.
- [x] **6a — Skeleton:** `gateway/modules/demoConfigs/pwgDemo2026.py` mit `PwgDemo2026(_BaseDemoConfig)`, code `"pwg-demo-2026"`, `label "PWG Pilot Demo (Mietzinsbestätigungen)"`. `load()` / `remove()` analog `investorDemo2026.py` (Helpers wurden vorerst kopiert; Refactor in `_demoHelpers.py` ist eigene Iteration).
- [x] **6a — Skeleton:** `platform-core/modules/demoConfigs/pwgDemo2026.py` mit `PwgDemo2026(_BaseDemoConfig)`, code `"pwg-demo-2026"`, `label "PWG Pilot Demo (Mietzinsbestätigungen)"`. `load()` / `remove()` analog `investorDemo2026.py` (Helpers wurden vorerst kopiert; Refactor in `_demoHelpers.py` ist eigene Iteration).
- [x] **6b — Mandant + User + Features:** Mandant `stiftung-pwg`, User `pwg.demo@poweron.swiss` mit Platform-Admin-Flag, 4 Features (`workspace`, `trustee`, `graphicalEditor`, `neutralization`), Membership + Feature-Access + Billing + Neutralization-Config.
- [x] **6c — Trustee-Seed-Daten:** `gateway/demoData/pwg/_seedTrusteeData.json` mit 5 Mieter-Contacts und je 12 monatlichen JournalLines für 2026. Helper `_ensureTrusteeSeed` schreibt direkt in `poweron_trustee` DB (Account 6000 für Mietzinsertrag wird ebenfalls erstellt). Idempotent über `external_id`.
- [x] **6c — Trustee-Seed-Daten:** `platform-core/demoData/pwg/_seedTrusteeData.json` mit 5 Mieter-Contacts und je 12 monatlichen JournalLines für 2026. Helper `_ensureTrusteeSeed` schreibt direkt in `poweron_trustee` DB (Account 6000 für Mietzinsertrag wird ebenfalls erstellt). Idempotent über `external_id`.
- [x] **6d — Pilot-Workflow Auto-Import:** `_ensurePilotWorkflow` lädt `pwg-mietzinsbestaetigung-pilot.workflow.json`, ersetzt Platzhalter `<<TRUSTEE_INSTANCE_ID>>` mit der real angelegten Trustee-Instanz, importiert via `importWorkflowFromDict` (active=false). Idempotent über Label-Check.
- [x] **6e — Test-Scans:** `gateway/demoData/pwg/_generateScans.py` (reportlab) erzeugt 3 PDFs: `mieter01-bestaetigt.pdf`, `mieter02-abweichung-betrag.pdf`, `mieter03-keine-unterschrift.pdf`. Folder-Pfad bleibt im Workflow-File generisch (SharePoint-Connection-Ref) — User legt im Editor manuell den Source-Folder fest, oder dreht in der Demo den Trigger zu `trigger.manual` mit Inline-Files.
- [x] **6e — Test-Scans:** `platform-core/demoData/pwg/_generateScans.py` (reportlab) erzeugt 3 PDFs: `mieter01-bestaetigt.pdf`, `mieter02-abweichung-betrag.pdf`, `mieter03-keine-unterschrift.pdf`. Folder-Pfad bleibt im Workflow-File generisch (SharePoint-Connection-Ref) — User legt im Editor manuell den Source-Folder fest, oder dreht in der Demo den Trigger zu `trigger.manual` mit Inline-Files.
- [x] **6f — `remove()`-Pfad:** Spiegelbildlich, löscht Workflow-Records, Trustee-Seed (Lines/Entries/Contacts/Accounts), Memberships, Feature-Instances, User, Mandant.
- [ ] **OFFEN — Smoke-Test (manuell):** `POST /api/admin/demoConfigs/pwg-demo-2026/load` → Login `pwg.demo` → 5 Mieter sichtbar → Workflow vorhanden → manueller Trigger → CSV im Outlook-Draft. Wird beim nächsten Local-Dev-Start gemacht.
@ -378,7 +378,7 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
### Test B — Demo-Inhalt prüfen (≈ 2 min)
1. Logout, Login mit Username `pwg.demo` / Passwort `pwg.demo.2026` (Default-Credentials werden auch im Erfolgs-Banner aus Test A angezeigt — Quelle: `gateway/modules/demoConfigs/pwgDemo2026.py` `_USER` + `credentials`-Klassenattribut).
1. Logout, Login mit Username `pwg.demo` / Passwort `pwg.demo.2026` (Default-Credentials werden auch im Erfolgs-Banner aus Test A angezeigt — Quelle: `platform-core/modules/demoConfigs/pwgDemo2026.py` `_USER` + `credentials`-Klassenattribut).
2. Mandanten-Wechsler oben links → **„Stiftung PWG"** auswählen.
3. Vier Tiles sichtbar: **Workspace**, **Buchhaltung PWG** (Trustee), **PWG Automationen** (GraphicalEditor), **Datenschutz** (Neutralization).
4. **Buchhaltung PWG öffnen** → Reiter **„Daten"** → Tabelle „Contacts" zeigt 5 Mieter (Mieter01Mieter05). Tabelle „JournalLines" zeigt 60 Einträge (Filter `account = 6000`).
@ -404,7 +404,7 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
2. Property-Panel der Nodes prüfen:
- `sharepoint.listFiles` Source-Folder auf einen erreichbaren SharePoint-/OneDrive-Ordner setzen.
- `email.draftEmail` Connection auf den eigenen Outlook-Account, Empfänger auf eigene Adresse setzen (Demo-Mail an sich selbst).
3. Test-PDFs vorbereiten: `python gateway/demoData/pwg/_generateScans.py` einmal ausführen → 3 PDFs in `gateway/demoData/pwg/scans/`. Diese in den oben gewählten SharePoint-Ordner hochladen.
3. Test-PDFs vorbereiten: `python platform-core/demoData/pwg/_generateScans.py` einmal ausführen → 3 PDFs in `platform-core/demoData/pwg/scans/`. Diese in den oben gewählten SharePoint-Ordner hochladen.
4. Workflow oben rechts auf **„Aktiv"** schalten → Button **„Manuell ausführen"** klicken.
5. Run-Detail-Seite zeigt Step-by-Step-Logs:
- 3 Loop-Durchläufe (1 pro PDF).
@ -443,41 +443,41 @@ Antworte AUSSCHLIESSLICH als JSON nach folgendem Schema:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1, 4 | unit | ja | `gateway/tests/unit/workflow/test_workflowFileSchema.py` (17 Tests, deckt Round-Trip + Field-Stripping + Envelope-Validierung ab) | done |
| T2 | 2, 3, 10 | api | ja | `gateway/tests/integration/graphicalEditor/test_workflow_import.py` | abgedeckt durch T1 (Schema-Layer) + T3 (Tool-Layer); separater Route-Test deferred bis Bedarf |
| T3 | 5, 6 | unit | ja | `gateway/tests/unit/serviceAgent/test_workflow_tools_crud.py` (20 Tests: createWorkflow happy/error, deleteWorkflow confirm-Flag, updateWorkflowMetadata Rename, Import/Export Round-Trip, Tool-Definitionen) | done |
| T1 | 1, 4 | unit | ja | `platform-core/tests/unit/workflow/test_workflowFileSchema.py` (17 Tests, deckt Round-Trip + Field-Stripping + Envelope-Validierung ab) | done |
| T2 | 2, 3, 10 | api | ja | `platform-core/tests/integration/graphicalEditor/test_workflow_import.py` | abgedeckt durch T1 (Schema-Layer) + T3 (Tool-Layer); separater Route-Test deferred bis Bedarf |
| T3 | 5, 6 | unit | ja | `platform-core/tests/unit/serviceAgent/test_workflow_tools_crud.py` (20 Tests: createWorkflow happy/error, deleteWorkflow confirm-Flag, updateWorkflowMetadata Rename, Import/Export Round-Trip, Tool-Definitionen) | done |
| T4 | 7, 8, 9, 13 | e2e | manuell | PWG-Demo-Instanz mit 3 Test-Scans (über `pwgDemo2026.load()` gebootstrappt) | pending |
| T5 | 1, 2 | manuell UI | nein | Frontend FilesTab + Graph-Editor in lokaler Dev-Umgebung | pending |
| T6 | 11, 12 | api | ja | `gateway/tests/demo/test_pwg_demo_bootstrap.py` (15 Tests; markiert `expensive + live` — Ausführen mit `pytest -m "expensive or live" tests/demo/test_pwg_demo_bootstrap.py`) | done (live DB nötig) |
| T6 | 11, 12 | api | ja | `platform-core/tests/demo/test_pwg_demo_bootstrap.py` (15 Tests; markiert `expensive + live` — Ausführen mit `pytest -m "expensive or live" tests/demo/test_pwg_demo_bootstrap.py`) | done (live DB nötig) |
## Links
- Quellplan (0-ideas): `wiki/c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md` (Abschnitt 1.9c)
- PWG-Workshop-Inputs: `pamocreate/projects/poweron/customer-pwg/20260415-inputs-pwg.txt`
- Graph-Editor Models: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
- Graph-Editor Routes: `gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
- System-Templates Bootstrap: `gateway/modules/interfaces/interfaceBootstrap.py` (`_buildSystemTemplates`)
- Agent Workflow-Tools: `gateway/modules/serviceCenter/services/serviceAgent/workflowTools.py`
- Toolbox-Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- UDB Files-Tab: `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- File-Upload-Route: `gateway/modules/routes/routeDataFiles.py`
- Trustee-Modelle: `gateway/modules/features/trustee/datamodelFeatureTrustee.py`
- Abacus-Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Feature-Sub-Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Demo-Config-Basis: `gateway/modules/demoConfigs/_baseDemoConfig.py`
- Investor-Demo-Vorlage: `gateway/modules/demoConfigs/investorDemo2026.py`
- Demo-Config Auto-Discovery: `gateway/modules/demoConfigs/__init__.py`
- Demo-Config-Routen: `gateway/modules/routes/routeAdminDemoConfig.py`
- Bestehende Demo-Tests: `gateway/tests/demo/test_demo_bootstrap.py`
- Graph-Editor Models: `platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
- Graph-Editor Routes: `platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
- System-Templates Bootstrap: `platform-core/modules/interfaces/interfaceBootstrap.py` (`_buildSystemTemplates`)
- Agent Workflow-Tools: `platform-core/modules/serviceCenter/services/serviceAgent/workflowTools.py`
- Toolbox-Registry: `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- UDB Files-Tab: `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- File-Upload-Route: `platform-core/modules/routes/routeDataFiles.py`
- Trustee-Modelle: `platform-core/modules/features/trustee/datamodelFeatureTrustee.py`
- Abacus-Connector: `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Feature-Sub-Agent: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Demo-Config-Basis: `platform-core/modules/demoConfigs/_baseDemoConfig.py`
- Investor-Demo-Vorlage: `platform-core/modules/demoConfigs/investorDemo2026.py`
- Demo-Config Auto-Discovery: `platform-core/modules/demoConfigs/__init__.py`
- Demo-Config-Routen: `platform-core/modules/routes/routeAdminDemoConfig.py`
- Bestehende Demo-Tests: `platform-core/tests/demo/test_demo_bootstrap.py`
- PR: ...
- Issue: ...
## Abschluss
- [ ] `b-reference/gateway/architecture.md` ergänzen (Workflow-File-IO Sektion)
- [ ] `b-reference/frontend-nyla/architecture.md` ergänzen (FilesTab Workflow-Handling)
- [ ] `b-reference/platform-core/architecture.md` ergänzen (Workflow-File-IO Sektion)
- [ ] `b-reference/ui-nyla/architecture.md` ergänzen (FilesTab Workflow-Handling)
- [ ] `TOPICS.md` ergänzen (neues Thema "Workflow Portability")
- [ ] PWG-Pilot-Workflow-Datei in `gateway/demoData/workflows/` committed und im Demo-Config (`pwgDemo2026.py`) automatisch importiert (siehe Phase 6d)
- [ ] PWG-Pilot-Workflow-Datei in `platform-core/demoData/workflows/` committed und im Demo-Config (`pwgDemo2026.py`) automatisch importiert (siehe Phase 6d)
- [ ] PWG-Demo-Bootstrap (`pwgDemo2026.py`) erscheint in `_getAvailableDemoConfigs()` und ist über die Admin-UI / `routeAdminDemoConfig` aufrufbar
- [ ] Dieses Dokument → `c-work/2-build/` verschieben sobald Phase 1 startet

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-21 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Redmine Feature -- Ticket-Topologie, Browser, AI-Tools, Workflow-Nodes
@ -20,7 +20,7 @@ Wir nutzen in mehreren Software-Projekten **Redmine** als Ticketsystem (Userstor
- **Wurzel-Tracker explizit aus der Config.** Kein Heuristik-Fallback. Im `RedmineInstanceConfig` steht `rootTrackerName` (Default `Userstory`); beim Schema-Fetch wird dieser Name gegen die Tracker-Liste des Projekts case-insensitive aufgelöst. Falls der Tracker nicht existiert, ist `rootTrackerId=None` und das UI zeigt einen Konfig-Fehler.
- **Lokaler Mirror für 20k+ Tickets.** Tickets und Relations werden in `poweron_redmine` gespiegelt (`RedmineTicketMirror`, `RedmineRelationMirror`, beide `PowerOnModel` mit Auto-DDL). Stats und Browser lesen ausschliesslich aus dem Mirror. Schreibops gehen an Redmine und upserten **danach** sofort den betroffenen Ticket-Datensatz im Mirror. Eigener Service `serviceRedmineSync` mit per-Instanz `asyncio.Lock`, Routes `POST /api/redmine/{instanceId}/sync?force=` und `GET /sync/status` -- gestartet manuell aus der Settings-Page (Button), später optional zeitgesteuert.
- **Statistik = erste Seite des Features.** Eigene Page mit KPI-Tiles (Total / Offen / Geschlossen in Periode / Neu in Periode / Orphan-Count) und Diagrammen via `FormGeneratorReport` (siehe Abschnitt "Statistik-Sektionen").
- **Zeitraum-Auswahl: ausschliesslich `PeriodPicker` (`components/PeriodPicker`).** Keine Custom-Dropdowns. `PeriodValue` (`{preset, fromDate, toDate}`) ist die einzige Quelle der Wahrheit; gesendet wird via `dateFrom`/`dateTo` an das Backend (analog `gateway/modules/shared/dateRange.py`). Im Stats-Page wird `PeriodPicker` direkt vom `FormGeneratorReport.dateRangeSelector` gerendert; im Browser-Page-Filter-Bar wird er als Standalone-Komponente eingesetzt. Default-Preset für Stats: `last12Months`; für Browser: `lastMonth`.
- **Zeitraum-Auswahl: ausschliesslich `PeriodPicker` (`components/PeriodPicker`).** Keine Custom-Dropdowns. `PeriodValue` (`{preset, fromDate, toDate}`) ist die einzige Quelle der Wahrheit; gesendet wird via `dateFrom`/`dateTo` an das Backend (analog `platform-core/modules/shared/dateRange.py`). Im Stats-Page wird `PeriodPicker` direkt vom `FormGeneratorReport.dateRangeSelector` gerendert; im Browser-Page-Filter-Bar wird er als Standalone-Komponente eingesetzt. Default-Preset für Stats: `last12Months`; für Browser: `lastMonth`.
- **Pro Feature-Instanz** eine Verbindung: `redmineBaseUrl`, `apiKey` (encrypted), `projectId`, optional Whitelist-Tracker / Default-Custom-Fields. Mehrere Instanzen pro Mandat möglich.
- **API-Key sicher speichern:** Wie andere Connector-Secrets (`apiTokenConfigKey`-Pattern bei Jira) -- verschlüsselt im Mandat-Secret-Store, nie ins Frontend zurückgeben.
- **Idempotenz beim Schreiben:** Vor jedem `PUT/POST` aktuellen Stand lesen, nur Diff schreiben (siehe `applyPlan.py`-Pattern).
@ -86,7 +86,7 @@ MTTR pro Tracker · Sprint-Burnup je `fixedVersion` · Re-Open-Rate · Cumulativ
- **DB-Migration:**
- **Ja**, eine Tabelle `RedmineInstanceConfig` (FK auf `FeatureInstance`) -- speichert Base-URL, projectId, encrypted apiKey, Default-Filter (incl. `defaultPeriodPreset` als JSON-Snapshot des `PeriodValue`), `rootTrackerId` (default Userstory), Schema-Cache-TTL. Schema-Daten (Trackers, Statuses, CFs) liegen in einer separaten JSON-Spalte als Cache.
- **Andere:**
- `wiki/b-reference/gateway/features/redmine.md` (NEU, beim Done)
- `wiki/b-reference/platform-core/features/redmine.md` (NEU, beim Done)
- `wiki/TOPICS.md` Eintrag (beim Done)
## Entscheidungen
@ -165,7 +165,7 @@ MTTR pro Tracker · Sprint-Burnup je `fixedVersion` · Re-Open-Rate · Cumulativ
- [ ] Tests: Unit-Tests für Connector (Mock-Server), Integration-Tests gegen einen lokalen Redmine-Sandbox (oder VCR-Cassette)
### Phase 4 -- Doku & Cleanup
- [ ] `wiki/b-reference/gateway/features/redmine.md` neu anlegen (mit Sektion "Statistik-Aggregationen")
- [ ] `wiki/b-reference/platform-core/features/redmine.md` neu anlegen (mit Sektion "Statistik-Aggregationen")
- [ ] `wiki/TOPICS.md` Eintrag
- [ ] Pilot-Skript-Doku (`redmine-sync`) ergänzen: "→ produktiv via PORTA-Feature 'redmine'"
- [ ] Plan-Dokument nach `c-work/4-done/` verschieben
@ -194,19 +194,19 @@ Alle Connector-/Route-Tests laufen **live** gegen `redmine.logobject.ch`, Projek
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | live-integration | ja (`mark.live`) | gateway/tests/test_connector_redmine_live.py (whoAmI, getProjectMeta, getIssue, listIssues paginated) | pending |
| T2 | 1 | api | ja | gateway/tests/test_route_redmine_config.py | pending |
| T3 | 2 | unit | ja | gateway/tests/test_service_redmine_orphans.py (Tree-Builder + Orphan-Detection auf Fixture-JSON) | pending |
| T4 | 3 | live-integration | ja (`mark.live`) | gateway/tests/test_route_redmine_update_live.py (Read-modify-write Round-trip) | pending |
| T5 | 4,11 | unit | ja | gateway/tests/test_service_redmine_stats.py (Period-Filter, Tracker-Filter, Bucket-Aggregation auf Fixture-JSON) | pending |
| T6 | 5,6,12 | integration | ja | gateway/tests/test_redmine_tools.py (`mark.live` für Write-Tools) | pending |
| T7 | 7 | integration | ja | gateway/tests/test_method_redmine.py | pending |
| T8 | 8 | api | ja | gateway/tests/test_route_redmine_delete.py (Soft-Delete-Mapping + Toast-Message) | pending |
| T1 | 1 | live-integration | ja (`mark.live`) | platform-core/tests/test_connector_redmine_live.py (whoAmI, getProjectMeta, getIssue, listIssues paginated) | pending |
| T2 | 1 | api | ja | platform-core/tests/test_route_redmine_config.py | pending |
| T3 | 2 | unit | ja | platform-core/tests/test_service_redmine_orphans.py (Tree-Builder + Orphan-Detection auf Fixture-JSON) | pending |
| T4 | 3 | live-integration | ja (`mark.live`) | platform-core/tests/test_route_redmine_update_live.py (Read-modify-write Round-trip) | pending |
| T5 | 4,11 | unit | ja | platform-core/tests/test_service_redmine_stats.py (Period-Filter, Tracker-Filter, Bucket-Aggregation auf Fixture-JSON) | pending |
| T6 | 5,6,12 | integration | ja | platform-core/tests/test_redmine_tools.py (`mark.live` für Write-Tools) | pending |
| T7 | 7 | integration | ja | platform-core/tests/test_method_redmine.py | pending |
| T8 | 8 | api | ja | platform-core/tests/test_route_redmine_delete.py (Soft-Delete-Mapping + Toast-Message) | pending |
| T9 | 9 | ui | manuell | -- | pending |
| T10 | 10 | api | ja | gateway/tests/test_route_redmine_rbac.py | pending |
| T10 | 10 | api | ja | platform-core/tests/test_route_redmine_rbac.py | pending |
| T11 | 4 | ui | manuell | -- (PeriodPicker-Round-trip in Stats) | pending |
| T12 | 13 | unit | ja | gateway/tests/test_service_redmine_stats.py::test_unassigned_bucket | pending |
| T13 | -- | unit | ja | gateway/tests/test_service_redmine_stats_cache.py (TTL, Hit/Miss, Invalidierung bei Write) | pending |
| T12 | 13 | unit | ja | platform-core/tests/test_service_redmine_stats.py::test_unassigned_bucket | pending |
| T13 | -- | unit | ja | platform-core/tests/test_service_redmine_stats_cache.py (TTL, Hit/Miss, Invalidierung bei Write) | pending |
## Links
@ -215,14 +215,14 @@ Alle Connector-/Route-Tests laufen **live** gegen `redmine.logobject.ch`, Projek
- HTML-Pilot (Phase 0, **erledigt**): `poweron/local/notes/redmine-pilot/index.html`
- Pilot-Doku: `poweron/local/notes/redmine-pilot/README.md`
- Redmine REST-API: <https://www.redmine.org/projects/redmine/wiki/Rest_api>
- Vergleichs-Connector: `gateway/modules/connectors/connectorTicketsJira.py`
- Vergleichs-Method: `gateway/modules/workflows/methods/methodJira/methodJira.py`
- Vergleichs-Feature: `gateway/modules/features/trustee/` (Config pro Instanz, Tools)
- Vergleichs-Connector: `platform-core/modules/connectors/connectorTicketsJira.py`
- Vergleichs-Method: `platform-core/modules/workflows/methods/methodJira/methodJira.py`
- Vergleichs-Feature: `platform-core/modules/features/trustee/` (Config pro Instanz, Tools)
- Bestehende Komponenten -- **wiederverwenden, nicht neubauen**:
- `frontend_nyla/src/components/PeriodPicker/` (Zeitraum-Auswahl mit Presets)
- `frontend_nyla/src/components/FormGenerator/FormGeneratorReport/` (Stats-Page-Renderer mit Charts via Recharts; akzeptiert PeriodPicker via `dateRangeSelector`)
- `gateway/modules/shared/dateRange.py` (`parseIsoDateRange`, `isoDateRangeToLocalEpoch`)
- Stats-Vorbild im Code (Pattern für `serviceRedmineStats`): `gateway/modules/workflows/methods/methodTrustee/actions/queryData.py`
- `ui-nyla/src/components/PeriodPicker/` (Zeitraum-Auswahl mit Presets)
- `ui-nyla/src/components/FormGenerator/FormGeneratorReport/` (Stats-Page-Renderer mit Charts via Recharts; akzeptiert PeriodPicker via `dateRangeSelector`)
- `platform-core/modules/shared/dateRange.py` (`parseIsoDateRange`, `isoDateRangeToLocalEpoch`)
- Stats-Vorbild im Code (Pattern für `serviceRedmineStats`): `platform-core/modules/workflows/methods/methodTrustee/actions/queryData.py`
## Kritischer Review (Pre-Execution)
@ -272,10 +272,10 @@ Dieser Abschnitt fasst Risiken, blinde Flecken und ungeklärte Punkte zusammen,
→ ✅ **Plan ist executionsbereit.** Phase 1 kann starten.
### G. Phase-1 Start-Sequenz (operative Reihenfolge)
1. `gateway/modules/features/redmine/datamodelRedmine.py` -- Pydantic-Modelle, **inkl.** `RedmineStatsDto` mit Roh-Bucket-Substrukturen
2. `gateway/modules/connectors/connectorTicketsRedmine.py` -- Read-Methoden zuerst (`whoAmI`, `getProjectMeta`, `getIssue`, `listIssues`, `listRelations`), Write-Methoden danach
1. `platform-core/modules/features/redmine/datamodelRedmine.py` -- Pydantic-Modelle, **inkl.** `RedmineStatsDto` mit Roh-Bucket-Substrukturen
2. `platform-core/modules/connectors/connectorTicketsRedmine.py` -- Read-Methoden zuerst (`whoAmI`, `getProjectMeta`, `getIssue`, `listIssues`, `listRelations`), Write-Methoden danach
3. T1 (Live-Connector-Tests) parallel mit (2) -- Tests treiben Connector-API-Form
4. Helper-Skript `gateway/tests/fixtures/captureRedmineSnapshot.py` -- ruft `listIssues` einmalig live, schreibt JSON-Fixture für Service-/Stats-Unit-Tests
4. Helper-Skript `platform-core/tests/fixtures/captureRedmineSnapshot.py` -- ruft `listIssues` einmalig live, schreibt JSON-Fixture für Service-/Stats-Unit-Tests
5. `serviceRedmine.py` (Idempotenz, Throttle) + `serviceRedmineStats.py` (Aggregationen) + `serviceRedmineStatsCache.py`
6. T3, T5, T12, T13 (Unit auf Fixture)
7. DB-Migration + `interfaceFeatureRedmine.py` (Config-Persistenz, Schema-Cache)
@ -285,6 +285,6 @@ Dieser Abschnitt fasst Risiken, blinde Flecken und ungeklärte Punkte zusammen,
## Abschluss
- [ ] `wiki/b-reference/gateway/features/redmine.md` aktualisiert (NEU anlegen)
- [ ] `wiki/b-reference/platform-core/features/redmine.md` aktualisiert (NEU anlegen)
- [ ] `wiki/TOPICS.md` aktualisiert (Eintrag "Redmine Feature")
- [ ] Dieses Dokument → `z-archive/` verschoben

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-17 -->
<!-- finished: 2026-04-17 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# SysAdmin-Authority-Modell konsolidieren: Flag + Rolle → zwei klar getrennte Flags
@ -212,81 +212,81 @@ after:
| Datei | Was | Änderung |
| --------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| `gateway/modules/datamodels/datamodelUam.py` | `User` Pydantic + `UserInDB` | Neues Feld `isPlatformAdmin: bool = False` + Validator |
| `gateway/modules/datamodels/datamodelUam.py` | Docstring `isSysAdmin` | Neue Semantik („Infrastructure/System Operator") |
| `platform-core/modules/datamodels/datamodelUam.py` | `User` Pydantic + `UserInDB` | Neues Feld `isPlatformAdmin: bool = False` + Validator |
| `platform-core/modules/datamodels/datamodelUam.py` | Docstring `isSysAdmin` | Neue Semantik („Infrastructure/System Operator") |
### Backend — Auth
| Datei | Was | Änderung |
| --------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------- |
| `gateway/modules/auth/authentication.py` | `_hasSysAdminRole`, `requireSysAdminRole`, `_getRootMandateRoleIds` | **Löschen** (bzw. als deprecated Stub behalten für transitional Phase) |
| `gateway/modules/auth/authentication.py` | `RequestContext.hasSysAdminRole` | **Löschen** |
| `gateway/modules/auth/authentication.py` | `RequestContext.isPlatformAdmin` (neu) | Property |
| `gateway/modules/auth/authentication.py` | `requirePlatformAdmin` (neu) | Dependency |
| `gateway/modules/auth/__init__.py` | Exporte | `requirePlatformAdmin` exportieren |
| `platform-core/modules/auth/authentication.py` | `_hasSysAdminRole`, `requireSysAdminRole`, `_getRootMandateRoleIds` | **Löschen** (bzw. als deprecated Stub behalten für transitional Phase) |
| `platform-core/modules/auth/authentication.py` | `RequestContext.hasSysAdminRole` | **Löschen** |
| `platform-core/modules/auth/authentication.py` | `RequestContext.isPlatformAdmin` (neu) | Property |
| `platform-core/modules/auth/authentication.py` | `requirePlatformAdmin` (neu) | Dependency |
| `platform-core/modules/auth/__init__.py` | Exporte | `requirePlatformAdmin` exportieren |
### Backend — Bootstrap
| Datei | Was | Änderung |
| ----------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------ |
| `gateway/modules/interfaces/interfaceBootstrap.py` | `_initSysAdminRole` + `_createSysAdminAccessRules` + `_ensureSysAdminAccessRules` | **Löschen** (inkl. aller damit verbundener AccessRules) |
| `gateway/modules/interfaces/interfaceBootstrap.py` | `_ensureAdminUser`, `_ensureEventUser` | Setze `isPlatformAdmin=True` zusätzlich zu `isSysAdmin=True` |
| `gateway/modules/interfaces/interfaceBootstrap.py` | Neu: `_migrateSysAdminRoleToPlatformAdminFlag()` | Einmalige Migration beim Boot; idempotent |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | `_initSysAdminRole` + `_createSysAdminAccessRules` + `_ensureSysAdminAccessRules` | **Löschen** (inkl. aller damit verbundener AccessRules) |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | `_ensureAdminUser`, `_ensureEventUser` | Setze `isPlatformAdmin=True` zusätzlich zu `isSysAdmin=True` |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | Neu: `_migrateSysAdminRoleToPlatformAdminFlag()` | Einmalige Migration beim Boot; idempotent |
### Backend — Routen (alle Callsites von `hasSysAdminRole` / `requireSysAdminRole`)
| Datei | Callsites | Änderung |
| --------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `gateway/modules/routes/routeDataUsers.py` | Z.106, 159, 236, 325, 445, 517, 571, 586, 919 | `hasSysAdminRole``isPlatformAdmin` |
| `gateway/modules/routes/routeDataUsers.py` | `_syncSysAdminRole` (aus Sync-Phase 1) | **Löschen** (nicht mehr nötig) |
| `gateway/modules/routes/routeDataUsers.py` | `update_user`: Flag-Sync-Logik | Vereinfachen (kein Rolle-Sync mehr) |
| `gateway/modules/routes/routeDataMandates.py` | Z.104, 226, 258, 380, 437, 510, 1054 | `hasSysAdminRole`/`requireSysAdminRole` → `isPlatformAdmin`/`requirePlatformAdmin` |
| `gateway/modules/routes/routeDataMandates.py` | Reverse-Sync (Z.916944 aus Sync-Phase 1) | **Löschen** |
| `gateway/modules/routes/routeAdminRbacRules.py` | 11 Stellen (Z.245, 365, 490, 537, 588, 668, 756, 839, 1020, 1079, 1140, 1204, 1360) | `hasSysAdminRole`/`requireSysAdminRole` → `isPlatformAdmin`/`requirePlatformAdmin` |
| `gateway/modules/routes/routeAdminFeatures.py` | 22 Stellen | analog |
| `gateway/modules/routes/routeAdminUserAccessOverview.py` | Z.78, 126, 220 | analog |
| `gateway/modules/routes/routeAdminDatabaseHealth.py` | Z.44, 56, 68, 93 | bleibt `requireSysAdmin` (Infrastruktur) |
| `gateway/modules/routes/routeAdminLogs.py` | Z.66, 107 | bleibt `requireSysAdmin` (Infrastruktur) |
| `gateway/modules/routes/routeAdminDemoConfig.py` | Z.28, 44, 69 | `isPlatformAdmin` (Data-Change-Operation) |
| `gateway/modules/routes/routeBilling.py` | Z.89, 145, 737, 1464, 1487 | Cross-Mandate-Views → `isPlatformAdmin`; Mandate-eigene → unverändert |
| `gateway/modules/routes/routeI18n.py` | Z.829, 847, 860, 876, 914, 942 | i18n-Master/System → `requireSysAdmin`; Übersetzungs-Management → `isPlatformAdmin`|
| `gateway/modules/routes/routeSubscription.py` | Z.49, 306, 488 | `isPlatformAdmin` |
| `gateway/modules/routes/routeInvitations.py` | Z.189, 894 | `isPlatformAdmin` |
| `gateway/modules/routes/routeSystem.py` | Z.481, 299, 306, 360, 370, 375, 385, 398, 408 | `isPlatformAdmin` für Navigations-Sichtbarkeit |
| `gateway/modules/routes/routeAudit.py` | Z.134 | `isPlatformAdmin` (Cross-Mandate-Audit) |
| `gateway/modules/routes/routeNotifications.py` | 518 | unverändert (`addRoleToUserMandate` betrifft keine sysadmin mehr) |
| `gateway/modules/routes/routeDataFiles.py` | Z.11, 548, 850, 1044 | Global-Scope → `isSysAdmin` bleibt (Infra-Daten) |
| `gateway/modules/routes/routeDataSources.py` | Z.10, 56 | analog |
| `gateway/modules/routes/routeWorkflowDashboard.py` | 9 Stellen | Cross-Mandate-Übersicht → `isPlatformAdmin` |
| `gateway/modules/features/trustee/routeFeatureTrustee.py` | Z.107, 141, 159, 161, 1814 | prüfen pro Callsite (meist `isPlatformAdmin`) |
| `gateway/modules/features/teamsbot/routeFeatureTeamsbot.py` | 8 Stellen | System-Bot-Registrierung → `isSysAdmin` bleibt; User-Mgmt → `isPlatformAdmin` |
| `gateway/modules/features/chatbot/routeFeatureChatbot.py` | Z.105 | `isPlatformAdmin` |
| `gateway/modules/features/realEstate/routeFeatureRealEstate.py` | Z.119 | `isPlatformAdmin` |
| `gateway/modules/routes/routeRealEstate.py` | Z.124 | `isPlatformAdmin` |
| `gateway/modules/features/workspace/...` | (suchen) | pro Callsite prüfen |
| `gateway/modules/interfaces/interfaceDbManagement.py` | Z.637643 `_isSysAdmin` | Bleibt an Flag gebunden (RBAC-Bypass in Data-Management) |
| `platform-core/modules/routes/routeDataUsers.py` | Z.106, 159, 236, 325, 445, 517, 571, 586, 919 | `hasSysAdminRole``isPlatformAdmin` |
| `platform-core/modules/routes/routeDataUsers.py` | `_syncSysAdminRole` (aus Sync-Phase 1) | **Löschen** (nicht mehr nötig) |
| `platform-core/modules/routes/routeDataUsers.py` | `update_user`: Flag-Sync-Logik | Vereinfachen (kein Rolle-Sync mehr) |
| `platform-core/modules/routes/routeDataMandates.py` | Z.104, 226, 258, 380, 437, 510, 1054 | `hasSysAdminRole`/`requireSysAdminRole` → `isPlatformAdmin`/`requirePlatformAdmin` |
| `platform-core/modules/routes/routeDataMandates.py` | Reverse-Sync (Z.916944 aus Sync-Phase 1) | **Löschen** |
| `platform-core/modules/routes/routeAdminRbacRules.py` | 11 Stellen (Z.245, 365, 490, 537, 588, 668, 756, 839, 1020, 1079, 1140, 1204, 1360) | `hasSysAdminRole`/`requireSysAdminRole` → `isPlatformAdmin`/`requirePlatformAdmin` |
| `platform-core/modules/routes/routeAdminFeatures.py` | 22 Stellen | analog |
| `platform-core/modules/routes/routeAdminUserAccessOverview.py` | Z.78, 126, 220 | analog |
| `platform-core/modules/routes/routeAdminDatabaseHealth.py` | Z.44, 56, 68, 93 | bleibt `requireSysAdmin` (Infrastruktur) |
| `platform-core/modules/routes/routeAdminLogs.py` | Z.66, 107 | bleibt `requireSysAdmin` (Infrastruktur) |
| `platform-core/modules/routes/routeAdminDemoConfig.py` | Z.28, 44, 69 | `isPlatformAdmin` (Data-Change-Operation) |
| `platform-core/modules/routes/routeBilling.py` | Z.89, 145, 737, 1464, 1487 | Cross-Mandate-Views → `isPlatformAdmin`; Mandate-eigene → unverändert |
| `platform-core/modules/routes/routeI18n.py` | Z.829, 847, 860, 876, 914, 942 | i18n-Master/System → `requireSysAdmin`; Übersetzungs-Management → `isPlatformAdmin`|
| `platform-core/modules/routes/routeSubscription.py` | Z.49, 306, 488 | `isPlatformAdmin` |
| `platform-core/modules/routes/routeInvitations.py` | Z.189, 894 | `isPlatformAdmin` |
| `platform-core/modules/routes/routeSystem.py` | Z.481, 299, 306, 360, 370, 375, 385, 398, 408 | `isPlatformAdmin` für Navigations-Sichtbarkeit |
| `platform-core/modules/routes/routeAudit.py` | Z.134 | `isPlatformAdmin` (Cross-Mandate-Audit) |
| `platform-core/modules/routes/routeNotifications.py` | 518 | unverändert (`addRoleToUserMandate` betrifft keine sysadmin mehr) |
| `platform-core/modules/routes/routeDataFiles.py` | Z.11, 548, 850, 1044 | Global-Scope → `isSysAdmin` bleibt (Infra-Daten) |
| `platform-core/modules/routes/routeDataSources.py` | Z.10, 56 | analog |
| `platform-core/modules/routes/routeWorkflowDashboard.py` | 9 Stellen | Cross-Mandate-Übersicht → `isPlatformAdmin` |
| `platform-core/modules/features/trustee/routeFeatureTrustee.py` | Z.107, 141, 159, 161, 1814 | prüfen pro Callsite (meist `isPlatformAdmin`) |
| `platform-core/modules/features/teamsbot/routeFeatureTeamsbot.py` | 8 Stellen | System-Bot-Registrierung → `isSysAdmin` bleibt; User-Mgmt → `isPlatformAdmin` |
| `platform-core/modules/features/chatbot/routeFeatureChatbot.py` | Z.105 | `isPlatformAdmin` |
| `platform-core/modules/features/realEstate/routeFeatureRealEstate.py` | Z.119 | `isPlatformAdmin` |
| `platform-core/modules/routes/routeRealEstate.py` | Z.124 | `isPlatformAdmin` |
| `platform-core/modules/features/workspace/...` | (suchen) | pro Callsite prüfen |
| `platform-core/modules/interfaces/interfaceDbManagement.py` | Z.637643 `_isSysAdmin` | Bleibt an Flag gebunden (RBAC-Bypass in Data-Management) |
### Backend — Services / Demo / Tests
| Datei | Was | Änderung |
| -------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------- |
| `gateway/modules/demoConfigs/investorDemo2026.py` | Z.188, 222 | `isPlatformAdmin=True` statt Rolle; `isSysAdmin` wie gehabt |
| `gateway/modules/serviceCenter/services/serviceAgent/...` | Z.568 | Liest Flag — kein Change |
| `gateway/tests/**` | alle `hasSysAdminRole`/`requireSysAdminRole` Mentions | Tests anpassen |
| `gateway/tests/integration/rbac/test_sysadmin_sync.py` (geplant Phase 1) | **entfällt** bzw. wird zu `test_platform_admin_flag.py` | |
| `platform-core/modules/demoConfigs/investorDemo2026.py` | Z.188, 222 | `isPlatformAdmin=True` statt Rolle; `isSysAdmin` wie gehabt |
| `platform-core/modules/serviceCenter/services/serviceAgent/...` | Z.568 | Liest Flag — kein Change |
| `platform-core/tests/**` | alle `hasSysAdminRole`/`requireSysAdminRole` Mentions | Tests anpassen |
| `platform-core/tests/integration/rbac/test_sysadmin_sync.py` (geplant Phase 1) | **entfällt** bzw. wird zu `test_platform_admin_flag.py` | |
### Frontend
| Datei | Was | Änderung |
| --------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- |
| `frontend_nyla/src/types/mandate.ts` | User-Typ Z.143 | `isPlatformAdmin: boolean` ergänzen |
| `frontend_nyla/src/api/userApi.ts` / `authApi.ts` | User-Schema | `isPlatformAdmin?: boolean` ergänzen |
| `frontend_nyla/src/utils/userCache.ts` | User-Cache | `isPlatformAdmin` ergänzen |
| `frontend_nyla/src/pages/admin/AdminUsersPage.tsx` | Edit-Formular | Zwei separate Toggles: "Systemadmin" und "Plattformadmin"; Tooltip mit Erklärung |
| `frontend_nyla/src/pages/admin/AdminUserAccessOverviewPage.tsx` | User-Grid, Detail-Ansicht | Beide Flags anzeigen; Spalten + Filter |
| `frontend_nyla/src/pages/billing/BillingAdmin.tsx` | Z.449, 505, 508, 669 | `isSysAdmin``isPlatformAdmin` für Cross-Mandate-View |
| `frontend_nyla/src/pages/views/teamsbot/*.tsx` | Z.23, 24, 446, 329 | prüfen; meist `isPlatformAdmin` für Admin-UI, `isSysAdmin` für SystemBot-Config |
| `frontend_nyla/src/hooks/useUsers.ts` | Z.35, 39, 74, 88, 92, 218, 222 | Beide Flags mitgeben |
| `ui-nyla/src/types/mandate.ts` | User-Typ Z.143 | `isPlatformAdmin: boolean` ergänzen |
| `ui-nyla/src/api/userApi.ts` / `authApi.ts` | User-Schema | `isPlatformAdmin?: boolean` ergänzen |
| `ui-nyla/src/utils/userCache.ts` | User-Cache | `isPlatformAdmin` ergänzen |
| `ui-nyla/src/pages/admin/AdminUsersPage.tsx` | Edit-Formular | Zwei separate Toggles: "Systemadmin" und "Plattformadmin"; Tooltip mit Erklärung |
| `ui-nyla/src/pages/admin/AdminUserAccessOverviewPage.tsx` | User-Grid, Detail-Ansicht | Beide Flags anzeigen; Spalten + Filter |
| `ui-nyla/src/pages/billing/BillingAdmin.tsx` | Z.449, 505, 508, 669 | `isSysAdmin``isPlatformAdmin` für Cross-Mandate-View |
| `ui-nyla/src/pages/views/teamsbot/*.tsx` | Z.23, 24, 446, 329 | prüfen; meist `isPlatformAdmin` für Admin-UI, `isSysAdmin` für SystemBot-Config |
| `ui-nyla/src/hooks/useUsers.ts` | Z.35, 39, 74, 88, 92, 218, 222 | Beide Flags mitgeben |
## Entscheidungen
@ -379,13 +379,13 @@ after:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
| --- | ---- | ------------------------ | ------------- | ------------------------------------------------------------------ | ------- |
| T1 | 1 | api-integration | ja | `gateway/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T1 | 1 | api-integration | ja | `platform-core/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T2 | 2 | api-integration | ja | dito | done |
| T3 | 3 | api-integration | ja | dito | done |
| T4 | 4,10 | migration-unit | ja | `gateway/tests/unit/rbac/test_sysadmin_migration.py` | done |
| T5 | 5,6 | api-integration | ja | `gateway/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T6 | 7 | frontend (Playwright) | optional | `frontend_nyla/e2e/admin-users-flags.spec.ts` (neu) | open |
| T7 | 8 | api-unit | ja | `gateway/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T4 | 4,10 | migration-unit | ja | `platform-core/tests/unit/rbac/test_sysadmin_migration.py` | done |
| T5 | 5,6 | api-integration | ja | `platform-core/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T6 | 7 | frontend (Playwright) | optional | `ui-nyla/e2e/admin-users-flags.spec.ts` (neu) | open |
| T7 | 8 | api-unit | ja | `platform-core/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T8 | 9 | codebase-scan | ja (CI-Check) | `scripts/check_no_sysadmin_role.py` (CI-Gate) | done |
| T9 | 11,12| manuelle UI-Regression | manuell | Siehe Security-Regression-Manual | open |
@ -412,7 +412,7 @@ after:
## Links
- RBAC-Referenz: `wiki/b-reference/platform/rbac.md`
- Auth-Modul: `gateway/modules/auth/authentication.py`
- Auth-Modul: `platform-core/modules/auth/authentication.py`
- Ausgangspunkt Testing PORTA 2026-04-17 (Issue 4: Security-Bug)
## Abschluss
@ -420,7 +420,7 @@ after:
- [x] `wiki/b-reference/platform/rbac.md`: Abschnitt „Platform-Governance-Autoritaet" ergaenzt
- [ ] `wiki/TOPICS.md`: Topic „Authority-Modell: System/Platform/Mandate" anlegen
- [x] Dieses Dokument nach Abschluss → `wiki/c-work/4-done/` verschoben
- [x] CI-Gate `gateway/scripts/check_no_sysadmin_role.py` (Acceptance T8 / AC#9)
- [x] CI-Gate `platform-core/scripts/check_no_sysadmin_role.py` (Acceptance T8 / AC#9)
### Umsetzungs-Status

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-23 -->
<!-- completed: 2026-04-24 -->
<!-- component: gateway, frontend-nyla, teams-bot -->
<!-- component: gateway, ui-nyla, teams-bot -->
<!--
Vollstaendig umgesetzt: Datamodel, Interface-CRUD, _activeServices-Registry,
@ -9,11 +9,11 @@
Hybrid-Routing (needsAgent), SystemPrompt mit Eskalations-Regeln, Routes
POST/GET/DELETE mit RBAC + Limits + Rate-Limit, Frontend-API + SSE-Listener
+ UDB-Sidebar + Regie-Panel + CSS. 26 Backend-Unit-Tests gruen
(gateway/tests/unit/teamsbot/test_directorPrompts.py). AC 5 + 6 abgedeckt;
(platform-core/tests/unit/teamsbot/test_directorPrompts.py). AC 5 + 6 abgedeckt;
AC 1-4 sind manuelle Live-Meeting-Tests.
b-reference: teams-bot/architecture.md (Hybrid + Director Prompts) und
gateway/ai-agent.md (Teamsbot-Integration, kein eigenes Toolset) sind
platform-core/ai-agent.md (Teamsbot-Integration, kein eigenes Toolset) sind
aktualisiert; TOPICS.md gepflegt.
-->
@ -139,7 +139,7 @@ flowchart LR
| T2 | 2 | manual e2e | nein | live meeting | pending (manual) |
| T3 | 3 | manual e2e | nein | live meeting | pending (manual) |
| T4 | 4 | manual e2e | nein | live meeting | pending (manual) |
| T5 | 5,6| api unit | ja | gateway/tests/unit/teamsbot/test_directorPrompts.py | done (26 Tests) |
| T5 | 5,6| api unit | ja | platform-core/tests/unit/teamsbot/test_directorPrompts.py | done (26 Tests) |
## Links
@ -149,6 +149,6 @@ flowchart LR
## Abschluss
- [x] `wiki/b-reference/teams-bot/architecture.md` (Director Prompts + Hybrid + Tool-Set)
- [x] `wiki/b-reference/gateway/ai-agent.md` (kein neues Teamsbot-Toolset, Hybrid-Routing)
- [x] `wiki/b-reference/platform-core/ai-agent.md` (kein neues Teamsbot-Toolset, Hybrid-Routing)
- [x] `wiki/TOPICS.md` (Teams-Bot-Eintrag um Director Prompts ergaenzt + neuer Aktive-Arbeiten-Eintrag)
- [x] Diesen Plan nach `4-done/` verschieben

View file

@ -1,7 +1,7 @@
<!-- status: build -->
<!-- started: 2026-04-29 -->
<!-- verified: 2026-05-03 -->
<!-- component: gateway, frontend-nyla, teams-bot -->
<!-- component: gateway, ui-nyla, teams-bot -->
# TeamsBot Greenfield-IA: MeetingModule + Live-Update-Fixes
@ -58,22 +58,22 @@ TeamsBot zum verlaesslichen Meeting-Tool.
## Betroffene Module
- Gateway:
- `gateway/modules/features/teamsbot/datamodelTeamsbot.py` -- neue
- `platform-core/modules/features/teamsbot/datamodelTeamsbot.py` -- neue
Klasse `TeamsbotMeetingModule`, FK `TeamsbotSession.moduleId`
(nullable in Uebergangsphase).
- `gateway/modules/features/teamsbot/interfaceFeatureTeamsbot.py` --
- `platform-core/modules/features/teamsbot/interfaceFeatureTeamsbot.py` --
CRUD fuer `MeetingModule`.
- `gateway/modules/features/teamsbot/routeFeatureTeamsbot.py` --
- `platform-core/modules/features/teamsbot/routeFeatureTeamsbot.py` --
neue Routen `/modules/...`, `agentRun`-Event sauberer schicken,
`stats`-Payload kontinuierlich anreichern.
- `gateway/modules/features/teamsbot/mainTeamsbot.py` -- RBAC-Keys
- `platform-core/modules/features/teamsbot/mainTeamsbot.py` -- RBAC-Keys
auf 5 Tabs, optional Default-MeetingModule-Templates.
- Frontend:
- `frontend_nyla/src/types/mandate.ts` 244-252 -- TeamsBot-Sidebar
- `ui-nyla/src/types/mandate.ts` 244-252 -- TeamsBot-Sidebar
3 -> 5 Eintraege.
- `frontend_nyla/src/pages/FeatureView.tsx` 159-163 -- View-Mapping
- `ui-nyla/src/pages/FeatureView.tsx` 159-163 -- View-Mapping
aktualisieren.
- `frontend_nyla/src/pages/views/teamsbot/` -- vorhandene Komponenten
- `ui-nyla/src/pages/views/teamsbot/` -- vorhandene Komponenten
aufteilen:
- `TeamsbotDashboardView` -- KPIs erweitern (Modul-Aggregate +
Gamification).
@ -81,7 +81,7 @@ TeamsBot zum verlaesslichen Meeting-Tool.
- `TeamsbotModulesView` (NEU) -- Modul-CRUD + Sessions je Modul.
- `TeamsbotSessionView` -- bleibt, jetzt nur Live-Session.
- `TeamsbotSettingsView` -- bleibt.
- `frontend_nyla/src/api/teamsbotApi.ts` -- Module-API + neuer
- `ui-nyla/src/api/teamsbotApi.ts` -- Module-API + neuer
Reconnect-Hook.
- DB-Migration: ja (additive Tabelle + nullable FK).
@ -210,11 +210,11 @@ flowchart LR
### Phase 3 -- Frontend Routing & Sidebar
- [ ] `frontend_nyla/src/types/mandate.ts` 244-252 TeamsBot-Eintraege
- [ ] `ui-nyla/src/types/mandate.ts` 244-252 TeamsBot-Eintraege
auf 5 Eintraege.
- [ ] `frontend_nyla/src/App.tsx` Routes ergaenzen (`assistant`,
- [ ] `ui-nyla/src/App.tsx` Routes ergaenzen (`assistant`,
`modules`).
- [ ] `frontend_nyla/src/pages/FeatureView.tsx` View-Mapping
- [ ] `ui-nyla/src/pages/FeatureView.tsx` View-Mapping
aktualisieren.
### Phase 4 -- Frontend Komponenten
@ -256,19 +256,19 @@ flowchart LR
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | frontend_nyla/src/types/__tests__/mandate.test.ts | pending |
| T2 | 2,3 | e2e | ja | frontend_nyla/tests/e2e/teamsbot-modules-crud.spec.ts | pending |
| T3 | 4 | unit | ja | frontend_nyla/src/pages/views/teamsbot/__tests__/TeamsbotSessionView_agentRun.test.tsx | pending |
| T4 | 5 | integration | ja | frontend_nyla/tests/integration/teamsbot-stats-binding.spec.ts | pending |
| T1 | 1 | unit | ja | ui-nyla/src/types/__tests__/mandate.test.ts | pending |
| T2 | 2,3 | e2e | ja | ui-nyla/tests/e2e/teamsbot-modules-crud.spec.ts | pending |
| T3 | 4 | unit | ja | ui-nyla/src/pages/views/teamsbot/__tests__/TeamsbotSessionView_agentRun.test.tsx | pending |
| T4 | 5 | integration | ja | ui-nyla/tests/integration/teamsbot-stats-binding.spec.ts | pending |
| T5 | 6 | manual | nein | -- | pending |
| T6 | 7 | integration | ja | gateway/tests/features/teamsbot/test_migration_modules.py | pending |
| T6 | 7 | integration | ja | platform-core/tests/features/teamsbot/test_migration_modules.py | pending |
| T7 | 8,9 | manual | nein | -- | pending |
## Links
- Audit-Quelle: Subagent-Report 2026-04-29.
- Aktueller Code: `gateway/modules/features/teamsbot/`,
`frontend_nyla/src/pages/views/teamsbot/`.
- Aktueller Code: `platform-core/modules/features/teamsbot/`,
`ui-nyla/src/pages/views/teamsbot/`.
- Wiki: `wiki/b-reference/teams-bot/architecture.md`,
`wiki/c-work/4-done/2026-04-teamsbot-director-prompts.md`.

View file

@ -111,25 +111,25 @@ falsche Zahlen). Auditor-Risiko.
## Betroffene Module
- **Gateway**:
- `gateway/modules/features/trustee/accounting/accountingConnectorBase.py`
- `platform-core/modules/features/trustee/accounting/accountingConnectorBase.py`
-- neue Datenklasse `AccountingPeriodBalance`, neue optionale Methode
`getAccountBalances`.
- `gateway/modules/features/trustee/accounting/connectors/accountingConnectorRma.py`
- `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorRma.py`
-- `getAccountBalances` via `GET /gl/saldo`. Annual-Bucket + 12 Monats-
Buckets, jeweils kumulativ bis Periodenende. Opening-Balance = Saldo per
Periodenstart - 1 Tag (zweiter API-Call) oder via vorheriger Periode.
- `gateway/modules/features/trustee/accounting/connectors/accountingConnectorBexio.py`
- `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorBexio.py`
-- `getAccountBalances` aggregiert lokal aus `GET /3.0/accounting/journal`
(filtert per `from`/`to`-Param) -- Bexio bietet keine Saldoliste.
- `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
-- `getAccountBalances` aggregiert lokal aus `GET GeneralJournalEntries`
(OData-Filter `JournalDate ge ... and le ...`). Mit Schemahinweis im Code,
falls Abacus-Instanz die Entity `AccountBalances` (offiziell vorhanden,
aber Verfuegbarkeit instanzabhaengig) ausliefern kann.
- `gateway/modules/features/trustee/accounting/accountingDataSync.py`
- `platform-core/modules/features/trustee/accounting/accountingDataSync.py`
-- Phase 4 (`_persistBalances`) umbauen: zuerst Connector fragen; bei
leerer / fehlerhafter Antwort den **korrigierten** lokalen Fallback nutzen.
- `gateway/modules/workflows/methods/methodTrustee/actions/refreshAccountingData.py`
- `platform-core/modules/workflows/methods/methodTrustee/actions/refreshAccountingData.py`
-- nur Doc-String anpassen (verweist auf neuen Datenfluss).
- **Frontend**: keine Aenderung.
- **DB-Migration**: nein.
@ -178,15 +178,15 @@ falsche Zahlen). Auditor-Risiko.
### Tests
- [x] `gateway/tests/unit/features/trustee/test_accountingConnectorRma_balances.py`:
- [x] `platform-core/tests/unit/features/trustee/test_accountingConnectorRma_balances.py`:
`getAccountBalances` mit gemocktem `/gl/saldo` (17 Tests: BuHa-SoHa-Szenario,
ER-Reset, Parser, Helpers).
- [x] `gateway/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py`:
- [x] `platform-core/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py`:
lokale Aggregation aus gemockter Journal-Liste (8 Tests: BS cumulative,
carry-over, ER-Reset).
- [x] `gateway/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py`:
- [x] `platform-core/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py`:
OData-Aggregation (6 Tests: BS carry-over, ER-Reset).
- [x] `gateway/tests/unit/features/trustee/test_accountingDataSync_balances.py`:
- [x] `platform-core/tests/unit/features/trustee/test_accountingDataSync_balances.py`:
End-to-End mit FakeDb (11 Tests: Connector-Path verbatim persist,
Local-Fallback kumulative BS/ER-Berechnung, _resolveBalanceYears,
_isIncomeStatementAccount).
@ -195,7 +195,7 @@ falsche Zahlen). Auditor-Risiko.
- [x] Plan: dieses Dokument von `1-plan/` -> `4-done/` verschoben.
- [x] `wiki/c-work/_CHANGELOG.md`: 2 Zeilen (fix + test).
- [x] `wiki/b-reference/gateway/features/trustee.md`: Abschnitt
- [x] `wiki/b-reference/platform-core/features/trustee.md`: Abschnitt
"Saldenliste (`TrusteeDataAccountBalance`)" mit Datenquelle + Fallback
ergaenzt; Tests-Tabelle erweitert; Link auf dieses Dokument.
- [x] `lastReviewed: 2026-04-25` + `verifiedAgainst: ... + Account-Balance-Import`
@ -217,10 +217,10 @@ falsche Zahlen). Auditor-Risiko.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1, 2, 3 | unit | ja | gateway/tests/unit/features/trustee/test_accountingConnectorRma_balances.py | 17/17 passed |
| T2 | 4 | unit | ja | gateway/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py | 8/8 passed |
| T3 | 4 | unit | ja | gateway/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py | 6/6 passed |
| T4 | 1-3, 5 | integration | ja | gateway/tests/unit/features/trustee/test_accountingDataSync_balances.py (FakeDb) | 11/11 passed |
| T1 | 1, 2, 3 | unit | ja | platform-core/tests/unit/features/trustee/test_accountingConnectorRma_balances.py | 17/17 passed |
| T2 | 4 | unit | ja | platform-core/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py | 8/8 passed |
| T3 | 4 | unit | ja | platform-core/tests/unit/features/trustee/test_accountingConnectorAbacus_balances.py | 6/6 passed |
| T4 | 1-3, 5 | integration | ja | platform-core/tests/unit/features/trustee/test_accountingDataSync_balances.py (FakeDb) | 11/11 passed |
| T5 | 1, 2, 6 | manual | nein | PROD-Mandant `BuHa SoHa`, vorher/nachher Vergleich | pending (nach Deployment) |
## Links
@ -232,7 +232,7 @@ falsche Zahlen). Auditor-Risiko.
## Abschluss
- [x] `wiki/b-reference/gateway/features/trustee.md` aktualisiert (Quelle der
- [x] `wiki/b-reference/platform-core/features/trustee.md` aktualisiert (Quelle der
Saldenliste).
- [x] `wiki/TOPICS.md` -- kein neuer Eintrag noetig (faellt unter Trustee).
- [x] Dieses Dokument in `wiki/c-work/4-done/` verschoben.

View file

@ -3,7 +3,7 @@
Status: done
Date: 2026-04-24
Scope: gateway (trustee adapter, method definition, port catalog, tests),
frontend_nyla (FlowEditor / DataPicker)
ui-nyla (FlowEditor / DataPicker)
## Symptoms reported
@ -22,7 +22,7 @@ Two independent bugs collided on the same UI path.
### 1. Adapter drift around `ActionResult.documents`
Every trustee action returns `ActionResult.isSuccess(documents=[...])` at
runtime (see `gateway/modules/datamodels/datamodelChat.py` and the three
runtime (see `platform-core/modules/datamodels/datamodelChat.py` and the three
action implementations). However the typed-action surface disagreed in three
places:
@ -45,7 +45,7 @@ correctly rejected every other candidate, so the user saw "no input data".
### 2. Rules-of-Hooks violation in `DataPicker`
`frontend_nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx` called
`ui-nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx` called
`useMemo(... loopAncestorIds ...)` *after* the `if (!open) return null;`
early return. As soon as the picker opened (e.g. when clicking a parameter
on the sync node), React saw "rendered more hooks than during the previous
@ -54,22 +54,22 @@ whole tree unmounted to a white screen.
## Fix
- `frontend_nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx`
- `ui-nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx`
- Moved both `useMemo` calls (`connections`, `loopAncestorIds`) **above**
the `if (!open) return null;` guard.
- Added a comment block explaining why hooks must stay above the early
return so the next refactor doesn't reintroduce the bug.
- `gateway/modules/features/graphicalEditor/portTypes.py`
- `platform-core/modules/features/graphicalEditor/portTypes.py`
- Added `ActionDocument` `PortSchema` (mirrors
`datamodelChat.ActionDocument`).
- Added `documents: List[ActionDocument]` field on the `ActionResult`
schema so the DataPicker can drill into it.
- `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- `extractFromFiles.outputPorts[0].schema = "ActionResult"`.
- Both consumer params (`processDocuments.documentList`,
`syncToAccounting.documentList`) typed as `List[ActionDocument]`.
- `processDocuments.inputPorts[0].accepts` includes `ActionResult`.
- `gateway/modules/workflows/methods/methodTrustee/methodTrustee.py`
- `platform-core/modules/workflows/methods/methodTrustee/methodTrustee.py`
- `extractFromFiles.outputType = "ActionResult"`.
- `processDocuments.outputType = "ActionResult"`,
`documentList.type = "List[ActionDocument]"`.
@ -78,13 +78,13 @@ whole tree unmounted to a white screen.
## Verification
- `gateway/tests/unit/nodeDefinitions/test_trustee_schema_compliance.py`
- `platform-core/tests/unit/nodeDefinitions/test_trustee_schema_compliance.py`
rewritten to enforce the new alignment plus two new regressions
(`test_catalog_ActionResult_exposes_documents_field`,
`test_catalog_ActionDocument_is_registered`).
- `python -m pytest gateway/tests/unit/graphicalEditor/
gateway/tests/unit/nodeDefinitions/
gateway/tests/unit/workflow/test_trusteeQueryData.py` → 112 passed.
- `python -m pytest platform-core/tests/unit/graphicalEditor/
platform-core/tests/unit/nodeDefinitions/
platform-core/tests/unit/workflow/test_trusteeQueryData.py` → 112 passed.
Includes `test_staticNodesHaveNoDriftAgainstLiveMethods`, the strict
drift gate added during the Phase-4 cleanup.
- `npx vitest run src/components/FlowEditor/` → 32 passed (DataPicker,

View file

@ -1,13 +1,13 @@
<!-- status: plan -->
<!-- started: 2026-04-29 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Trustee Budget Comparison Refactor (Excel-only, Prompt-Klarheit)
## Beschreibung und Kontext
Der Trustee-Service "Budget-Vergleich"
(`gateway/modules/features/trustee/mainTrustee.py` 430-461) liefert heute
(`platform-core/modules/features/trustee/mainTrustee.py` 430-461) liefert heute
ein Word-Dokument mit teils kaputten Bildern in Tabellenzellen und mit
Charts pro Konto statt einem Uebersichts-Chart. Ursachen:
@ -16,7 +16,7 @@ Charts pro Konto statt einem Uebersichts-Chart. Ursachen:
- Prompt (Z. 442-454) ist mehrdeutig: "Erstelle **ein** Abweichungs-Chart"
steht direkt neben "**pro Konto**" -- das LLM waehlt mal Lesart A, mal B.
- Bilder-in-Tabellenzellen sind im Markdown->JSON-Pfad
(`gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`
(`platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`
72-86, 108-127) **nicht** vorgesehen: Tabellenzellen sind reine
Strings, Bilder muessen eine eigene Markdown-Zeile sein. python-docx
koennte Bilder in Zellen, aber unsere MD-Pipeline kann es nicht
@ -50,10 +50,10 @@ sortier-/filterbar). Word-Pfad fuer diesen Workflow weg.
## Betroffene Module
- Gateway:
- `gateway/modules/features/trustee/mainTrustee.py` -- Budget-Template
- `platform-core/modules/features/trustee/mainTrustee.py` -- Budget-Template
Z. 430-461 (Prompt + `resultType` + Output-Schema-Hinweis).
- Frontend:
- `frontend_nyla/src/pages/views/trustee/TrusteeAnalyseView.tsx` --
- `ui-nyla/src/pages/views/trustee/TrusteeAnalyseView.tsx` --
File-Karten korrekt rendern (xlsx-Icon).
- DB-Migration: nein (nur Template-Aenderung; bei naechstem
`_copyTemplateWorkflows`-Lauf greift es).
@ -112,7 +112,7 @@ Uebersichts-Chart ueber alle Konten ist gewuenscht.
- [ ] Verifizieren dass `rendererXlsx` PNG-Bilder unter Tabellen
korrekt rendert (vorhanden, `_renderJsonImage`-Pfad).
- [ ] Default-Bildbreite checken (heute hardcoded `maxWidth=800` in
`gateway/modules/serviceCenter/services/serviceGeneration/renderers/rendererXlsx.py`
`platform-core/modules/serviceCenter/services/serviceGeneration/renderers/rendererXlsx.py`
~ 1427-1428) -- ok fuer A4-druckbares Diagramm; spaeter via
Theme-System (Plan D) konfigurierbar.
@ -128,7 +128,7 @@ Uebersichts-Chart ueber alle Konten ist gewuenscht.
genau einer `table`-Section + einer `image`-Section + einer
`paragraph`-Section.
- [ ] Snapshot des produzierten .xlsx in
`gateway/tests/features/trustee/snapshots/`.
`platform-core/tests/features/trustee/snapshots/`.
## Akzeptanzkriterien
@ -144,20 +144,20 @@ Uebersichts-Chart ueber alle Konten ist gewuenscht.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | gateway/tests/features/trustee/test_budget_comparison_format.py | pending |
| T2 | 2,3,4 | integration | ja | gateway/tests/features/trustee/test_budget_comparison_structure.py | pending |
| T3 | 5 | unit | ja | frontend_nyla/src/pages/views/trustee/__tests__/TrusteeAnalyseView.test.tsx | pending |
| T1 | 1 | integration | ja | platform-core/tests/features/trustee/test_budget_comparison_format.py | pending |
| T2 | 2,3,4 | integration | ja | platform-core/tests/features/trustee/test_budget_comparison_structure.py | pending |
| T3 | 5 | unit | ja | ui-nyla/src/pages/views/trustee/__tests__/TrusteeAnalyseView.test.tsx | pending |
## Links
- Workflow-Definition: `gateway/modules/features/trustee/mainTrustee.py`
- Workflow-Definition: `platform-core/modules/features/trustee/mainTrustee.py`
430-461.
- Renderer-Pipeline: `gateway/modules/serviceCenter/services/serviceGeneration/`.
- Renderer-Pipeline: `platform-core/modules/serviceCenter/services/serviceGeneration/`.
- Verwandter Plan: `wiki/c-work/1-plan/2026-04-ai-reports-theming-and-pipeline.md`.
- Audit-Quelle: Subagent-Report 2026-04-29.
## Abschluss
- [ ] `wiki/b-reference/gateway/features/trustee.md` Budget-Service-Sektion
- [ ] `wiki/b-reference/platform-core/features/trustee.md` Budget-Service-Sektion
aktualisieren
- [ ] Dieses Dokument -> `z-archive/` verschoben

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- planned: 2026-04-21 -->
<!-- done: 2026-04-21 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# Trustee: Aufraeumen `Positionen` / `Dokumente` Top-Level-Seiten
@ -11,9 +11,9 @@ Mit `2026-04-trustee-data-tables-page.md` (status: done) sind alle 13 Trustee-Ta
Top-Level-Routen / Mappings fuer diese beiden Seiten wurden in der Vorgaenger-Iteration entfernt:
- `frontend_nyla/src/pages/FeatureView.tsx`: kein direktes `'positions' / 'documents'`-Mapping mehr (`VIEW_COMPONENTS.trustee`).
- `frontend_nyla/src/App.tsx`: keine `Route path="positions"` / `path="documents"` mehr.
- `gateway/modules/features/trustee/mainTrustee.py`: `ui.feature.trustee.positions` und `ui.feature.trustee.documents` entfernt; einziger neuer UI-Eintrag ist `ui.feature.trustee.data-tables`.
- `ui-nyla/src/pages/FeatureView.tsx`: kein direktes `'positions' / 'documents'`-Mapping mehr (`VIEW_COMPONENTS.trustee`).
- `ui-nyla/src/App.tsx`: keine `Route path="positions"` / `path="documents"` mehr.
- `platform-core/modules/features/trustee/mainTrustee.py`: `ui.feature.trustee.positions` und `ui.feature.trustee.documents` entfernt; einziger neuer UI-Eintrag ist `ui.feature.trustee.data-tables`.
Was noch lebt: die beiden Standalone-Komponenten als Datei + Index-Export. Sie werden ausschliesslich vom `TrusteeDataTablesView` als Tab-Body referenziert.
@ -24,7 +24,7 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
- Die Spezialdarstellungen (Beleg-Download in Positionen-Tabelle, Dokument-Download in Dokumente-Tabelle, Inline-Sync-Status) leben in `TrusteePositionsView` / `TrusteeDocumentsView`. Sie sind weiterhin **als Tab-Body** im neuen `TrusteeDataTablesView` produktiv -- darf nicht versehentlich entfernt werden.
- Falls ein simpler `TrusteeDataTab` (generischer Wrapper) die Spezialfeatures nicht abdeckt, bleiben die beiden Komponenten erhalten und werden nur in der `index.ts` und im Code-Layout sauber als "Tab-Body, nicht Top-Level-View" gekennzeichnet.
- `position-documents` (Zuordnungen) bleibt als eigene Top-Level-View unangetastet (anderer Use-Case: Position-Document-Zuordnung).
- `FEATURE_REGISTRY.trustee.views` in `frontend_nyla/src/types/mandate.ts` ist laut Header (`TODO: Remove after all references are migrated to use backend navigation.`) ohnehin geplant zu entsorgen -- in dieser Iteration nur sicherstellen, dass keine `'positions'`/`'documents'`-Eintraege mehr drin sind.
- `FEATURE_REGISTRY.trustee.views` in `ui-nyla/src/types/mandate.ts` ist laut Header (`TODO: Remove after all references are migrated to use backend navigation.`) ohnehin geplant zu entsorgen -- in dieser Iteration nur sicherstellen, dass keine `'positions'`/`'documents'`-Eintraege mehr drin sind.
## Ziel und Nicht-Ziele
@ -39,17 +39,17 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
## Betroffene Module
- **Frontend**:
- `frontend_nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`: Header-Kommentar / Renaming.
- `frontend_nyla/src/pages/views/trustee/index.ts`: Exporte pruefen (nur was extern noch noetig ist, bleibt).
- `frontend_nyla/src/pages/FeatureView.tsx`: Sicherstellen, dass `VIEW_COMPONENTS.trustee` keine `'positions'/'documents'`-Eintraege hat.
- `frontend_nyla/src/App.tsx`: Suche nach Restrouten mit `positions` / `documents`.
- `frontend_nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` (legacy) -- Eintraege sauber halten, ggf. ganzen Block deprecaten.
- `frontend_nyla/src/components/Navigation/*`: Pruefen, ob noch Icons / Default-Routes auf `positions` / `documents` zeigen.
- `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`: Header-Kommentar / Renaming.
- `ui-nyla/src/pages/views/trustee/index.ts`: Exporte pruefen (nur was extern noch noetig ist, bleibt).
- `ui-nyla/src/pages/FeatureView.tsx`: Sicherstellen, dass `VIEW_COMPONENTS.trustee` keine `'positions'/'documents'`-Eintraege hat.
- `ui-nyla/src/App.tsx`: Suche nach Restrouten mit `positions` / `documents`.
- `ui-nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` (legacy) -- Eintraege sauber halten, ggf. ganzen Block deprecaten.
- `ui-nyla/src/components/Navigation/*`: Pruefen, ob noch Icons / Default-Routes auf `positions` / `documents` zeigen.
- **Gateway**:
- `gateway/modules/features/trustee/mainTrustee.py`: Sweep `UI_OBJECTS`, `TEMPLATE_ROLES`, `QUICK_ACTIONS` -- keine `ui.feature.trustee.positions` / `.documents` mehr.
- `gateway/modules/features/trustee/routeFeatureTrustee.py`: kein Code-Change geplant (REST-Endpunkte fuer Position/Document bleiben).
- `platform-core/modules/features/trustee/mainTrustee.py`: Sweep `UI_OBJECTS`, `TEMPLATE_ROLES`, `QUICK_ACTIONS` -- keine `ui.feature.trustee.positions` / `.documents` mehr.
- `platform-core/modules/features/trustee/routeFeatureTrustee.py`: kein Code-Change geplant (REST-Endpunkte fuer Position/Document bleiben).
- **Wiki**:
- `wiki/b-reference/frontend-nyla/architecture.md` und `gateway/architecture.md`: pruefen, ob in den `trustee`-Mentions noch `positions`/`documents` als Top-Level-Pages stehen.
- `wiki/b-reference/ui-nyla/architecture.md` und `platform-core/architecture.md`: pruefen, ob in den `trustee`-Mentions noch `positions`/`documents` als Top-Level-Pages stehen.
- **DB-Migration**: nein.
## Entscheidungen
@ -65,18 +65,18 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
- [x] `TrusteePositionsView.tsx` Header-Kommentar `Mounted only as a tab inside TrusteeDataTablesView` ergaenzt (inkl. Hinweis, dass kein Re-Export mehr ueber `index.ts` existiert).
- [x] `TrusteeDocumentsView.tsx` analog ergaenzt.
- [x] `frontend_nyla/src/pages/views/trustee/index.ts`: `TrusteePositionsView` + `TrusteeDocumentsView` aus dem Re-Export entfernt; Header-Kommentar erklaert die Aenderung. Direkte Imports (`./TrusteePositionsView`) durch `TrusteeDataTablesView` funktionieren weiter -- Build verifiziert.
- [x] `ui-nyla/src/pages/views/trustee/index.ts`: `TrusteePositionsView` + `TrusteeDocumentsView` aus dem Re-Export entfernt; Header-Kommentar erklaert die Aenderung. Direkte Imports (`./TrusteePositionsView`) durch `TrusteeDataTablesView` funktionieren weiter -- Build verifiziert.
- [x] `grep "ui.feature.trustee.positions\|ui.feature.trustee.documents"` durch Gateway + Frontend: keine Live-Code-Treffer mehr (nur Plan-/Doku-/Changelog-Eintraege + 1 erklaerender Kommentar in `mainTrustee.py:28`).
- [x] `grep "/trustee/.*positions\|/trustee/.*documents"` (Mail-Templates, Workflows, QuickActions): die verbleibenden Treffer sind ausschliesslich **REST-API**-Endpunkte (`/api/trustee/{instanceId}/positions`, `/api/trustee/{instanceId}/documents` -- POST/PUT/DELETE), keine UI-Routen. Diese sind weiterhin gueltig (sie werden von den Tab-Bodies in `data-tables` aufgerufen).
- [x] `mainTrustee.py.QUICK_ACTIONS`: alle URLs sind API-Endpunkte (POST/PUT/DELETE) -- keine UI-Navigation, keine Aenderung noetig. „Neuer Beleg" / „Neue Position" oeffnen das Modal in der `data-tables`-Tab-Body-Komponente.
- [x] Navigation-Defaults: `FEATURE_REGISTRY.trustee.views` in `frontend_nyla/src/types/mandate.ts` enthaelt nur noch `dashboard`, `data-tables`, `position-documents`, `import-process`, `instance-roles`, `settings` -- kein `positions`/`documents` mehr; `App.tsx` hat ebenfalls keine entsprechenden Routen.
- [x] Navigation-Defaults: `FEATURE_REGISTRY.trustee.views` in `ui-nyla/src/types/mandate.ts` enthaelt nur noch `dashboard`, `data-tables`, `position-documents`, `import-process`, `instance-roles`, `settings` -- kein `positions`/`documents` mehr; `App.tsx` hat ebenfalls keine entsprechenden Routen.
### Verifikation
- [x] Manueller Smoke-Test (`Daten-Tabellen` -> Tab `Positionen`): Edit + Beleg-Download via `TrusteePositionsView`-Tab-Body funktional unveraendert.
- [x] Manueller Smoke-Test (`Daten-Tabellen` -> Tab `Dokumente`): Edit + Download via `TrusteeDocumentsView`-Tab-Body funktional unveraendert.
- [x] `npm run build` im Frontend: keine neuen TypeScript-Fehler durch entfernte `index.ts`-Exporte. Die zwei verbleibenden Build-Errors (`PeriodPickerLogic.ts` unused param, `RedmineStatsView.tsx` `'allTime'`-Period-Mismatch) sind **pre-existing**, gehoeren nicht in diesen Plan.
- [x] Gateway-Tests `gateway/tests/test_routeFeatureTrustee_*` -- nicht beruehrt (kein Backend-Change in dieser Iteration).
- [x] Gateway-Tests `platform-core/tests/test_routeFeatureTrustee_*` -- nicht beruehrt (kein Backend-Change in dieser Iteration).
## Akzeptanzkriterien
@ -92,23 +92,23 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | manual UI | nein | -- | done (smoke ok) |
| T2 | 2 | grep | manuell | gateway/, frontend_nyla/ | done (keine Live-Treffer) |
| T2 | 2 | grep | manuell | platform-core/, ui-nyla/ | done (keine Live-Treffer) |
| T3 | 3 | grep + manual | manuell | mainTrustee.py, mail-templates | done (nur API-URLs verbleiben) |
| T4 | 4 | build | ja | frontend_nyla `npm run build` | done (keine neuen Fehler) |
| T4 | 4 | build | ja | ui-nyla `npm run build` | done (keine neuen Fehler) |
## Links
- Vorgaenger-Plan: `wiki/c-work/4-done/2026-04-trustee-data-tables-page.md`
- Konsolidierte Seite: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`
- Eingebettete Tab-Bodies: `frontend_nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`
- Konsolidierte Seite: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`
- Eingebettete Tab-Bodies: `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`
## Abschluss
- [x] Dieses Dokument -> `c-work/4-done/` (Cleanup war eine reine Aufraeum-Iteration ohne Backend-Migration; keine separate Build-/Validate-Phase noetig).
- [x] Code-Aenderungen:
- `frontend_nyla/src/pages/views/trustee/TrusteePositionsView.tsx` -- Header-Kommentar (Mounted only as a tab inside `TrusteeDataTablesView`).
- `frontend_nyla/src/pages/views/trustee/TrusteeDocumentsView.tsx` -- analog.
- `frontend_nyla/src/pages/views/trustee/index.ts` -- die beiden Komponenten aus dem Re-Export entfernt; Header-Kommentar erklaert die Aenderung. Niemand importiert sie ueber `index.ts`.
- `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx` -- Header-Kommentar (Mounted only as a tab inside `TrusteeDataTablesView`).
- `ui-nyla/src/pages/views/trustee/TrusteeDocumentsView.tsx` -- analog.
- `ui-nyla/src/pages/views/trustee/index.ts` -- die beiden Komponenten aus dem Re-Export entfernt; Header-Kommentar erklaert die Aenderung. Niemand importiert sie ueber `index.ts`.
- [x] Audit ohne Code-Aenderung:
- Backend (`mainTrustee.py`): keine UI-Object-Keys `ui.feature.trustee.positions/.documents` mehr; `QUICK_ACTIONS` zielen auf REST-API.
- Frontend (`App.tsx`, `FeatureView.tsx`, `pageRegistry.tsx`, `mandate.ts`): keine Top-Level-Routen / Default-Views fuer `positions`/`documents` mehr.

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-20 -->
<!-- finished: 2026-04-21 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# Trustee: Konsolidierte Daten-Tabellen-Seite
@ -20,7 +20,7 @@ Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (ums
## Fokus und kritische Details
- **FormGeneratorTable-Vertrag** (siehe `wiki/b-reference/frontend-nyla/formgenerator.md`): Jede Tabelle braucht (a) ein `apiEndpoint` mit Unified Filter API (`mode=filterValues|ids`), (b) einen Hook mit `refetch / pagination / attributes / permissions`, (c) saubere Spaltendefinitionen aus `getModelAttributeDefinitions(...)`.
- **FormGeneratorTable-Vertrag** (siehe `wiki/b-reference/ui-nyla/formgenerator.md`): Jede Tabelle braucht (a) ein `apiEndpoint` mit Unified Filter API (`mode=filterValues|ids`), (b) einen Hook mit `refetch / pagination / attributes / permissions`, (c) saubere Spaltendefinitionen aus `getModelAttributeDefinitions(...)`.
- **`getModelAttributeDefinitions` ist bereits da** (`/api/trustee/{instanceId}/attributes/{entityType}`) aber nur registriert für die **6 CRUD-Modelle** (`_TRUSTEE_ENTITY_MODELS` in `routeFeatureTrustee.py`, Zeile 195). Die 7 fehlenden Modelle (TrusteeData* + Accounting*) müssen in dieser Map ergänzt werden.
- **Sync-Tabellen sind read-only** (User-Entscheidung). Endpunkte für TrusteeData*/AccountingSync sind aktuell **nicht** als generische REST-CRUDs implementiert nur Aggregat-Endpunkte (`/accounting/import-status`, `/accounting/sync-status`, `/accounting/export-data`). Es braucht **neue Read-Endpunkte** mit Pagination + Unified Filter API.
- **RBAC-Konsistenz**: Jede Tabelle hat in `mainTrustee.DATA_OBJECTS` einen `data.feature.trustee.<Model>`-Key. Der Hook (`_createTrusteeEntityHook`) löst Permissions via `data.feature.trustee.{entityName}` auf das funktioniert bereits für die bestehenden 6 Modelle, muss für die neuen 7 ebenfalls greifen.
@ -45,17 +45,17 @@ Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (ums
## Betroffene Module
- **Gateway**:
- `gateway/modules/features/trustee/routeFeatureTrustee.py`: `_TRUSTEE_ENTITY_MODELS` um 7 Modelle erweitern; neue Read-Endpunkte mit Pagination + Unified Filter API für `TrusteeDataAccount`, `TrusteeDataJournalEntry`, `TrusteeDataJournalLine`, `TrusteeDataContact`, `TrusteeDataAccountBalance`, `TrusteeAccountingConfig`, `TrusteeAccountingSync`.
- `gateway/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern.
- `platform-core/modules/features/trustee/routeFeatureTrustee.py`: `_TRUSTEE_ENTITY_MODELS` um 7 Modelle erweitern; neue Read-Endpunkte mit Pagination + Unified Filter API für `TrusteeDataAccount`, `TrusteeDataJournalEntry`, `TrusteeDataJournalLine`, `TrusteeDataContact`, `TrusteeDataAccountBalance`, `TrusteeAccountingConfig`, `TrusteeAccountingSync`.
- `platform-core/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern.
- **Frontend**:
- **Neu**: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` (Container mit Tab-Bar + URL-Sync).
- **Neu**: `frontend_nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` (generischer Tab-Body mit FormGeneratorTable für CRUD- und Read-only-Modi).
- **Erweitern**: `frontend_nyla/src/hooks/useTrustee.ts` um Hooks für die 7 neuen Modelle (über die bestehenden Factories `_createTrusteeEntityHook` / `_createTrusteeOperationsHook` read-only Variante für Sync-Tabellen).
- **Erweitern**: `frontend_nyla/src/api/trusteeApi.ts` um `fetchTrusteeData*`-Funktionen.
- **Anpassen**: `frontend_nyla/src/pages/FeatureView.tsx` (`VIEW_COMPONENTS.trustee` um `'data-tables': TrusteeDataTablesView` ergänzen).
- **Anpassen**: `frontend_nyla/src/pages/views/trustee/index.ts` (Export).
- **Anpassen**: `frontend_nyla/src/App.tsx` (Route `data-tables` registrieren).
- **Optional**: `frontend_nyla/src/types/mandate.ts` (`FEATURE_REGISTRY.trustee.views`) um `data-tables` ergänzen, falls noch genutzt.
- **Neu**: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` (Container mit Tab-Bar + URL-Sync).
- **Neu**: `ui-nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` (generischer Tab-Body mit FormGeneratorTable für CRUD- und Read-only-Modi).
- **Erweitern**: `ui-nyla/src/hooks/useTrustee.ts` um Hooks für die 7 neuen Modelle (über die bestehenden Factories `_createTrusteeEntityHook` / `_createTrusteeOperationsHook` read-only Variante für Sync-Tabellen).
- **Erweitern**: `ui-nyla/src/api/trusteeApi.ts` um `fetchTrusteeData*`-Funktionen.
- **Anpassen**: `ui-nyla/src/pages/FeatureView.tsx` (`VIEW_COMPONENTS.trustee` um `'data-tables': TrusteeDataTablesView` ergänzen).
- **Anpassen**: `ui-nyla/src/pages/views/trustee/index.ts` (Export).
- **Anpassen**: `ui-nyla/src/App.tsx` (Route `data-tables` registrieren).
- **Optional**: `ui-nyla/src/types/mandate.ts` (`FEATURE_REGISTRY.trustee.views`) um `data-tables` ergänzen, falls noch genutzt.
- **DB-Migration**: nein.
- **Andere Komponenten**: keine.
@ -92,18 +92,18 @@ Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (ums
### Frontend
- [x] `frontend_nyla/src/api/trusteeApi.ts`: 7 neue Read-Funktionen (`fetchDataAccounts`, `fetchDataJournalEntries`, `fetchDataJournalLines`, `fetchDataContacts`, `fetchDataAccountBalances`, `fetchAccountingConfigs`, `fetchAccountingSyncs`) plus passende Typen.
- [x] `frontend_nyla/src/hooks/useTrustee.ts`: 7 neue Read-only-Hooks via `_createTrusteeEntityHook` (`_buildReadOnlyConfig` injiziert no-op-Mutatoren).
- [x] **Neu** `frontend_nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` generischer Tab-Body, bindet `FormGeneratorTable` ein, respektiert `readOnly`.
- [x] **Neu** `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`:
- [x] `ui-nyla/src/api/trusteeApi.ts`: 7 neue Read-Funktionen (`fetchDataAccounts`, `fetchDataJournalEntries`, `fetchDataJournalLines`, `fetchDataContacts`, `fetchDataAccountBalances`, `fetchAccountingConfigs`, `fetchAccountingSyncs`) plus passende Typen.
- [x] `ui-nyla/src/hooks/useTrustee.ts`: 7 neue Read-only-Hooks via `_createTrusteeEntityHook` (`_buildReadOnlyConfig` injiziert no-op-Mutatoren).
- [x] **Neu** `ui-nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` generischer Tab-Body, bindet `FormGeneratorTable` ein, respektiert `readOnly`.
- [x] **Neu** `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`:
- 13 Tab-Defs, jede mit eigenem Wrapper-Component, das den passenden Hook aufruft.
- URL-Sync via `?tab=<key>`, Lazy-Mount (nur aktiver Wrapper rendert -> kein Datenfetch fuer inaktive Tabs).
- Tab-Bar im Stil von `TrusteeAbschlussView`/`TrusteeImportProcessView`; Sync-Tabs zeigen «(read-only)»-Hinweis.
- RBAC-Filter im Frontend deaktiviert: einzelne Tab-Hooks blockieren Datenzugriff serverseitig (vermeidet sync-Permission-Lookups; spaetere Iteration kann Tab-Hiding nachziehen).
- [x] `frontend_nyla/src/pages/views/trustee/index.ts`: Export ergaenzt.
- [x] `frontend_nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import.
- [x] `frontend_nyla/src/App.tsx`: Route `<Route path="data-tables" .../>` ergaenzt.
- [x] `frontend_nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` um `'data-tables'` ergaenzt.
- [x] `ui-nyla/src/pages/views/trustee/index.ts`: Export ergaenzt.
- [x] `ui-nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import.
- [x] `ui-nyla/src/App.tsx`: Route `<Route path="data-tables" .../>` ergaenzt.
- [x] `ui-nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` um `'data-tables'` ergaenzt.
### Cross-Cutting
@ -135,27 +135,27 @@ Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (ums
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | manual UI | nein | | pending |
| T2 | 2,5 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T3 | 3,4 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T4 | 6 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (Unified Filter API: mode=filterValues / mode=ids) | pending |
| T5 | 7 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (RBAC-Gate) | pending |
| T2 | 2,5 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T3 | 3,4 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T4 | 6 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (Unified Filter API: mode=filterValues / mode=ids) | pending |
| T5 | 7 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (RBAC-Gate) | pending |
| T6 | 8 | manual UI | nein | | pending |
| T7 | 9 | manual + e2e | teils | bestehende Position/Document Tests laufen weiter | pending |
| T8 | 10,11 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending |
| T8 | 10,11 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending |
## Links
- PR:
- Issue:
- Vorlage: `wiki/b-reference/frontend-nyla/formgenerator.md`
- Vorbild-Seite: `frontend_nyla/src/pages/basedata/PromptsPage.tsx`
- Vorbild-Tabs: `frontend_nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx`
- Vorlage: `wiki/b-reference/ui-nyla/formgenerator.md`
- Vorbild-Seite: `ui-nyla/src/pages/basedata/PromptsPage.tsx`
- Vorbild-Tabs: `ui-nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx`
## Abschluss
- [x] `b-reference/gateway/architecture.md` aktualisiert: neue Sektion "Feature: Trustee -- Daten-Tabellen-Endpunkte" mit Endpunkt-Tabelle + Helper `_paginatedReadEndpoint` + RBAC-Pattern.
- [x] `b-reference/frontend-nyla/architecture.md`: Eintrag fuer `TrusteeDataTablesView` in "Wichtige UI-Komponenten" plus neuer Abschnitt "Tab-Pattern fuer mehrere Modelle pro Seite" (Lazy-Mount, URL-State, Read-only-Tabs, Tab-Gruppen).
- [x] `b-reference/frontend-nyla/formgenerator.md`: bereits referenziert (`TrusteeDataTablesView` als Beispiel im "Page Layout Chain"-Pattern).
- [x] `b-reference/platform-core/architecture.md` aktualisiert: neue Sektion "Feature: Trustee -- Daten-Tabellen-Endpunkte" mit Endpunkt-Tabelle + Helper `_paginatedReadEndpoint` + RBAC-Pattern.
- [x] `b-reference/ui-nyla/architecture.md`: Eintrag fuer `TrusteeDataTablesView` in "Wichtige UI-Komponenten" plus neuer Abschnitt "Tab-Pattern fuer mehrere Modelle pro Seite" (Lazy-Mount, URL-State, Read-only-Tabs, Tab-Gruppen).
- [x] `b-reference/ui-nyla/formgenerator.md`: bereits referenziert (`TrusteeDataTablesView` als Beispiel im "Page Layout Chain"-Pattern).
- [x] `TOPICS.md`: keine Änderung nötig (kein neues Thema).
- [x] Folge-Plan `wiki/c-work/1-plan/2026-04-trustee-cleanup-positions-documents.md` erstellt: Aufräumen der alten Top-Level-Seiten (Standalone-Files bleiben als Tab-Body, aber Header-Kommentare + Sweep auf restliche `ui.feature.trustee.positions` / `.documents`-Referenzen).
- [x] Dieses Dokument → `c-work/4-done/`.

View file

@ -1,6 +1,6 @@
<!-- status: plan -->
<!-- started: 2026-04-29 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Trustee Workflow-Audit (A1) & Generischer Workflow-Run-Workspace (A2)
@ -93,26 +93,26 @@ Verfuegung, die direkt an der GE-Instanz haengen.
## Betroffene Module
- Gateway:
- `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
- `platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
(neues Feld `AutoWorkflow.targetFeatureInstanceId`).
- `gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
- `platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
(Save-Validation: non-template braucht `targetFeatureInstanceId`).
- `gateway/modules/features/graphicalEditor/interfaceFeatureGraphicalEditor.py`
- `platform-core/modules/features/graphicalEditor/interfaceFeatureGraphicalEditor.py`
(createWorkflow/updateWorkflow: Feld durchreichen).
- `gateway/modules/workflows/automation2/executionEngine.py`
- `platform-core/modules/workflows/automation2/executionEngine.py`
(`executeGraph`: `{{featureInstanceId}}` aus `targetFeatureInstanceId`
resolven).
- `gateway/modules/workflows/scheduler/mainScheduler.py` (Schedule-Fire
- `platform-core/modules/workflows/scheduler/mainScheduler.py` (Schedule-Fire
nutzt `targetFeatureInstanceId` vom Workflow).
- `gateway/modules/features/trustee/mainTrustee.py` (Templates pruefen:
- `platform-core/modules/features/trustee/mainTrustee.py` (Templates pruefen:
`targetFeatureInstanceId` wird bei `_copyTemplateWorkflows` gesetzt).
- `gateway/modules/interfaces/interfaceFeatures.py`
- `platform-core/modules/interfaces/interfaceFeatures.py`
(`_copyTemplateWorkflows`: `targetFeatureInstanceId` auf Ziel-Instanz
setzen bei Kopie).
- Neue Route-Datei: `gateway/modules/routes/routeAutomationWorkspace.py`
- Neue Route-Datei: `platform-core/modules/routes/routeAutomationWorkspace.py`
(User-facing `/api/automations/runs/...` Endpoints).
- Frontend:
- Neuer Tab in `frontend_nyla/src/pages/AutomationsDashboardPage.tsx`.
- Neuer Tab in `ui-nyla/src/pages/AutomationsDashboardPage.tsx`.
- Neue Komponenten `WorkflowRunWorkspaceView`,
`WorkflowRunDetailView`.
- FlowEditor CanvasHeader: Pflicht-Dropdown "Ziel-Instanz"
@ -228,7 +228,7 @@ in `TEMPLATE_WORKFLOWS`. Diese verwenden ebenfalls
### Phase 3 -- Generischer WorkflowRunWorkspace
- [ ] Neue Route-Datei `gateway/modules/routes/routeAutomationWorkspace.py`:
- [ ] Neue Route-Datei `platform-core/modules/routes/routeAutomationWorkspace.py`:
- `GET /api/automations/runs` (Query-Params: `scope=mine|mandate`,
`status`, `targetInstanceId`, `workflowId`, `limit`, `offset`).
RBAC: nur Runs sichtbar wo User FeatureAccess auf
@ -277,11 +277,11 @@ in `TEMPLATE_WORKFLOWS`. Diese verwenden ebenfalls
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | ja | gateway/tests/features/graphicalEditor/test_workflow_save_target_instance.py | pending |
| T2 | 2 | api | ja | gateway/tests/features/graphicalEditor/test_workflow_execute_rbac.py | pending |
| T3 | 3,4 | e2e | ja | frontend_nyla/tests/e2e/workflow-run-workspace.spec.ts | pending |
| T4 | 5 | unit | ja | frontend_nyla/src/components/flowEditor/__tests__/TargetInstanceDropdown.test.tsx | pending |
| T5 | 8 | api | ja | gateway/tests/features/test_copy_template_workflows.py | pending |
| T1 | 1 | api | ja | platform-core/tests/features/graphicalEditor/test_workflow_save_target_instance.py | pending |
| T2 | 2 | api | ja | platform-core/tests/features/graphicalEditor/test_workflow_execute_rbac.py | pending |
| T3 | 3,4 | e2e | ja | ui-nyla/tests/e2e/workflow-run-workspace.spec.ts | pending |
| T4 | 5 | unit | ja | ui-nyla/src/components/flowEditor/__tests__/TargetInstanceDropdown.test.tsx | pending |
| T5 | 8 | api | ja | platform-core/tests/features/test_copy_template_workflows.py | pending |
## Dev-DB-Befund (2026-04-29)
@ -311,14 +311,14 @@ in `TEMPLATE_WORKFLOWS`. Diese verwenden ebenfalls
- Audit-Quelle: Subagent-Report + DB-Query 2026-04-29.
- Code-Cross-Check: Subagent 2026-04-29 (16 Annahmen verifiziert).
- Wiki: `wiki/b-reference/gateway/workflow.md`,
`wiki/b-reference/gateway/features/trustee.md`.
- Wiki: `wiki/b-reference/platform-core/workflow.md`,
`wiki/b-reference/platform-core/features/trustee.md`.
## Abschluss
- [ ] `wiki/b-reference/gateway/workflow.md` Abschnitt
- [ ] `wiki/b-reference/platform-core/workflow.md` Abschnitt
"targetFeatureInstanceId + Workspace" anlegen
- [ ] `wiki/b-reference/gateway/features/trustee.md` Result-UX-Sektion
- [ ] `wiki/b-reference/platform-core/features/trustee.md` Result-UX-Sektion
aktualisieren
- [ ] `wiki/TOPICS.md` ggf. Tab-Beschreibung
- [ ] Dieses Dokument -> `4-done/` verschoben

View file

@ -2,7 +2,7 @@
<!-- started: 2026-04-24 -->
<!-- moved-to-3-validate: 2026-04-24 -->
<!-- moved-to-4-done: 2026-04-24 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
<!--
Phase 15 sind code-fertig (237 Backend-Tests gruen, FE TypeScript-Compile
@ -50,7 +50,7 @@ mindmap
root((Workflow-Code<br/>HEUTE))
Datentypen
PORT_TYPE_CATALOG
gateway/modules/features/graphicalEditor/portTypes.py
platform-core/modules/features/graphicalEditor/portTypes.py
Schemas: ConnectionRef, DocumentList, EmailDraft,<br/>FileList, AiResult, ActionResult, ...
Nur fuer Output-Ports + accepts genutzt
NICHT fuer Input-Param-Typen
@ -59,12 +59,12 @@ mindmap
ueberall im Code parallel
Keine Verbindung zum Katalog
WorkflowActionParameter
gateway/modules/datamodels/datamodelWorkflowActions.py
platform-core/modules/datamodels/datamodelWorkflowActions.py
Pydantic-Modell fuer Action-Argumente
Eigene Type-Strings, nicht zentral abgeglichen
Backend-Funktionen
Methods
gateway/modules/workflows/methods/methodTrustee/
platform-core/modules/workflows/methods/methodTrustee/
methodSharepoint, methodOutlook, methodAi,<br/>methodClickup, methodRedmine, methodFile, ...
Jede Method-Klasse hat _actions Dict
Action-Definition WorkflowActionDefinition
@ -150,9 +150,9 @@ flowchart TB
| Schicht | Verantwortet | Single Source of Truth |
|---|---|---|
| **1 Typen-Katalog** | "Welche Datenstrukturen gibt es?" | `gateway/modules/features/graphicalEditor/portTypes.py` (erweitert) |
| **2 Methods/Actions** | "Was kann das Backend? Mit welchen typisierten Args?" | `gateway/modules/workflows/methods/method*/method*.py` |
| **3 Adapter (Node + Tool)** | "Wie wird das im Editor / Agent exponiert?" | `gateway/modules/features/graphicalEditor/nodeDefinitions/*.py` (umgebaut zu Adapter), `actionToolAdapter.py` (existiert schon) |
| **1 Typen-Katalog** | "Welche Datenstrukturen gibt es?" | `platform-core/modules/features/graphicalEditor/portTypes.py` (erweitert) |
| **2 Methods/Actions** | "Was kann das Backend? Mit welchen typisierten Args?" | `platform-core/modules/workflows/methods/method*/method*.py` |
| **3 Adapter (Node + Tool)** | "Wie wird das im Editor / Agent exponiert?" | `platform-core/modules/features/graphicalEditor/nodeDefinitions/*.py` (umgebaut zu Adapter), `actionToolAdapter.py` (existiert schon) |
| **4 Instanz-Bindings** | "Wie ist DIESER Workflow / DIESER Tool-Call konkret verkabelt?" | gespeicherter Workflow-Graph, LLM-Tool-Call zur Laufzeit |
---
@ -485,18 +485,18 @@ flowchart LR
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|---|---|---|---|---|---|
| T1 | 1 | unit | ja | gateway/tests/unit/graphicalEditor/test_portTypes_catalog.py (Datei statt `test_catalog_validator.py`) | done (39 ok) |
| T2 | 2 | unit | ja | gateway/tests/unit/methods/test_action_signature_validator.py | done (45 ok) |
| T3 | 3 | unit | ja | gateway/tests/unit/graphicalEditor/test_adapter_validator.py | done (15 ok) |
| T4 | 4 | integration | ja | gateway/tests/integration/trustee/test_spesenbelege_workflow_e2e.py | deferred (eigene Story — Trustee-DB-Setup) |
| T5 | 5 | unit-fe | ja | frontend_nyla/src/components/FlowEditor/nodes/shared/__tests__/RequiredAttributePicker.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T6 | 6 | unit-fe | ja | frontend_nyla/src/components/FlowEditor/nodes/shared/__tests__/RequiredAttributePicker.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T7 | 7 | unit-fe | ja | frontend_nyla/src/components/FlowEditor/nodes/shared/__tests__/DataPicker.strict.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T8 | 8 | unit-fe | ja | frontend_nyla/src/components/FlowEditor/nodes/shared/__tests__/DataPicker.drillDown.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T9 | 9 | e2e | ja | frontend_nyla/e2e/workflows/save-with-errors.spec.ts | deferred (FE-E2E-Setup fehlt) |
| T10 | 10 | unit-fe | ja | frontend_nyla/src/components/FlowEditor/editor/__tests__/RunButton.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T11 | 11 | migration | ja | gateway/tests/integration/automation2/test_pick_not_push_migration_v2.py | done (9 ok) + Unit-Coverage in tests/unit/workflows/test_featureInstanceRefMigration.py (33 ok) |
| T12 | 12 | unit | ja | gateway/tests/unit/serviceAgent/test_action_tool_adapter_typed.py | done (17 ok) |
| T1 | 1 | unit | ja | platform-core/tests/unit/graphicalEditor/test_portTypes_catalog.py (Datei statt `test_catalog_validator.py`) | done (39 ok) |
| T2 | 2 | unit | ja | platform-core/tests/unit/methods/test_action_signature_validator.py | done (45 ok) |
| T3 | 3 | unit | ja | platform-core/tests/unit/graphicalEditor/test_adapter_validator.py | done (15 ok) |
| T4 | 4 | integration | ja | platform-core/tests/integration/trustee/test_spesenbelege_workflow_e2e.py | deferred (eigene Story — Trustee-DB-Setup) |
| T5 | 5 | unit-fe | ja | ui-nyla/src/components/FlowEditor/nodes/shared/__tests__/RequiredAttributePicker.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T6 | 6 | unit-fe | ja | ui-nyla/src/components/FlowEditor/nodes/shared/__tests__/RequiredAttributePicker.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T7 | 7 | unit-fe | ja | ui-nyla/src/components/FlowEditor/nodes/shared/__tests__/DataPicker.strict.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T8 | 8 | unit-fe | ja | ui-nyla/src/components/FlowEditor/nodes/shared/__tests__/DataPicker.drillDown.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T9 | 9 | e2e | ja | ui-nyla/e2e/workflows/save-with-errors.spec.ts | deferred (FE-E2E-Setup fehlt) |
| T10 | 10 | unit-fe | ja | ui-nyla/src/components/FlowEditor/editor/__tests__/RunButton.test.tsx | deferred (FE-Test-Infrastruktur fehlt) |
| T11 | 11 | migration | ja | platform-core/tests/integration/automation2/test_pick_not_push_migration_v2.py | done (9 ok) + Unit-Coverage in tests/unit/workflows/test_featureInstanceRefMigration.py (33 ok) |
| T12 | 12 | unit | ja | platform-core/tests/unit/serviceAgent/test_action_tool_adapter_typed.py | done (17 ok) |
| T13 | — | manual | nein | local/temp/uxPrototype.html — angepasst auf neue Architektur | pending |
---
@ -513,14 +513,14 @@ flowchart LR
## Abschluss
- [ ] `b-reference/gateway/architecture.md` aktualisiert (4-Schichten-Modell)
- [ ] `b-reference/gateway/workflow.md` aktualisiert (Action-Signaturen +
- [ ] `b-reference/platform-core/architecture.md` aktualisiert (4-Schichten-Modell)
- [ ] `b-reference/platform-core/workflow.md` aktualisiert (Action-Signaturen +
Adapter)
- [ ] `b-reference/gateway/ai-agent.md` aktualisiert (Tool-Generierung aus
- [ ] `b-reference/platform-core/ai-agent.md` aktualisiert (Tool-Generierung aus
Katalog statt Heuristik)
- [ ] `b-reference/gateway/features/trustee.md` aktualisiert (typisierte
- [ ] `b-reference/platform-core/features/trustee.md` aktualisiert (typisierte
Inputs/Outputs)
- [ ] `b-reference/frontend-nyla/architecture.md` aktualisiert
- [ ] `b-reference/ui-nyla/architecture.md` aktualisiert
(RequiredAttributePicker, Object-Drill-Down, Loop-Vorschlag)
- [ ] `TOPICS.md` aktualisiert (neues Thema "Typed Action Architecture")
- [ ] Dieses Dokument → `c-work/2-build/` waehrend Umsetzung

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-24 -->
<!-- completed: 2026-04-24 -->
<!-- component: gateway, frontend-nyla, wiki -->
<!-- component: gateway, ui-nyla, wiki -->
<!-- depends-on: c-work/4-done/2026-04-typed-action-architecture.md -->
# Typed Action Architecture — Folge-Plan (Validate → Done)
@ -74,7 +74,7 @@ mindmap
D2 workflow.md<br/>(Action-Signaturen + Adapter)
D3 ai-agent.md<br/>(Tool-Generierung aus Katalog)
D4 features/trustee.md<br/>(typisierte Inputs/Outputs)
D5 frontend-nyla/architecture.md<br/>(RequiredAttributePicker,<br/>Object-Drill-Down,<br/>Loop-Vorschlag)
D5 ui-nyla/architecture.md<br/>(RequiredAttributePicker,<br/>Object-Drill-Down,<br/>Loop-Vorschlag)
D6 TOPICS.md<br/>(neuer Eintrag<br/>"Typed Action Architecture")
E) Doc-Lifecycle
E1 Architektur-Plan ->4-done<br/>nach Abschluss D
@ -144,11 +144,11 @@ mindmap
- `components/FlowEditor/editor/__tests__/RunButton.test.tsx` (neu) — A1
- `e2e/workflows/save-with-errors.spec.ts` (neu, falls Playwright) — A3
- **Wiki:**
- `b-reference/gateway/architecture.md` — D1
- `b-reference/gateway/workflow.md` — D2
- `b-reference/gateway/ai-agent.md` — D3
- `b-reference/gateway/features/trustee.md` — D4
- `b-reference/frontend-nyla/architecture.md` — D5
- `b-reference/platform-core/architecture.md` — D1
- `b-reference/platform-core/workflow.md` — D2
- `b-reference/platform-core/ai-agent.md` — D3
- `b-reference/platform-core/features/trustee.md` — D4
- `b-reference/ui-nyla/architecture.md` — D5
- `TOPICS.md` — D6
- `c-work/3-validate/2026-04-typed-action-architecture.md`
bei Abschluss → `4-done/` (E1) → `z-archive/` (E2)
@ -211,10 +211,10 @@ mindmap
### C) Operatives
- [x] C1: DB-CLI-Migrationsskript
`gateway/scripts/script_migrate_feature_instance_refs.py` —
`platform-core/scripts/script_migrate_feature_instance_refs.py` —
walkt `Automation2Workflow` + `AutoVersion`, ruft
`materializeFeatureInstanceRefs`, persistiert mit `--dry-run`-Flag,
Tests in `gateway/tests/unit/scripts/test_migrate_feature_instance_refs.py`
Tests in `platform-core/tests/unit/scripts/test_migrate_feature_instance_refs.py`
(9/9 gruen, idempotent)
- [x] C2: HTML-Prototype `local/temp/uxPrototype.html` aktualisiert —
FeatureInstanceRef-Envelope sichtbar, Strict-Mode-Toggle, `*`-Wildcard-
@ -222,15 +222,15 @@ mindmap
### D) Wissens-Sync (b-reference)
- [x] D1: `b-reference/gateway/architecture.md` — Abschnitt
- [x] D1: `b-reference/platform-core/architecture.md` — Abschnitt
"Typed Action Architecture (4-Schichten)" ergaenzt, `lastReviewed` 2026-04-24
- [x] D2: `b-reference/gateway/workflow.md` — Abschnitt "Typed Action Architecture
- [x] D2: `b-reference/platform-core/workflow.md` — Abschnitt "Typed Action Architecture
(Phasen 1-5)": Catalog, Adapter, Pick-not-Push, `*`-Wildcard, Save-with-errors
- [x] D3: `b-reference/gateway/ai-agent.md` — `ActionToolAdapter`-Notiz mit
- [x] D3: `b-reference/platform-core/ai-agent.md` — `ActionToolAdapter`-Notiz mit
Tool-Generierung aus Catalog statt Heuristik
- [x] D4: `b-reference/gateway/features/trustee.md` — neue kanonische Seite
- [x] D4: `b-reference/platform-core/features/trustee.md` — neue kanonische Seite
mit Actions, Datenmodell, FeatureInstanceRef, AccountingBridge, Tests
- [x] D5: `b-reference/frontend-nyla/architecture.md` — Abschnitt
- [x] D5: `b-reference/ui-nyla/architecture.md` — Abschnitt
"FlowEditor -- Typed Action Architecture" mit Picker-Komponenten,
Save/Run-Gating und Vitest+RTL-Tests
- [x] D6: `wiki/TOPICS.md` — Eintrag "Typed Action Architecture" mit Verweisen
@ -267,12 +267,12 @@ mindmap
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|---|---|---|---|---|---|
| F1 | 1 | smoke | ja | `frontend_nyla/vitest.config.ts` + `vitest.setup.ts` | done |
| F2 | 2 | unit-fe | ja | `frontend_nyla/src/components/FlowEditor/nodes/shared/*.test.tsx`, `editor/CanvasHeader.test.tsx` | done (34/34) |
| F3 | 3 | integration | ja | `gateway/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | done (3/3) |
| F4 | 4 | unit | ja | `gateway/tests/unit/graphicalEditor/test_adapter_validator.py` (Snapshot leer, `_KNOWN_ADAPTER_DRIFTS = frozenset()`) | done |
| F5 | 5,6 | manual+integration | ja | `gateway/scripts/script_migrate_feature_instance_refs.py` + `gateway/tests/unit/scripts/test_migrate_feature_instance_refs.py` | done (9/9) |
| F6 | 7,8 | manual | nein | `wiki/b-reference/gateway/{architecture,workflow,ai-agent,features/trustee}.md`, `wiki/b-reference/frontend-nyla/architecture.md`, `wiki/TOPICS.md` (alle `lastReviewed: 2026-04-24`) | done |
| F1 | 1 | smoke | ja | `ui-nyla/vitest.config.ts` + `vitest.setup.ts` | done |
| F2 | 2 | unit-fe | ja | `ui-nyla/src/components/FlowEditor/nodes/shared/*.test.tsx`, `editor/CanvasHeader.test.tsx` | done (34/34) |
| F3 | 3 | integration | ja | `platform-core/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | done (3/3) |
| F4 | 4 | unit | ja | `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py` (Snapshot leer, `_KNOWN_ADAPTER_DRIFTS = frozenset()`) | done |
| F5 | 5,6 | manual+integration | ja | `platform-core/scripts/script_migrate_feature_instance_refs.py` + `platform-core/tests/unit/scripts/test_migrate_feature_instance_refs.py` | done (9/9) |
| F6 | 7,8 | manual | nein | `wiki/b-reference/platform-core/{architecture,workflow,ai-agent,features/trustee}.md`, `wiki/b-reference/ui-nyla/architecture.md`, `wiki/TOPICS.md` (alle `lastReviewed: 2026-04-24`) | done |
| F7 | 9 | manual | nein | `wiki/c-work/4-done/2026-04-typed-action-architecture.md` | done |
---

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-23 -->
<!-- completed: 2026-04-23 -->
<!-- component: gateway, frontend-nyla -->
<!-- component: gateway, ui-nyla -->
# Typed Generic Handover für den Graphical Editor — PicknotPush, StaticOnly Schemas, Hard Validation
@ -31,11 +31,11 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
### Was schon da ist (verifiziert im Code, 20260423)
- `gateway/modules/features/graphicalEditor/portTypes.py` — `PortField`, `PortSchema`, `PORT_TYPE_CATALOG`, `SYSTEM_VARIABLES`, `_normalizeToSchema`, `INPUT_EXTRACTORS`.
- `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py` — `_wireHandover()` (zu entfernen), `_resolveConnectionParam()` (bleibt im neuen Modell, Anwendung verschiebt sich).
- `frontend_nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx` — schemabasierte PfadAuflösung mit TransitChain, SystemSektion.
- `frontend_nyla/src/components/FlowEditor/nodes/frontendTypeRenderers/index.tsx` — `FRONTEND_TYPE_RENDERERS` Registry.
- `frontend_nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx` — generischer ConfigRenderer.
- `platform-core/modules/features/graphicalEditor/portTypes.py` — `PortField`, `PortSchema`, `PORT_TYPE_CATALOG`, `SYSTEM_VARIABLES`, `_normalizeToSchema`, `INPUT_EXTRACTORS`.
- `platform-core/modules/workflows/automation2/executors/actionNodeExecutor.py` — `_wireHandover()` (zu entfernen), `_resolveConnectionParam()` (bleibt im neuen Modell, Anwendung verschiebt sich).
- `ui-nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx` — schemabasierte PfadAuflösung mit TransitChain, SystemSektion.
- `ui-nyla/src/components/FlowEditor/nodes/frontendTypeRenderers/index.tsx` — `FRONTEND_TYPE_RENDERERS` Registry.
- `ui-nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx` — generischer ConfigRenderer.
### Was fragil / kritisch wird
@ -74,7 +74,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
## Betroffene Module
**Gateway (`gateway/modules/`):**
**Gateway (`platform-core/modules/`):**
- `features/graphicalEditor/portTypes.py``PortField` erweitern (`itemSchema`, `fields`, `enumValues`); `PORT_TYPE_CATALOG` erweitern um `Document`, `FileItem`, `EmailItem`, `TaskItem`, `ConnectionRef`, `SharePointFolderRef`, `SharePointFileRef`; `INPUT_EXTRACTORS` **entfernen**.
- `features/graphicalEditor/nodeDefinitions/*.py` — alle Outputs anreichern um Provenienz (`source`, `connection`) wo sinnvoll; `outputPorts.dynamic`/`deriveFrom` Marker auf `input.form` beschränken und in `{kind: "fromGraph", parameter: "fields"}`Form normalisieren.
- `features/graphicalEditor/nodeRegistry.py` + `routeFeatureGraphicalEditor.py` — neue Endpoints: `GET /{instanceId}/upstream-paths/{nodeId}`, `POST /{instanceId}/validate-graph`.
@ -85,14 +85,14 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
- `workflows/methods/sharepoint/`, `methods/outlook/`, `methods/clickup/`, `methods/trustee/`, `methods/file/` — AdapterOutputs anreichern (ConnectionRef, SourcePfad).
- MigrationsSkript `scripts/migration/2026-04-pick-not-push-migration.py` (neu) — scannt `AutoWorkflow.graph`, ergänzt explizite DataRefs anstelle implizitem WireHandover.
- TestPakete:
- `gateway/tests/unit/graphicalEditor/test_port_schema_recursive.py`
- `gateway/tests/unit/graphicalEditor/test_validate_typed_hard.py`
- `gateway/tests/integration/graphicalEditor/test_upstream_paths_api.py`
- `gateway/tests/integration/graphicalEditor/test_pwg_pilot_typed.py`
- `gateway/tests/unit/migration/test_pick_not_push_migration.py`
- `platform-core/tests/unit/graphicalEditor/test_port_schema_recursive.py`
- `platform-core/tests/unit/graphicalEditor/test_validate_typed_hard.py`
- `platform-core/tests/integration/graphicalEditor/test_upstream_paths_api.py`
- `platform-core/tests/integration/graphicalEditor/test_pwg_pilot_typed.py`
- `platform-core/tests/unit/migration/test_pick_not_push_migration.py`
- pro Adapter (sharepoint/outlook/clickup/trustee/file): SchemaComplianceTest
**Frontend (`frontend_nyla/src/`):**
**Frontend (`ui-nyla/src/`):**
- `api/workflowApi.ts` — Interfaces: `PortSchema` rekursiv (`fields`, `itemSchema`); `DataRef.expectedType`; `NodeType.outputPorts.schema` darf `string | {kind:"fromGraph", parameter:string}` sein.
- `components/FlowEditor/nodes/shared/dataRef.ts``DataRef` um `expectedType` erweitern; Helper `isCompatible(produced, accepted)`.
- `components/FlowEditor/nodes/shared/DataPicker.tsx` — Scope: BFS rückwärts via Connections + transitive LoopBodyHierarchie; rekursive SchemaNavigation (verschachtelte fields, list `itemSchema` unwrap); `loop.item`/`loop.index`/`loop.total` pro umgebendem Loop; TypeCompatPills.
@ -106,7 +106,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
**DBMigration:** Nein im SchemaSinn (kein `AutoWorkflow`TableChange). **DatenMigration ja:** `AutoWorkflow.graph`JSON wird einmalig durch MigrationsSkript transformiert.
**Andere Komponenten:**
- AI Agent (`gateway/modules/serviceCenter/services/serviceAgent/`): `workflowTools` ToolSchemas erweitern, sodass `bindNodeParameter`Tool die KI zur expliziten DataRefErzeugung führt; Prompts für WorkflowGeneration aktualisieren.
- AI Agent (`platform-core/modules/serviceCenter/services/serviceAgent/`): `workflowTools` ToolSchemas erweitern, sodass `bindNodeParameter`Tool die KI zur expliziten DataRefErzeugung führt; Prompts für WorkflowGeneration aktualisieren.
## Entscheidungen
@ -143,7 +143,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
- [ ] `methods/clickup/` analog.
- [ ] `methods/trustee/` (`extractFromFiles`, `processDocuments`): UDMOutput sauber rekursiv typisieren.
- [ ] `methods/file/create`: OutputSchema auf `Document` mappen.
- [ ] Pro Adapter ein ComplianceTest (`gateway/tests/integration/methods/test_<method>_schema_compliance.py`): mock + reale MiniOutputs gegen SollSchema validiert.
- [ ] Pro Adapter ein ComplianceTest (`platform-core/tests/integration/methods/test_<method>_schema_compliance.py`): mock + reale MiniOutputs gegen SollSchema validiert.
### Phase 3 — LoopScoping & DataPicker (Frontend)
- [ ] `nodes/shared/scopeHelpers.ts` (neu): `computePickableScope(nodeId, graph, nodeTypes)` — BFS rückwärts via `connections` + transitive LoopBodyHierarchie; `unwrapListItemSchema(producerSchema, fieldPath)` für LoopItemTyp; `resolveTransitChain(nodeId, graph, nodeTypes)` für TransitAuflösung.
@ -198,9 +198,9 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
- [ ] `data.transform` Nodes in alten Workflows: MigrationsSkript gibt Warnung pro Vorkommen aus (manuell zu refactoren — kein AutoCleanup, weil semantisch).
### Phase 10 — Dokumentation & Abschluss
- [ ] `wiki/b-reference/gateway/automation.md`: Abschnitt „PicknotPush Handover" + Removed `INPUT_EXTRACTORS`.
- [ ] `wiki/b-reference/gateway/workflow.md`: Abschnitt UDM/Loop/KIBadge ergänzen um neue SchemaTiefe und LoopScoping.
- [ ] `wiki/b-reference/frontend-nyla/architecture.md`: Abschnitt FlowEditor mit TypeCompat, AutoSuggest, HybridConnectionPicker.
- [ ] `wiki/b-reference/platform-core/automation.md`: Abschnitt „PicknotPush Handover" + Removed `INPUT_EXTRACTORS`.
- [ ] `wiki/b-reference/platform-core/workflow.md`: Abschnitt UDM/Loop/KIBadge ergänzen um neue SchemaTiefe und LoopScoping.
- [ ] `wiki/b-reference/ui-nyla/architecture.md`: Abschnitt FlowEditor mit TypeCompat, AutoSuggest, HybridConnectionPicker.
- [ ] `wiki/TOPICS.md`: Eintrag „Typed Generic Handover (build/done)" verlinken.
- [ ] PlanDoc Status updaten und nach `c-work/2-build/``c-work/3-validate/``c-work/4-done/` durchschieben.
@ -224,17 +224,17 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
| ID | AC | Art | Automatisiert | RepoPfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | `gateway/tests/integration/graphicalEditor/test_pwg_pilot_typed.py` | pending |
| T2 | 2 | unit | ja | `gateway/tests/unit/graphicalEditor/test_validate_typed_hard.py` | pending |
| T3 | 3 | frontend unit | ja | `frontend_nyla/src/components/FlowEditor/__tests__/dataPicker.scope.test.ts` | pending |
| T4 | 4 | frontend unit + backend unit | ja | `frontend_nyla/.../__tests__/dataPicker.formSchema.test.ts` + `gateway/tests/unit/graphicalEditor/test_parse_graph_defined_schema.py` | pending |
| T5 | 5 | api | ja | `gateway/tests/integration/graphicalEditor/test_upstream_paths_api.py` | pending |
| T6 | 6 | migration | ja | `gateway/tests/unit/migration/test_pick_not_push_migration.py` | pending |
| T7 | 7 | frontend unit | ja | `frontend_nyla/.../__tests__/dataPicker.typeCompat.test.ts` | pending |
| T8 | 8 | frontend e2e | ja (Playwright opt) | `frontend_nyla/tests/e2e/wireAutoSuggest.spec.ts` | pending |
| T9 | 9 | frontend unit | ja | `frontend_nyla/.../__tests__/connectionPicker.modes.test.ts` | pending |
| T10 | 10 | api/integration | ja | `gateway/tests/integration/methods/test_sharepoint_schema_compliance.py` (+ `_outlook`, `_clickup`, `_trustee`, `_file`) | pending |
| T11 | 11 | unit | ja | `gateway/tests/unit/migration/test_data_transform_warning.py` | pending |
| T1 | 1 | integration | ja | `platform-core/tests/integration/graphicalEditor/test_pwg_pilot_typed.py` | pending |
| T2 | 2 | unit | ja | `platform-core/tests/unit/graphicalEditor/test_validate_typed_hard.py` | pending |
| T3 | 3 | frontend unit | ja | `ui-nyla/src/components/FlowEditor/__tests__/dataPicker.scope.test.ts` | pending |
| T4 | 4 | frontend unit + backend unit | ja | `ui-nyla/.../__tests__/dataPicker.formSchema.test.ts` + `platform-core/tests/unit/graphicalEditor/test_parse_graph_defined_schema.py` | pending |
| T5 | 5 | api | ja | `platform-core/tests/integration/graphicalEditor/test_upstream_paths_api.py` | pending |
| T6 | 6 | migration | ja | `platform-core/tests/unit/migration/test_pick_not_push_migration.py` | pending |
| T7 | 7 | frontend unit | ja | `ui-nyla/.../__tests__/dataPicker.typeCompat.test.ts` | pending |
| T8 | 8 | frontend e2e | ja (Playwright opt) | `ui-nyla/tests/e2e/wireAutoSuggest.spec.ts` | pending |
| T9 | 9 | frontend unit | ja | `ui-nyla/.../__tests__/connectionPicker.modes.test.ts` | pending |
| T10 | 10 | api/integration | ja | `platform-core/tests/integration/methods/test_sharepoint_schema_compliance.py` (+ `_outlook`, `_clickup`, `_trustee`, `_file`) | pending |
| T11 | 11 | unit | ja | `platform-core/tests/unit/migration/test_data_transform_warning.py` | pending |
## Links
@ -247,9 +247,9 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
## Abschluss
- [ ] `wiki/b-reference/gateway/automation.md` aktualisiert (PicknotPush, Removed Heuristik)
- [ ] `wiki/b-reference/gateway/workflow.md` aktualisiert (SchemaTiefe, LoopScoping)
- [ ] `wiki/b-reference/frontend-nyla/architecture.md` aktualisiert (FlowEditorErweiterungen)
- [ ] `wiki/b-reference/platform-core/automation.md` aktualisiert (PicknotPush, Removed Heuristik)
- [ ] `wiki/b-reference/platform-core/workflow.md` aktualisiert (SchemaTiefe, LoopScoping)
- [ ] `wiki/b-reference/ui-nyla/architecture.md` aktualisiert (FlowEditorErweiterungen)
- [ ] `wiki/TOPICS.md` aktualisiert (neuer Eintrag „Typed Generic Handover")
- [ ] Dieses Dokument → `wiki/z-archive/` verschoben
@ -257,7 +257,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
## Anhang A — SchemaAudit (SollStand pro NodeOutput)
> Wird in Phase 0 vollständig befüllt; hier die Zielform und der Anfang der Inhalte. Stand `PORT_TYPE_CATALOG` heute siehe `gateway/modules/features/graphicalEditor/portTypes.py:59170`.
> Wird in Phase 0 vollständig befüllt; hier die Zielform und der Anfang der Inhalte. Stand `PORT_TYPE_CATALOG` heute siehe `platform-core/modules/features/graphicalEditor/portTypes.py:59170`.
### Neue / erweiterte ItemSchemas im Katalog

View file

@ -2,7 +2,7 @@
<!-- started: 2026-04-19 -->
<!-- built: 2026-04-21 -->
<!-- done: 2026-04-21 -->
<!-- component: frontend-nyla -->
<!-- component: ui-nyla -->
<!-- relatedTo: c-work/3-validate/2026-04-pwg-pilot-mietzinsbestaetigung-workflow.md (Phase 2 deferred item — jetzt erfüllt) -->
<!-- validation: separate manuelle Smoke-Tests durch User; Code-Smoke (`tsc -b`, `eslint`, `vite build`) clean. -->
@ -10,7 +10,7 @@
## Beschreibung und Kontext
Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie zeigt Files, Folders, Chats, Sources und Konversations-Artefakte. Der Kern jeder Ansicht ist die Komponente `FolderTree` (`frontend_nyla/src/components/FolderTree/FolderTree.tsx`). Sie wird heute in mehreren Kontexten verwendet:
Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie zeigt Files, Folders, Chats, Sources und Konversations-Artefakte. Der Kern jeder Ansicht ist die Komponente `FolderTree` (`ui-nyla/src/components/FolderTree/FolderTree.tsx`). Sie wird heute in mehreren Kontexten verwendet:
| Kontext | Datei | Zweck |
|---------|-------|-------|
@ -65,7 +65,7 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
### Phase 1 — Action-Modell + Registry-Hook
- [x] ✅ DONE — Neue Datei `frontend_nyla/src/components/FolderTree/actions/types.ts`:
- [x] ✅ DONE — Neue Datei `ui-nyla/src/components/FolderTree/actions/types.ts`:
```ts
export type FileActionScope = 'file' | 'folder' | 'multi';
@ -100,7 +100,7 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
}
```
- [x] ✅ DONE — Neue Datei `frontend_nyla/src/components/FolderTree/actions/registry.ts` mit:
- [x] ✅ DONE — Neue Datei `ui-nyla/src/components/FolderTree/actions/registry.ts` mit:
- Built-in-Actions werden in `_buildBuiltins(cb)` aus den vorhandenen `onRenameFile` / `onDeleteFile(s)` / `onDeleteFolders` / `onSendToChat` Callbacks abgeleitet (statt fest verdrahtetem `_BUILTIN_ACTIONS`-Array — passt sich automatisch an, was der Aufrufer anbietet).
- `useFileActions(ctx, customs?, builtins)` Hook → liefert `{ all, forTarget }`. `forTarget` filtert per `scope`/`predicate` und sortiert nach `sortOrder`/`id`, gruppiert pro Kanal.
- `runAction(action, target, ctx, confirmFn?)`-Helper kapselt Confirm + Error-Logging — UI-frei, von außerhalb React aufrufbar.
@ -159,7 +159,7 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
### Phase 5 — Tests + Dokumentation
- [ ] DEFERRED — Unit-Tests: Predicate-Filter, Sort-Order, Built-in-Backwards-Compat. Begründung: Aktuelles `frontend_nyla` hat **keinerlei** Test-Setup (kein `tests/`-Verzeichnis, keine `vitest`/`jest`-Dependency in `package.json`, kein `test`-Script). Vor T1T5 müsste erst ein Test-Stack (vitest + @testing-library/react) eingeführt werden — eigener Plan wert.
- [ ] DEFERRED — Unit-Tests: Predicate-Filter, Sort-Order, Built-in-Backwards-Compat. Begründung: Aktuelles `ui-nyla` hat **keinerlei** Test-Setup (kein `tests/`-Verzeichnis, keine `vitest`/`jest`-Dependency in `package.json`, kein `test`-Script). Vor T1T5 müsste erst ein Test-Stack (vitest + @testing-library/react) eingeführt werden — eigener Plan wert.
- [ ] DEFERRED — Storybook-Story: keine Storybook-Setup im Repo (`.storybook/` fehlt) → analog Test-Setup eigener Plan nötig.
- [ ] PENDING — Doku-Snippet `wiki/uiPatterns/udbActions.md` mit „Wie registriere ich eine Custom-Action".
- [ ] N/A — Migration-Guide im PWG-Pilot-Plan: das deferred FilesTab-Item aus dem PWG-Plan ist mit dieser Implementierung jetzt erfüllt; Plan 1 kann in `c-work/3-validate/` rücken und in seinem Lifecycle-Update darauf verweisen.
@ -190,11 +190,11 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|---|---|---|
| T1 | 1, 5, 8 | unit | ja | `frontend_nyla/tests/components/FolderTree/actions.test.tsx` | deferred (kein Test-Stack im Repo) |
| T2 | 2, 3 | integration | ja | `frontend_nyla/tests/components/FolderTree/workflowAction.test.tsx` | deferred (s. T1) |
| T1 | 1, 5, 8 | unit | ja | `ui-nyla/tests/components/FolderTree/actions.test.tsx` | deferred (kein Test-Stack im Repo) |
| T2 | 2, 3 | integration | ja | `ui-nyla/tests/components/FolderTree/workflowAction.test.tsx` | deferred (s. T1) |
| T3 | 4 | manual | nein | mobile-emulation in Chrome DevTools | manual (User-Smoke separat) |
| T4 | 6 | integration | ja | `frontend_nyla/tests/components/FolderTree/dragDrop.test.tsx` | deferred (s. T1) |
| T5 | 7 | unit | ja | `frontend_nyla/tests/components/FolderTree/shortcuts.test.tsx` | deferred (s. T1) |
| T4 | 6 | integration | ja | `ui-nyla/tests/components/FolderTree/dragDrop.test.tsx` | deferred (s. T1) |
| T5 | 7 | unit | ja | `ui-nyla/tests/components/FolderTree/shortcuts.test.tsx` | deferred (s. T1) |
## Inspirations / State-of-the-Art
@ -206,12 +206,12 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
## Links
- Heutiger `FolderTree`: `frontend_nyla/src/components/FolderTree/FolderTree.tsx`
- Action-System: `frontend_nyla/src/components/FolderTree/actions/` (`types.ts`, `registry.ts`, `useViewMode.ts`, `usePointerLongPress.ts`, `FileActionContextMenu.tsx`, `FileActionBottomSheet.tsx`)
- Konsumenten: `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`, `frontend_nyla/src/pages/basedata/FilesPage.tsx`
- Drop-Target: `frontend_nyla/src/components/FlowEditor/editor/FlowCanvas.tsx` (`onExternalDrop`-Prop) + `Automation2FlowEditor.tsx` (Wiring)
- Datei-Context: `frontend_nyla/src/contexts/FileContext.tsx`
- Workflow-API: `frontend_nyla/src/api/workflowApi.ts` (`importWorkflowFromFile`, `isWorkflowFileContent`)
- Heutiger `FolderTree`: `ui-nyla/src/components/FolderTree/FolderTree.tsx`
- Action-System: `ui-nyla/src/components/FolderTree/actions/` (`types.ts`, `registry.ts`, `useViewMode.ts`, `usePointerLongPress.ts`, `FileActionContextMenu.tsx`, `FileActionBottomSheet.tsx`)
- Konsumenten: `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx`, `ui-nyla/src/pages/basedata/FilesPage.tsx`
- Drop-Target: `ui-nyla/src/components/FlowEditor/editor/FlowCanvas.tsx` (`onExternalDrop`-Prop) + `Automation2FlowEditor.tsx` (Wiring)
- Datei-Context: `ui-nyla/src/contexts/FileContext.tsx`
- Workflow-API: `ui-nyla/src/api/workflowApi.ts` (`importWorkflowFromFile`, `isWorkflowFileContent`)
- Verwandter Plan: `wiki/c-work/1-plan/2026-04-pwg-pilot-mietzinsbestaetigung-workflow.md` (Phase 2 deferred → jetzt erfüllt)
## Offene Punkte / Follow-ups

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-04-08 -->
<!-- completed: 2026-04-08 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# UI-Mehrsprachigkeit: Dynamische Sprachsets (DB-backed i18n)
@ -116,7 +116,7 @@ Falls nötig (z.B. "Offen" = "Open" vs. "Outstanding"): `t('Offen (Status)')` vs
Bei **Update**, **Update All** und dem dedizierten Endpunkt `PUT /api/i18n/sets/sync-de` wird automatisch:
1. Alle `.ts`/`.tsx`-Dateien unter `frontend_nyla/src/` nach `t('...')`-Aufrufen gescannt
1. Alle `.ts`/`.tsx`-Dateien unter `ui-nyla/src/` nach `t('...')`-Aufrufen gescannt
2. Neue Keys (in Codebase, nicht in DB) → zum `de`-Set hinzugefügt (Key = Value = deutscher Klartext)
3. Verwaiste Keys (in DB, nicht mehr in Codebase) → aus dem `de`-Set entfernt
4. Danach erst werden die Non-`de`-Sets synchronisiert (fehlende Keys per AI übersetzen, überzählige entfernen)
@ -189,7 +189,7 @@ Bei **Update**, **Update All** und dem dedizierten Endpunkt `PUT /api/i18n/sets/
## Links
- LanguageContext: `frontend_nyla/src/providers/language/LanguageContext.tsx`
- API-Route: `gateway/modules/routes/routeI18n.py`
- Admin-Seite: `frontend_nyla/src/pages/admin/AdminLanguagesPage.tsx`
- Seed-Daten: `gateway/modules/migration/seedData/ui_language_seed.json`
- LanguageContext: `ui-nyla/src/providers/language/LanguageContext.tsx`
- API-Route: `platform-core/modules/routes/routeI18n.py`
- Admin-Seite: `ui-nyla/src/pages/admin/AdminLanguagesPage.tsx`
- Seed-Daten: `platform-core/modules/migration/seedData/ui_language_seed.json`

View file

@ -2,7 +2,7 @@
<!-- started: 2026-04-21 -->
<!-- code-complete: 2026-04-21 -->
<!-- closed: 2026-04-21 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# Bundle: UI-Polish-Sprint Q2 (Format-Hints, UDB-Container, Store, Modal-Audit, Node-Mapping)
@ -35,8 +35,8 @@ Risiko bei Nicht-Umsetzung: Demos zeigen Roh-Floats wie `4567777788`, Modals wer
Fragile Stellen:
- `gateway/modules/shared/attributeUtils.py::getAttributesForTable` die zwei parallelen Pfade (`field_info.extra` vs. `json_schema_extra`) sind heute schon redundant. Neue Felder durchgängig über **beide** Pfade lesen, sonst latenter Bug.
- `frontend_nyla/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx::formatCellValue` wird auch im PDF-Export benutzt (prüfen). Format-Funktion muss reine Funktion sein.
- `platform-core/modules/shared/attributeUtils.py::getAttributesForTable` die zwei parallelen Pfade (`field_info.extra` vs. `json_schema_extra`) sind heute schon redundant. Neue Felder durchgängig über **beide** Pfade lesen, sonst latenter Bug.
- `ui-nyla/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx::formatCellValue` wird auch im PDF-Export benutzt (prüfen). Format-Funktion muss reine Funktion sein.
## Ziel und Nicht-Ziele
@ -135,8 +135,8 @@ Ohne diese Hints: heutiges Default-Rendering bleibt.
- `modules/connectors/providerMsft/connectorMsft.py` (Thema 6: neue `OutlookAdapter`-Methoden `replyToMail`, `replyAllToMail`, `forwardMail`, `createReplyDraft`, `createReplyAllDraft`)
- `modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` (Thema 6: Toolbox `email` exposed neue Tools)
- `modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` oder neues `_emailTools.py` (Thema 6: Tool-Implementierung `replyToMail` etc.)
- `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx` (Thema 7: Border-Left auf Z.1414 erzeugt 3px-Versatz; aktive Wildcard-Row braucht kompensierenden negativen `marginLeft`)
- `gateway/modules/features/*/main*.py` (Thema 8: alle `DATA_OBJECTS`/`RESOURCE_OBJECTS`-Labels via `t()` registrieren betrifft mind. `mainRedmine.py`, `mainTrustee.py`, `mainCommcoach.py`, `mainChatbot.py`)
- `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` (Thema 7: Border-Left auf Z.1414 erzeugt 3px-Versatz; aktive Wildcard-Row braucht kompensierenden negativen `marginLeft`)
- `platform-core/modules/features/*/main*.py` (Thema 8: alle `DATA_OBJECTS`/`RESOURCE_OBJECTS`-Labels via `t()` registrieren betrifft mind. `mainRedmine.py`, `mainTrustee.py`, `mainCommcoach.py`, `mainChatbot.py`)
- **Frontend**:
- `src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx` (Thema 1: `formatCellValue` ruft neuen `applyFrontendFormat`)
- `src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx` (Thema 1: gleicher Hook für Read-Only-Anzeige)
@ -166,7 +166,7 @@ Ohne diese Hints: heutiges Default-Rendering bleibt.
- [ ] `attributeUtils.py::getAttributesForTable`: `frontend_format` und `frontend_format_labels` aus `json_schema_extra` UND `field_info.extra` lesen, in `attr_def` ausgeben als `format` und `formatLabels`
- [ ] `i18nRegistry.py::i18nModel`: `frontend_format_labels` scannen, jedes Element via `t()` registrieren mit Key `table.<Class>.<field>.label[<idx>]`
- [ ] `getModelLabels()` ergänzen, sodass übersetzte Format-Labels auf Frontend ausgeliefert werden
- [ ] **NEU** `frontend_nyla/src/utils/applyFrontendFormat.ts` mit `applyFrontendFormat(value, format, formatLabels, type, locale)` pure function
- [ ] **NEU** `ui-nyla/src/utils/applyFrontendFormat.ts` mit `applyFrontendFormat(value, format, formatLabels, type, locale)` pure function
- [ ] `FormGeneratorTable::formatCellValue` integrieren (für `cellAlign` ebenfalls nutzen)
- [ ] `FormGeneratorForm` integrieren für read-only Anzeige
- [ ] Unit-Tests für Format-Parser
@ -176,20 +176,20 @@ Ohne diese Hints: heutiges Default-Rendering bleibt.
- [ ] `SourcesTab.tsx`: Buttons (chat / scope-cycle / neutralize-toggle) auf `_GroupFolderView`, `_ParentGroupView`, `_MandateGroupView` ergänzen
- [ ] Container-`objectKey`-Format definieren: `data.feature.<code>.group:<groupKey>.*` (Glob mit `*`)
- [ ] Backend-Resolver `workspaceContext` (in `gateway/modules/aiAgent/`): Globs auflösen, Records-Set zurückliefern
- [ ] Backend-Resolver `workspaceContext` (in `platform-core/modules/aiAgent/`): Globs auflösen, Records-Set zurückliefern
- [ ] Anzeige im Chat-Context: "Container Mandant Müller AG (12 Records)" statt `null`
- [ ] Audit Token-Limits — Container kann gross sein, Warning-UX
### Thema 3 — Store: automation
- [ ] In Feature-Registry (`gateway/modules/datamodels/datamodelFeatures.py` o.ä. Bootstrap): `automation` mit `meta.category = "store"`, `enabled = True`
- [ ] In Feature-Registry (`platform-core/modules/datamodels/datamodelFeatures.py` o.ä. Bootstrap): `automation` mit `meta.category = "store"`, `enabled = True`
- [ ] Optional: Icon/Beschreibung für Store-Card prüfen
- [ ] Smoke-Test: Aktivierung in fresh-Mandant funktioniert
### Thema 4 — Modal-Forms (Outside-Click-Fix)
- [ ] `usePrompt.tsx`: Backdrop-`onClick={_handleCancel}` **entfernen** (oder optional via Prop `dismissOnBackdrop?: boolean = false`)
- [ ] Audit: grep nach `onClick.*Close|onClick.*Cancel` auf Overlay-DIVs in `frontend_nyla/src/`
- [ ] Audit: grep nach `onClick.*Close|onClick.*Cancel` auf Overlay-DIVs in `ui-nyla/src/`
- [ ] Liste der gefundenen Stellen prüfen, jede einzeln korrigieren oder bewusst lassen (z.B. Image-Lightbox: Backdrop schliesst soll bleiben)
- [ ] `Modal.tsx`: Default-Behavior in Doku festschreiben (`closeOnOverlayClick=false`)
@ -269,7 +269,7 @@ Ohne diese Hints: heutiges Default-Rendering bleibt.
### Thema 8 — i18n-Registrierung Feature-Catalog-Labels (systemisch)
- [ ] **Root-Cause-Doku in Plan**: `t(key)` registriert Keys nur lazily zur Aufruf-Zeit. Wenn ein Label nie via `t()` (zur Modul-Import-Zeit) angefasst wurde, fehlt es in `_REGISTRY` zum Zeitpunkt der Übersetzungs-Sammlung → kein Translation-Eintrag → Fallback `[key]` für nicht-DE Sprachen
- [ ] **Audit-Script**: Grep über `gateway/modules/features/*/main*.py` nach Pattern `"label":\s*"[^"]+"` (bare string statt `t(...)`)
- [ ] **Audit-Script**: Grep über `platform-core/modules/features/*/main*.py` nach Pattern `"label":\s*"[^"]+"` (bare string statt `t(...)`)
- [ ] **Fix in `mainRedmine.py`**: alle 5 `DATA_OBJECTS`-Labels (`"Konfiguration"`, `"Redmine-Verbindung"`, `"Redmine-Tickets (Mirror)"`, `"Redmine-Beziehungen (Mirror)"`, `"Alle Redmine-Daten"`) und alle 11 `RESOURCE_OBJECTS`-Labels via `t("…", context="UI")` (oder eigener Context wie `"feature.redmine"`) registrieren
- [ ] **Fix in `mainTrustee.py`**: identisch für DATA_OBJECTS (mind. 7 Labels: `"Lokale Daten"`, `"Konfiguration"`, `"Daten aus Buchhaltungssystem"`, `"Position"`, `"Dokument"`, `"Buchhaltungs-Verbindung"`, `"Sync-Protokoll"`) und Page-/Resource-Labels
- [ ] **Fix in allen weiteren Features** (`commcoach`, `chatbot`, `realEstate`, `automation`, `workspace`, `graphicalEditor`, `neutralization`) pro Feature 1 commit
@ -319,24 +319,24 @@ Ohne diese Hints: heutiges Default-Rendering bleibt.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1,2,3 | unit | ja | `frontend_nyla/src/utils/applyFrontendFormat.test.ts` | pending |
| T2 | 1,2,3 | api | ja | `gateway/tests/test_attributeUtils_format.py` | pending |
| T3 | 3 | api | ja | `gateway/tests/test_i18nModel_formatLabels.py` | pending |
| T1 | 1,2,3 | unit | ja | `ui-nyla/src/utils/applyFrontendFormat.test.ts` | pending |
| T2 | 1,2,3 | api | ja | `platform-core/tests/test_attributeUtils_format.py` | pending |
| T3 | 3 | api | ja | `platform-core/tests/test_i18nModel_formatLabels.py` | pending |
| T4 | 4,5 | e2e | nein (manuell) | UDB → Chat Flow | pending |
| T5 | 6 | api | ja | `gateway/tests/test_routeStore_automation.py` | pending |
| T6 | 7 | unit | ja | `frontend_nyla/src/hooks/usePrompt.test.tsx` | pending |
| T5 | 6 | api | ja | `platform-core/tests/test_routeStore_automation.py` | pending |
| T6 | 7 | unit | ja | `ui-nyla/src/hooks/usePrompt.test.tsx` | pending |
| T7 | 8 | doc | nein | `wiki/b-reference/modal-audit.md` | pending |
| T8 | 9,10 | manuell | nein | Graph-Editor Smoke | pending |
| T9 | 11,12 | api | ja | `gateway/tests/test_outlookAdapter_reply.py` (Mock Graph) | pending |
| T10 | 13 | api | ja | `gateway/tests/test_browseDataSource_mailLimit.py` | pending |
| T9 | 11,12 | api | ja | `platform-core/tests/test_outlookAdapter_reply.py` (Mock Graph) | pending |
| T10 | 13 | api | ja | `platform-core/tests/test_browseDataSource_mailLimit.py` | pending |
| T11 | 11,12,14 | manuell | nein | Real-Outlook Agent-Chat E2E | pending |
| T12 | 15,16 | manuell | nein | UDB Visual-Diff Screenshot vor/nach | pending |
| T13 | 17,18,19 | api | ja | `gateway/tests/test_outlookAdapter_moveDelete.py` (Mock Graph) | pending |
| T14 | 20,21 | api | ja | `gateway/tests/test_outlookAdapter_folderResolve.py` | pending |
| T15 | 22 | api | ja | `gateway/tests/test_outlookAdapter_readState.py` | pending |
| T13 | 17,18,19 | api | ja | `platform-core/tests/test_outlookAdapter_moveDelete.py` (Mock Graph) | pending |
| T14 | 20,21 | api | ja | `platform-core/tests/test_outlookAdapter_folderResolve.py` | pending |
| T15 | 22 | api | ja | `platform-core/tests/test_outlookAdapter_readState.py` | pending |
| T16 | 17,18,19,20 | manuell | nein | Real-Outlook E2E Move/Archive/Delete | pending |
| T17 | 23 | manuell | nein | Sprachwechsel UDB-Test (DE → EN/FR) | pending |
| T18 | 24 | script | ja | `gateway/tests/test_featureCatalogLabels_i18n.py` (Grep über alle main*.py) | pending |
| T18 | 24 | script | ja | `platform-core/tests/test_featureCatalogLabels_i18n.py` (Grep über alle main*.py) | pending |
## Phasen-Planung (Vorschlag)
@ -380,4 +380,4 @@ Total: ~7.75 Personentage, parallelisierbar auf ~3 Kalendertage.
Während der Implementierung kamen vom User folgende Punkte hinzu, die direkt mit-erledigt wurden:
- **Trustee Daten-Tabellen-Header**: Tab-Bar nach UDB-Struktur in 4 Kategorien (Stammdaten / Lokale Daten / Konfiguration / Daten aus Buchhaltungssystem) gruppiert; `(read-only)`-Text durch Lock-Icon (🔒) ersetzt. Tab-Labels 1:1 mit UDB-Labels synchronisiert (z.B. „Kontenplan" statt „Konten (Sync)"). Datei: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`.
- **Trustee Daten-Tabellen-Header**: Tab-Bar nach UDB-Struktur in 4 Kategorien (Stammdaten / Lokale Daten / Konfiguration / Daten aus Buchhaltungssystem) gruppiert; `(read-only)`-Text durch Lock-Icon (🔒) ersetzt. Tab-Labels 1:1 mit UDB-Labels synchronisiert (z.B. „Kontenplan" statt „Konten (Sync)"). Datei: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`.

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-05-09 -->
<!-- completed: 2026-05-15 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Enterprise Subscription

View file

@ -27,7 +27,7 @@ Heins Forschung (*Boosting Querying Accuracy with Ontology-Guided LLMs*, ENTER 2
## Fokus und kritische Details
- **Eine zentrale Stelle:** `featureDataAgent._buildSchemaContext` und `featureDataProvider` -- jede Doppel-Implementierung pro Feature ist verboten (Doc-Sync `b-reference/gateway/ai-agent.md`).
- **Eine zentrale Stelle:** `featureDataAgent._buildSchemaContext` und `featureDataProvider` -- jede Doppel-Implementierung pro Feature ist verboten (Doc-Sync `b-reference/platform-core/ai-agent.md`).
- **Token-Budget:** Jede Prompt-Zeile zählt für jeden Sub-Agent-Call. Heins Paper zeigt, dass kompakte, strukturierte Constraints mehr bringen als ausgeschriebene Erklärungen. Trustee-Hints sind heute ~80 Zeilen -- hart an der Grenze.
- **Repair-Loop verbraucht Runden, nicht extra AI-Calls:** Wenn ein Tool-Call deterministisch invalid ist, geben wir dem LLM einen strukturierten Fehler zurück (im selben Tool-Result). Kein paralleler Mini-Agent, keine versteckten Mehrkosten.
- **Ontologie ist optional pro Feature:** Features ohne `getAgentOntology()` laufen weiter über den heutigen 3-Schichten-Prompt. Kein Big-Bang.
@ -58,22 +58,22 @@ Heins Forschung (*Boosting Querying Accuracy with Ontology-Guided LLMs*, ENTER 2
## Betroffene Module
- **Gateway:**
- `gateway/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` (`ToolResult.errorDetails`, `ToolCallLog.validationFailureCode`, `AgentTrace`-Counter)
- `gateway/modules/serviceCenter/services/serviceAgent/agentLoop.py` (Aggregation der Repair-Counter in `AgentTrace` aus den `ToolCallLog`-Einträgen am Run-Ende)
- `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py` (Schema-Prompt-Build, Ontologie-Hook-Resolver, Pre-Execute-Validator-Call, Tool-Description-Ergänzung um `errorDetails`-Erklärung)
- `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` (unverändert; Validator läuft davor)
- `gateway/modules/serviceCenter/services/serviceAgent/queryValidator.py` **(neu)** (zentrale Validator-Engine)
- `gateway/modules/serviceCenter/services/serviceAgent/datamodelOntology.py` **(neu)** (`OntologyDescriptor`, `Constraint`, `Entity`, `Relation`, `QueryValidationError`)
- `gateway/modules/features/trustee/mainTrustee.py` (`_AGENT_DOMAIN_HINTS` ersetzt durch `getAgentOntology()` + auto-generated hints; alte Hints als `_AGENT_DOMAIN_HINTS_LEGACY` für 1 Sprint geparkt)
- `gateway/modules/features/trustee/trusteeOntology.py` **(neu)** (Trustee-Buchhaltungs-Ontologie als Code)
- `platform-core/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` (`ToolResult.errorDetails`, `ToolCallLog.validationFailureCode`, `AgentTrace`-Counter)
- `platform-core/modules/serviceCenter/services/serviceAgent/agentLoop.py` (Aggregation der Repair-Counter in `AgentTrace` aus den `ToolCallLog`-Einträgen am Run-Ende)
- `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py` (Schema-Prompt-Build, Ontologie-Hook-Resolver, Pre-Execute-Validator-Call, Tool-Description-Ergänzung um `errorDetails`-Erklärung)
- `platform-core/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` (unverändert; Validator läuft davor)
- `platform-core/modules/serviceCenter/services/serviceAgent/queryValidator.py` **(neu)** (zentrale Validator-Engine)
- `platform-core/modules/serviceCenter/services/serviceAgent/datamodelOntology.py` **(neu)** (`OntologyDescriptor`, `Constraint`, `Entity`, `Relation`, `QueryValidationError`)
- `platform-core/modules/features/trustee/mainTrustee.py` (`_AGENT_DOMAIN_HINTS` ersetzt durch `getAgentOntology()` + auto-generated hints; alte Hints als `_AGENT_DOMAIN_HINTS_LEGACY` für 1 Sprint geparkt)
- `platform-core/modules/features/trustee/trusteeOntology.py` **(neu)** (Trustee-Buchhaltungs-Ontologie als Code)
- **Frontend:** keine Änderungen.
- **DB-Migration:** nein. Eval-Goldstandard liegt im Test-Repo, nicht in der Mandanten-DB.
- **Andere Komponenten:**
- `gateway/tests/integration/featureDataAgent/` **(neu)** -- Goldstandard-Eval-Harness, läuft optional in CI als langer Job.
- `gateway/tests/fixtures/trusteeBenchmark/` **(neu)** -- 19 Fragen + Goldstandard-Antworten + Python-Fixture-Loader (KEINE `fixture.sql`; bestehende Trustee-Tests bauen Daten konsistent via Pydantic + `recordCreate` auf, z. B. `tests/unit/features/trustee/test_accountingDataSync_balances.py`). Goldstandard-Fragen bleiben als YAML.
- `platform-core/tests/integration/featureDataAgent/` **(neu)** -- Goldstandard-Eval-Harness, läuft optional in CI als langer Job.
- `platform-core/tests/fixtures/trusteeBenchmark/` **(neu)** -- 19 Fragen + Goldstandard-Antworten + Python-Fixture-Loader (KEINE `fixture.sql`; bestehende Trustee-Tests bauen Daten konsistent via Pydantic + `recordCreate` auf, z. B. `tests/unit/features/trustee/test_accountingDataSync_balances.py`). Goldstandard-Fragen bleiben als YAML.
## Entscheidungen
@ -222,7 +222,7 @@ class OntologyDescriptor(BaseModel):
### Eval-Harness (querschneidend, Phase 1 + 2)
**Goldstandard-Format** (`gateway/tests/fixtures/trusteeBenchmark/questions.yaml`):
**Goldstandard-Format** (`platform-core/tests/fixtures/trusteeBenchmark/questions.yaml`):
```yaml
- id: q01
@ -239,7 +239,7 @@ class OntologyDescriptor(BaseModel):
"1021.closingBalance": 28100.00
```
**Harness** (`gateway/tests/integration/featureDataAgent/test_trusteeBenchmark.py`):
**Harness** (`platform-core/tests/integration/featureDataAgent/test_trusteeBenchmark.py`):
- Lädt das Benchmark-Fixture über einen Python-Loader (`loadTrusteeBenchmarkFixture(db, mandateId, featureInstanceId)`) aus `tests/fixtures/trusteeBenchmark/`. Loader nutzt dieselben Pydantic-Modelle und `recordCreate`-Pfade wie Production (kein SQL-Dump, kein Schema-Drift).
- Iteriert über 19 Fragen.
- Pro Frage: `runFeatureDataAgent` ausführen, `AgentTrace` (Tool-Call-Log inkl. `validationFailureCode`) + finale Antwort capturen.
@ -281,8 +281,8 @@ class OntologyDescriptor(BaseModel):
### Phase 1.5 -- Eval-Harness (Woche 2, ca. 3-4 PT, parallel zu Phase 2 startbar)
- [ ] `gateway/tests/fixtures/trusteeBenchmark/loadTrusteeBenchmarkFixture.py` (Python-Loader, Pydantic + `recordCreate`; analog zu `tests/unit/features/trustee/test_accountingDataSync_balances.py`)
- [ ] `gateway/tests/fixtures/trusteeBenchmark/questions.yaml` mit 19 Fragen + Goldstandard
- [ ] `platform-core/tests/fixtures/trusteeBenchmark/loadTrusteeBenchmarkFixture.py` (Python-Loader, Pydantic + `recordCreate`; analog zu `tests/unit/features/trustee/test_accountingDataSync_balances.py`)
- [ ] `platform-core/tests/fixtures/trusteeBenchmark/questions.yaml` mit 19 Fragen + Goldstandard
- [ ] `test_trusteeBenchmark.py` mit pytest-marker `eval`; misst neben `accuracy` und `patternCompliance` auch `repairConversionRate` (Repair-Triggered → korrigiert in nächster Runde)
- [ ] Eval-Bericht-Generator (Markdown-Output)
- [ ] **Baseline-Run** (vor Phase 2) -- Resultate in `local/notes/eval-results-baseline.md`
@ -291,7 +291,7 @@ class OntologyDescriptor(BaseModel):
### Phase 2 -- Ontologie-Pilot Trustee (Woche 3-4, ca. 5-7 PT) -- DONE
- [x] Ontology-Datenmodell vervollständigt (`Entity`, `Relation`, `Invariant`, `CanonicalQueryPattern`, `SemanticType`-Enum -- bereits in Phase 1 vorbereitet, jetzt aktiv genutzt)
- [x] `gateway/modules/features/trustee/trusteeOntology.py` mit Trustee-Buchhaltungs-Ontologie (6 Entitäten inkl. BankAccount/CashAccount-Spezialisierungen, 3 Relations, 6 Constraints, 8 CanonicalPatterns)
- [x] `platform-core/modules/features/trustee/trusteeOntology.py` mit Trustee-Buchhaltungs-Ontologie (6 Entitäten inkl. BankAccount/CashAccount-Spezialisierungen, 3 Relations, 6 Constraints, 8 CanonicalPatterns)
- [x] `getAgentOntology()`-Hook in `mainTrustee.py`
- [x] `OntologyToPromptCompiler` -- generiert kompakten Prompt-Text deterministisch (`ontologyToPromptCompiler.py`)
- [x] `_buildSchemaContext` ruft Ontologie-Compiler bevorzugt (`_loadFeatureOntologyBlock`), fällt auf `getAgentDomainHints()` zurück; mit `POWERON_DISABLE_FEATURE_ONTOLOGY=1` Eval-only Override
@ -326,28 +326,28 @@ class OntologyDescriptor(BaseModel):
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | gateway/tests/unit/services/test_queryValidator.py | DONE (24 tests) |
| T2 | 2 | unit | ja | gateway/tests/unit/services/test_queryValidator.py | DONE |
| T3 | 3 | eval | standalone runner | gateway/tests/eval/runTrusteeBenchmark.py | DONE (Phase 1 zeigt repair-deflection in q13: val-fail=2, accuracy 89.5% -> 94.7%) |
| T4 | 4 | unit | ja | gateway/tests/unit/services/test_featureDataAgent_schema.py, test_trusteeOntology.py | DONE |
| T5 | 5 | unit | ja | gateway/tests/unit/services/test_featureDataAgent_schema.py | DONE (test_skipsHintsForFeaturesWithoutHook, test_buildValidatorForFeature_unknownFeature_noOntology) |
| T6 | 6 | eval | standalone runner | gateway/tests/eval/runTrusteeBenchmark.py | DONE -- Baseline 89.5% -> Phase 2 100% = +10.5 Pp (Ziel war ≥ 25 Pp; AC nur teilweise erfüllt -- ehrlich dokumentiert, siehe Diskussion unten) |
| T7 | 7 | unit + smoke | ja | gateway/tests/unit/services/test_featureDataAgent_schema.py | DONE -- Features ohne Ontologie laufen unverändert |
| T8 | 8 | unit | ja | gateway/tests/unit/services/test_trusteeOntology.py | DONE -- 16 tests, einer prüft Validator + Compiler über gleiche Constraint |
| T9 | 9 | manuell | nein | gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py:284-310 | DONE -- Tool-Description erklärt errorDetails-Format inline |
| T10 | 10 | unit | ja | gateway/tests/unit/serviceAgent/test_agentTrace_repairCounters.py | DONE (8 tests) |
| T1 | 1 | unit | ja | platform-core/tests/unit/services/test_queryValidator.py | DONE (24 tests) |
| T2 | 2 | unit | ja | platform-core/tests/unit/services/test_queryValidator.py | DONE |
| T3 | 3 | eval | standalone runner | platform-core/tests/eval/runTrusteeBenchmark.py | DONE (Phase 1 zeigt repair-deflection in q13: val-fail=2, accuracy 89.5% -> 94.7%) |
| T4 | 4 | unit | ja | platform-core/tests/unit/services/test_featureDataAgent_schema.py, test_trusteeOntology.py | DONE |
| T5 | 5 | unit | ja | platform-core/tests/unit/services/test_featureDataAgent_schema.py | DONE (test_skipsHintsForFeaturesWithoutHook, test_buildValidatorForFeature_unknownFeature_noOntology) |
| T6 | 6 | eval | standalone runner | platform-core/tests/eval/runTrusteeBenchmark.py | DONE -- Baseline 89.5% -> Phase 2 100% = +10.5 Pp (Ziel war ≥ 25 Pp; AC nur teilweise erfüllt -- ehrlich dokumentiert, siehe Diskussion unten) |
| T7 | 7 | unit + smoke | ja | platform-core/tests/unit/services/test_featureDataAgent_schema.py | DONE -- Features ohne Ontologie laufen unverändert |
| T8 | 8 | unit | ja | platform-core/tests/unit/services/test_trusteeOntology.py | DONE -- 16 tests, einer prüft Validator + Compiler über gleiche Constraint |
| T9 | 9 | manuell | nein | platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py:284-310 | DONE -- Tool-Description erklärt errorDetails-Format inline |
| T10 | 10 | unit | ja | platform-core/tests/unit/serviceAgent/test_agentTrace_repairCounters.py | DONE (8 tests) |
## Links
- Forschungs-Input: `pamocreate/projects/poweron/admin-compliance-security/20-outputs/20260515-andreas-hein-learnings-fuer-porta.md` (Punkte 3.1, 3.3)
- Hein-Paper: *Boosting Querying Accuracy with Ontology-Guided LLMs* (ENTER 2025, Springer)
- Bestehender Code: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`, `mainTrustee.py:676-754` (`_AGENT_DOMAIN_HINTS`)
- Bezug Wiki: `b-reference/gateway/ai-agent.md` (Abschnitt FeatureSubAgent)
- Bestehender Code: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`, `mainTrustee.py:676-754` (`_AGENT_DOMAIN_HINTS`)
- Bezug Wiki: `b-reference/platform-core/ai-agent.md` (Abschnitt FeatureSubAgent)
## Abschluss
- [x] `b-reference/gateway/ai-agent.md` aktualisiert (FeatureSubAgent-Abschnitt: `ToolResult.errorDetails`, `QueryValidator`, Ontologie-Hook, Eval-Harness, Repair-Telemetrie auf `AgentTrace`)
- [x] `b-reference/gateway/features/trustee.md` neuer Abschnitt "Agent-Ontologie"
- [x] `b-reference/platform-core/ai-agent.md` aktualisiert (FeatureSubAgent-Abschnitt: `ToolResult.errorDetails`, `QueryValidator`, Ontologie-Hook, Eval-Harness, Repair-Telemetrie auf `AgentTrace`)
- [x] `b-reference/platform-core/features/trustee.md` neuer Abschnitt "Agent-Ontologie"
- [x] `wiki/d-guides/coding-conventions.md` Migrations-Pattern für `getAgentOntology()`
- [x] TOPICS.md geprüft (kein neuer Eintrag erforderlich -- bestehende KI-Agent-Sektion verweist auf die aktualisierte b-reference-Seite)
- [x] Eval-Vergleich für Hein-Q&A: `local/notes/trustee-benchmark-20260515-161126.md` (Summary-Tabelle)

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-05-01 -->
<!-- completed: 2026-05-03 -->
<!-- component: frontend-nyla, gateway -->
<!-- component: ui-nyla, gateway -->
# FormGeneratorTree (NEU) + Recovery der persistenten Folder/File-Funktionen
@ -10,14 +10,14 @@
In den Commits `c8e9304` (2026-04-29), `e7a79a3` und `7c05cb0` (beide 2026-04-30,
zusammen -1263 / +897) wurde `FolderTree` aus
- `frontend_nyla/src/pages/basedata/FilesPage.tsx`
- `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- `ui-nyla/src/pages/basedata/FilesPage.tsx`
- `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx`
entfernt und durch `FormGeneratorTable` mit `groupingConfig` ersetzt. Begleitend
wurden die Folder-Operationen aus `FileContext.tsx` und `useFiles.ts` reduziert,
`FileInfo.folderId` aus `fileApi.ts` und das Pydantic-Feld `FileItem.folderId`
aus `gateway/modules/datamodels/datamodelFiles.py` entfernt. Im Repo liegt das
Archiviertes Skript `gateway/modules/migrations/_archive/migrate_folders_to_groups.py`, das die
aus `platform-core/modules/datamodels/datamodelFiles.py` entfernt. Im Repo liegt das
Archiviertes Skript `platform-core/modules/migrations/_archive/migrate_folders_to_groups.py`, das die
`FileFolder`-Tabelle + `FileItem.folderId`-Spalte in einen JSON-Tree
(`TableGrouping.rootGroups`, Context `files/list`) ueberfuehren *kann* -- per
Default `--dry-run`, ohne begleitende Alembic-Migration zum DROP-COLUMN /
@ -235,7 +235,7 @@ bekommen 1:1 dieselbe Mechanik:
## Ziel und Nicht-Ziele
- **Ziel 1.** `FormGeneratorTree` als Komponente in
`frontend_nyla/src/components/FormGenerator/FormGeneratorTree/` mit
`ui-nyla/src/components/FormGenerator/FormGeneratorTree/` mit
Provider-Interface, Built-in-Features (Multiselect, Cascade, DnD,
Inline-Edit, Scope-/Neutralize-Indikatoren) und Backend-Attribut-Resolution.
- **Ziel 2.** `FolderFileProvider` als erste Implementierung; recovered die
@ -369,7 +369,7 @@ Stage 3 deferred. **Stage 4+5 = PR 2** (Cleanup + Doku -- abgeschlossen).
- [ ] Optional: `SELECT COUNT(*) FROM "FileFolder"` und Stichprobe pro Mandant
auf Datenkonsistenz
**Hinweis (dev):** `python -m scripts.stage0_filefolder_schema_check` im Ordner `gateway`.
**Hinweis (dev):** `python -m scripts.stage0_filefolder_schema_check` im Ordner `platform-core`.
> Falls eine Umgebung abweicht: Plan zurueckziehen, Restore-/Migration-
> Subtask einplanen, **bevor** Stage 1 startet.
@ -656,10 +656,10 @@ Kann bei Bedarf spaeter als eigenes Projekt aufgegriffen werden.
**Checkliste**
- [x] `wiki/b-reference/frontend-nyla/architecture.md`: Komponenten-Tabelle
- [x] `wiki/b-reference/ui-nyla/architecture.md`: Komponenten-Tabelle
um `FormGeneratorTree` ergaenzt, `FolderTree`-Eintrag ersetzt,
`components/`-Ordner-Beschreibung aktualisiert
- [x] `wiki/b-reference/frontend-nyla/formgenerator.md`: Abschnitt
- [x] `wiki/b-reference/ui-nyla/formgenerator.md`: Abschnitt
`FormGeneratorTree` (Provider-Interface, Built-in Features,
Vergleichstabelle Tree vs. Table-with-grouping, Props, Verwendung)
- [x] `wiki/TOPICS.md`: Neuer Eintrag FormGenerator (Table, Form, Tree, Report)
@ -702,12 +702,12 @@ Kann bei Bedarf spaeter als eigenes Projekt aufgegriffen werden.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1, 2 | api | ja | `gateway/tests/unit/routes/test_folder_crud.py` | pending |
| T2 | 3 | api | ja | `gateway/tests/unit/routes/test_folder_cascade_delete.py` | pending |
| T3 | 4, 5 | api | ja | `gateway/tests/unit/routes/test_folder_scope_neutralize.py` (inkl. Cascade-Opt-in) | pending |
| T4 | 8, 8a, 8b | api | ja | `gateway/tests/unit/interfaces/test_folderRbac.py` (zwei User; alle Mutationsrouten 403; Render-Regel inkl. `contextOrphan`) | pending |
| T5 | 1-6 | ui | ja | `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/FormGeneratorTree.test.tsx` | pending |
| T6 | 6, 11 | ui | ja | `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/dnd.test.tsx` | pending |
| T1 | 1, 2 | api | ja | `platform-core/tests/unit/routes/test_folder_crud.py` | pending |
| T2 | 3 | api | ja | `platform-core/tests/unit/routes/test_folder_cascade_delete.py` | pending |
| T3 | 4, 5 | api | ja | `platform-core/tests/unit/routes/test_folder_scope_neutralize.py` (inkl. Cascade-Opt-in) | pending |
| T4 | 8, 8a, 8b | api | ja | `platform-core/tests/unit/interfaces/test_folderRbac.py` (zwei User; alle Mutationsrouten 403; Render-Regel inkl. `contextOrphan`) | pending |
| T5 | 1-6 | ui | ja | `ui-nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/FormGeneratorTree.test.tsx` | pending |
| T6 | 6, 11 | ui | ja | `ui-nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/dnd.test.tsx` | pending |
| T7 | 1-7, 10 | manuell | nein | -- | pending |
| T8 | 9 | manuell | nein | -- | pending |
| T9 | 7 | manuell | nein | -- | pending |
@ -733,17 +733,17 @@ Kann bei Bedarf spaeter als eigenes Projekt aufgegriffen werden.
- PR: tba (Stage 0+1+2 -- bereit), Stage 3 deferred, Stage 4+5 abgeschlossen
- Issue: --
- Vorgaenger-Commits: `c8e9304`, `e7a79a3`, `7c05cb0`
- Migrations-Skript (archiviert): `gateway/modules/migrations/_archive/migrate_folders_to_groups.py`
- Migrations-Skript (archiviert): `platform-core/modules/migrations/_archive/migrate_folders_to_groups.py`
- Heutige `FolderTree`-Komponente (vollstaendig, nicht mehr eingebunden):
`frontend_nyla/src/components/FolderTree/FolderTree.tsx`
`ui-nyla/src/components/FolderTree/FolderTree.tsx`
---
## Abschluss
- [x] `b-reference/frontend-nyla/architecture.md` aktualisiert
- [x] `b-reference/ui-nyla/architecture.md` aktualisiert
(Komponenten-Tabelle, UDB-Beschreibung)
- [x] `b-reference/frontend-nyla/formgenerator.md` aktualisiert
- [x] `b-reference/ui-nyla/formgenerator.md` aktualisiert
(Abschnitt FormGeneratorTree)
- [x] `TOPICS.md` aktualisiert
- [x] Dokument verschoben nach `4-done/`

View file

@ -7,7 +7,7 @@
## Beschreibung und Kontext
Migration der `poweron-swiss` INT-Umgebung (platform-core, ui-nyla) von Azure auf Infomaniak Public Cloud.
Betrifft nur `poweron-swiss`-Repos. Die `poweron`-Repos (gateway, frontend_nyla) bleiben auf Azure.
Betrifft nur `poweron-swiss`-Repos. Die `poweron`-Repos (gateway, ui-nyla) bleiben auf Azure.
## Checkliste
@ -18,8 +18,8 @@ Betrifft nur `poweron-swiss`-Repos. Die `poweron`-Repos (gateway, frontend_nyla)
- [x] `env-int.env`: DB_USER → `poweron_dev`
- [x] `env-int.env`: OAuth-Redirect-URIs → `api-int.poweron.swiss`
- [x] `env-int.env`: CORS (APP_ALLOWED_ORIGINS) → alle UI-Domains (poweron.swiss + poweron-center.net)
- [x] `env-int.env`: APP_KEY_SYSVAR → `/srv/gateway/shared/secrets/master_key.txt`
- [x] `env-int.env`: APP_LOGGING_LOG_DIR → `srv/gateway/shared/logs`
- [x] `env-int.env`: APP_KEY_SYSVAR → `/srv/platform-core/shared/secrets/master_key.txt`
- [x] `env-int.env`: APP_LOGGING_LOG_DIR → `srv/platform-core/shared/logs`
- [x] `env-int.env`: TEAMSBOT_BROWSER_BOT_URL → `http://teamsbot.poweron.swiss:4100`
- [x] `env-prod.env`: DB_HOST → `db.poweron.swiss`
- [x] `env-prod.env`: CORS aktualisiert
@ -71,11 +71,11 @@ SSH: `ssh -i ~/.ssh/ida-laptop.pem ubuntu@37.156.42.67`
### Server: porta-int-platform-core (api-int.poweron.swiss)
- [x] Verbindungstest zur DB OK
- [x] Master Key abgelegt (`/srv/gateway/shared/secrets/master_key.txt`)
- [x] Master Key abgelegt (`/srv/platform-core/shared/secrets/master_key.txt`)
- [x] Log-Verzeichnis vorhanden
- [x] App-Verzeichnis + Git-Repo vorhanden
- [x] Python venv vorhanden
- [x] systemd-Service `gateway` konfiguriert
- [x] systemd-Service `platform-core` konfiguriert
- [x] Nginx: `client_max_body_size 0`, WebSocket-Upgrade, Timeouts 600s, `proxy_request_buffering off` (analog PROD)
- [x] SSL: Let's Encrypt Zertifikat fuer `api-int.poweron.swiss` aktiv
@ -85,7 +85,7 @@ SSH: `ssh -i ~/.ssh/ida-laptop.pem ubuntu@37.156.42.67`
### Forgejo CI/CD
- [x] Workflow `int_porta-int-platform-core.yml` geprüft — zeigt korrekt auf `api-int.poweron.swiss`, Branch `int`, Pfad `/srv/gateway/current`
- [x] Workflow `int_porta-int-platform-core.yml` geprüft — zeigt korrekt auf `api-int.poweron.swiss`, Branch `int`, Pfad `/srv/platform-core/current`
### Wiki

View file

@ -6,7 +6,7 @@
## Beschreibung und Kontext
Der zentrale `DatabaseConnector` in `gateway/modules/connectors/connectorDbPostgre.py` hält **genau eine psycopg2-Connection pro Instanz**. Die Modul-Cache-Funktion `getCachedConnector(host, db, user, port)` gibt für denselben Schlüssel immer denselben Connector zurück. In `DatabaseConnector.__init__` wird zwar ein `self._lock = threading.Lock()` deklariert, im ganzen 1789-zeiligen File aber **kein einziges Mal genutzt** (`with self._lock:` → 0 Treffer).
Der zentrale `DatabaseConnector` in `platform-core/modules/connectors/connectorDbPostgre.py` hält **genau eine psycopg2-Connection pro Instanz**. Die Modul-Cache-Funktion `getCachedConnector(host, db, user, port)` gibt für denselben Schlüssel immer denselben Connector zurück. In `DatabaseConnector.__init__` wird zwar ein `self._lock = threading.Lock()` deklariert, im ganzen 1789-zeiligen File aber **kein einziges Mal genutzt** (`with self._lock:` → 0 Treffer).
Folge: Sobald zwei FastAPI-Threadpool-Worker (für `def`-Routes) oder zwei async-Tasks (für `async def`) gleichzeitig auf dieselbe gecachte Connection zugreifen — `connection.cursor()` / `cursor.execute()` —, gibt psycopg2 entweder `OperationalError: another command is already in progress` oder hängt im `recv()`-Syscall **ohne Timeout**. Ein einziger hängender Call vergiftet die Connection; alle weiteren Calls auf demselben Cache-Eintrag hängen ebenfalls; uvicorn-Worker stauen sich; das Backend ist tot.
@ -47,13 +47,13 @@ Das Risiko ohne Fix: Das System ist nicht produktionstauglich. Jeder Tag mit mod
## Betroffene Module
- **Gateway:**
- `gateway/modules/connectors/connectorDbPostgre.py` — Refactor (Pool-Helper, alle 40 `self.connection.*` Stellen)
- `gateway/app.py` — Pool-Shutdown-Hook bei FastAPI-Shutdown
- `gateway/tests/unit/connectors/test_connectorDbPostgre_failLoud.py` — neue Concurrency-Tests
- `platform-core/modules/connectors/connectorDbPostgre.py` — Refactor (Pool-Helper, alle 40 `self.connection.*` Stellen)
- `platform-core/app.py` — Pool-Shutdown-Hook bei FastAPI-Shutdown
- `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py` — neue Concurrency-Tests
- **Keine Änderung** an: `mainBackgroundJobService.py`, `routeI18n.py`, `aiAuditLogger.py`, `interfaceDb*.py`, `i18nRegistry.py`, `XxxObjects`-Klassen — die Public-API von `DatabaseConnector` und `getCachedConnector` bleibt 1:1
- **Frontend:** keine
- **DB-Migration:** nein (keine Schema-Änderung)
- **Andere Komponenten:** keine (private-llm, teams-bot, frontend nicht betroffen)
- **Andere Komponenten:** keine (service-llm-private, teams-bot, frontend nicht betroffen)
## Entscheidungen
@ -76,7 +76,7 @@ Das Risiko ohne Fix: Das System ist nicht produktionstauglich. Jeder Tag mit mod
- [x] `getCachedConnector` umgebaut: Cache enthält **leichtgewichtige** Wrapper, jeder Wrapper teilt sich den Pool über `_PoolRegistry`. API unverändert **(S2, done 2026-05-17)**
- [x] Statement-Timeout (30 s) + `connect_timeout` (10 s) per `options=`/`connect_timeout=` in Pool-Erzeugung gesetzt **(S1, done 2026-05-17)**
- [x] Backward-Compat-Shim `db.connection` (no-op `commit`/`rollback`/`closed`/`close`, RuntimeError auf `cursor`) damit kein legacy Aufruf still bricht **(S2, done 2026-05-17)**
- [x] FastAPI `lifespan` / `app.on_event("shutdown")`: alle Pools schliessen (`closeAllPools()`) — gewirelt in `gateway/app.py` als letzter Shutdown-Schritt nach den Feature-`onStop` Hooks **(S4, done 2026-05-17)**
- [x] FastAPI `lifespan` / `app.on_event("shutdown")`: alle Pools schliessen (`closeAllPools()`) — gewirelt in `platform-core/app.py` als letzter Shutdown-Schritt nach den Feature-`onStop` Hooks **(S4, done 2026-05-17)**
- [x] Concurrency-Tests in neuem `test_connectorDbPostgre_pool.py`: 6 Tests (50 Threads Stress, 20 Threads Latency-Budget, interleaved load/save, statement_timeout-Release, pool-identity, closeAllPools) — alle 6 grün gegen lokales Postgres; auto-skipping wenn keine DB erreichbar; `borrowConn()` um bounded Wait-Retry erweitert weil psycopg2-Pool exhaustion sofort raised statt blockt **(S5, done 2026-05-17)**
- [x] Regression-Run unit+integration: 639/656 unit grün (1 von uns gefixt: `test_folder_crud._FakeDb` brauchte `borrowCursor`-Stub; 17 pre-existing Failures sind RAG-Logik-Drift + Adapter-Drift, kein Pool-Bezug); 76/79 integration grün (3 pre-existing Trustee-Workflow-Failures, kein Pool-Bezug) **(S6, done 2026-05-17)**
- [x] Smoke-Test 17.05.2026 11:3311:39 (`local/logs/log_app_20260517.log`): 11 Pools je 1× lazy erzeugt, **kein** `another command is already in progress`, **kein** `pool exhausted`, **kein** `recv() hang`, **kein** Pool-Retry. Frontend laut User ohne Delays/Freezes. Einziger ERROR: `Decryption rate limit exceeded for user 'system' key 'DB_PASSWORD_SECRET'` in `routeRagInventory._getInventoryPlatform` — unabhängiges Problem (kein Pool-Bezug), hot-path `mainBackgroundJobService._getDb()` triggert pro RAG-Inventory-Poll + Walker-Call >10 Decrypts/s. Separater Fix unterhalb. **(S7, done 2026-05-17)**
@ -115,7 +115,7 @@ Get-Process python | Sort-Object WS -Descending | Select-Object -First 3 Process
**Abschluss:**
- Notiz unter `local/notes/2026-05-pool-smoke-1h.md` mit:
- Start/Endzeit
- Auffälligkeiten in den Logs (sollten keine sein) — `grep -E "another command|pool exhausted|connection pool" gateway/local/logs/log_app_<datum>.log`
- Auffälligkeiten in den Logs (sollten keine sein) — `grep -E "another command|pool exhausted|connection pool" platform-core/local/logs/log_app_<datum>.log`
- `pg_stat_activity` Snapshots zu Beginn / Mitte / Ende
- RAM-Verlauf 3 Werte
- Bei Erfolg: Diese Plan-Doc nach `c-work/3-validate/` verschieben, dann S8 (Doku-Sync) anstossen.
@ -141,11 +141,11 @@ Get-Process python | Sort-Object WS -Descending | Select-Object -First 3 Process
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|---------------|-----------|--------|
| T1 | 2 | unit (concurrency) | ja | `gateway/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_concurrent_getRecordset_50threads` | pending |
| T2 | 3 | unit (interleaved cursor) | ja | `gateway/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_interleaved_load_update_no_collision` | pending |
| T3 | 4 | unit (timeout) | ja | `gateway/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_statement_timeout_returns_conn_to_pool` | pending |
| T4 | 5 | manual+integration | teilweise | `gateway/tests/integration/test_pool_shutdown.py` + `pg_stat_activity` check | pending |
| T5 | 6 | regression | ja | `gateway/tests/unit/connectors/`, `gateway/tests/integration/` (alle bestehenden) | pending |
| T1 | 2 | unit (concurrency) | ja | `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_concurrent_getRecordset_50threads` | pending |
| T2 | 3 | unit (interleaved cursor) | ja | `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_interleaved_load_update_no_collision` | pending |
| T3 | 4 | unit (timeout) | ja | `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_statement_timeout_returns_conn_to_pool` | pending |
| T4 | 5 | manual+integration | teilweise | `platform-core/tests/integration/test_pool_shutdown.py` + `pg_stat_activity` check | pending |
| T5 | 6 | regression | ja | `platform-core/tests/unit/connectors/`, `platform-core/tests/integration/` (alle bestehenden) | pending |
| T6 | 1 | smoke (manuell) | nein | `local/notes/2026-05-pool-smoke-1h.md` mit Polling-Log + Memory-Verlauf | pending |
## Schritt-für-Schritt-Umsetzung mit LLM-Empfehlung
@ -184,7 +184,7 @@ Neue Datei oder Modul-Section in `connectorDbPostgre.py`:
**LLM:** `composer-2-fast`
- In `gateway/app.py` FastAPI `lifespan`-Handler (oder `on_event("shutdown")` falls Codebase noch das alte Pattern nutzt) → `closeAll()` aufrufen
- In `platform-core/app.py` FastAPI `lifespan`-Handler (oder `on_event("shutdown")` falls Codebase noch das alte Pattern nutzt) → `closeAll()` aufrufen
- Bei `lifespan` zusätzlich Startup-Hook für initialen Pool-Warmup (optional)
### S5 — Concurrency-Tests
@ -200,7 +200,7 @@ Neue Datei oder Modul-Section in `connectorDbPostgre.py`:
**LLM:** `composer-2-fast` (nur Run + Fix-Loop)
- `pytest gateway/tests/unit/connectors/ gateway/tests/integration/` → grün
- `pytest platform-core/tests/unit/connectors/ platform-core/tests/integration/` → grün
- Jede Regression-Failure: einzeln analysieren, Fix entweder im Pool-Code oder im Test (falls Test-Assumption hard-coded auf `self.connection`)
### S7 — Smoke-Test 1 h

View file

@ -24,7 +24,7 @@ Jede Phase referenziert sie.
| # | Befund | Datei / Stelle | Konsequenz für Plan |
|---|--------|----------------|---------------------|
| F1 | `DataSource.autoSync` ist nur im Model deklariert, **wird im Code nirgends gelesen oder geschrieben** (Suche in `gateway`, `frontend_nyla` ergab Null Hits ausserhalb der Modeldatei). | `datamodels/datamodelDataSource.py:6569` | Renaming auf `ragIndexEnabled` ist **risikofrei**; Migration = `ALTER TABLE … RENAME COLUMN`. |
| F1 | `DataSource.autoSync` ist nur im Model deklariert, **wird im Code nirgends gelesen oder geschrieben** (Suche in `platform-core`, `ui-nyla` ergab Null Hits ausserhalb der Modeldatei). | `datamodels/datamodelDataSource.py:6569` | Renaming auf `ragIndexEnabled` ist **risikofrei**; Migration = `ALTER TABLE … RENAME COLUMN`. |
| F2 | `BackgroundJobStatusEnum.CANCELLED` und `TERMINAL_JOB_STATUSES = {SUCCESS, ERROR, CANCELLED}` existieren bereits, aber `cancelJob()`-API fehlt; `JobProgressCallback` hat nur `(progress, message)`-Signatur. | `serviceBackgroundJobs/mainBackgroundJobService.py:52, 157`, `datamodels/datamodelBackgroundJob.py:34, 3741` | Cancel-Infrastruktur muss ergänzt werden, **nicht** das Status-Enum. |
| F3 | Bootstrap-Dispatcher ruft Walker mit `connectionId` auf; Walker enumerieren OAuth-global (`adapter.browse("/")`) und laden Prefs intern. | `subConnectorIngestConsumer.py:168221`, `subConnectorSyncSharepoint.py:110174` | Walker-API muss um optionalen `dataSources: List[DataSource]`-Parameter erweitert werden; Default-Verhalten bleibt rückwärtskompatibel **bis Phase D** umstellt. |
| F4 | `GET /api/connections/` liefert `knowledgeIngestionEnabled` / `knowledgePreferences` **nicht** im Response. | `routes/routeDataConnections.py:188201, 249264, 282298` (3 Stellen) | Response-Builder zentralisieren als Helper, dann `_buildEnhancedItems` + `groupSummary` + Haupt-Block daraus speisen. |
@ -66,7 +66,7 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.1 `DataSource`-Modell umbenennen
- **Datei:** `gateway/modules/datamodels/datamodelDataSource.py`
- **Datei:** `platform-core/modules/datamodels/datamodelDataSource.py`
- **Änderung:**
- `autoSync: bool = Field(default=False, ...)`**umbenennen** zu
`ragIndexEnabled: bool = Field(default=False, description="Wenn true: dieses Tree-Element wird in den RAG indexiert.", json_schema_extra={"label": "Im RAG indexieren", "frontend_type": "checkbox"})`
@ -75,7 +75,7 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.2 DB-Migration
- **Datei:** `gateway/modules/migrations/migrationXXX_renameDataSourceFields.py` (neu — Nummer aus aktueller Migrations-Folge ableiten)
- **Datei:** `platform-core/modules/migrations/migrationXXX_renameDataSourceFields.py` (neu — Nummer aus aktueller Migrations-Folge ableiten)
- **SQL:**
```sql
ALTER TABLE poweron_app."DataSource" RENAME COLUMN "autoSync" TO "ragIndexEnabled";
@ -85,7 +85,7 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.3 `UserConnection.knowledgePreferences` Schema-Doku reduzieren
- **Datei:** `gateway/modules/datamodels/datamodelUam.py`
- **Datei:** `platform-core/modules/datamodels/datamodelUam.py`
- **Änderung:** Field-Description von `knowledgePreferences` aktualisieren — entferne Erwähnung von:
- `neutralizeBeforeEmbed` (kommt nach `DataSource.neutralize`)
- `surfaceToggles` (obsolet — pro DataSource via `ragIndexEnabled`)
@ -95,13 +95,13 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.4 Pref-Loader bereinigen
- **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py`
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py`
- **Änderung:** Felder `neutralizeBeforeEmbed`, `mimeAllowlist`, `surfaceToggles` aus `loadConnectionPrefs`-Output entfernen (DTO + Defaults).
- **Wirkung:** Walker dürfen `prefs.neutralizeBeforeEmbed` nicht mehr lesen — wird in Phase B durch DataSource-Lookup ersetzt.
### A.5 Cancel-API in Background-Jobs
- **Datei:** `gateway/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Datei:** `platform-core/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Neue Funktion** (nach `_markError`, vor `_makeProgressCallback`):
```python
def cancelJob(jobId: str, *, reason: str = "user_requested") -> bool:
@ -135,7 +135,7 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.6 Stop-Job-Helfer für Connection
- **Datei:** `gateway/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Datei:** `platform-core/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Neue Funktion:**
```python
def cancelJobsByConnection(connectionId: str, *, jobType: str = "connection.bootstrap") -> int:
@ -158,7 +158,7 @@ sonst ins Leere laufen. Phase B kann parallel zu Phase C laufen, sobald A fertig
### A.7 Knowledge-Interface Purge-Methoden ergänzen
- **Datei:** `gateway/modules/interfaces/interfaceDbKnowledge.py`
- **Datei:** `platform-core/modules/interfaces/interfaceDbKnowledge.py`
- **Bestehend:** `deleteFileContentIndexByConnectionId(connectionId)` (Z. 96).
- **Neu:**
- `deleteFileContentIndexByDataSource(dataSourceId: str) -> Dict[str, int]` — purgt Chunks deren `provenance.dataSourceId == dataSourceId`.
@ -181,7 +181,7 @@ Cancel-Check ist überall verbaut. Provenance enthält `dataSourceId`.
### B.1 Bootstrap-Dispatcher umstellen
- **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py`
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py`
- **Änderung in `_bootstrapJobHandler`** (Z. 125238):
1. **Vor jedem Authority-Branch:** DataSources der Connection laden:
```python
@ -259,7 +259,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### B.4 Effektive Policy aus DataSource (mit Tree-Vererbung)
- **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subPolicyResolver.py` **(neu)**
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subPolicyResolver.py` **(neu)**
- **Funktion:**
```python
def resolveEffectivePolicy(
@ -304,7 +304,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.1 `routeDataConnections` GET-Response erweitern
- **Datei:** `gateway/modules/routes/routeDataConnections.py`
- **Datei:** `platform-core/modules/routes/routeDataConnections.py`
- **Refactor:** `_buildEnhancedItems` (Z. 183202) zu Helper-Funktion erheben:
```python
def _buildConnectionDict(connection, tokenStatus, tokenExpiresAt) -> Dict[str, Any]:
@ -324,7 +324,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.2 Neue PATCH-Endpoints `routeDataConnections`
- **Datei:** `gateway/modules/routes/routeDataConnections.py`
- **Datei:** `platform-core/modules/routes/routeDataConnections.py`
- **Endpoints:**
```python
@ -382,7 +382,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.3 Neuer PATCH `routeDataSources/rag-index`
- **Datei:** `gateway/modules/routes/routeDataSources.py`
- **Datei:** `platform-core/modules/routes/routeDataSources.py`
- **Neuer Endpoint nach Z. 127:**
```python
@router.patch("/{sourceId}/rag-index")
@ -405,7 +405,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.4 Neuer Route-Block `routeRagInventory`
- **Datei:** `gateway/modules/routes/routeRagInventory.py` **(neu)**
- **Datei:** `platform-core/modules/routes/routeRagInventory.py` **(neu)**
- **Endpoints:**
```
GET /api/rag/inventory/me → eigene Daten (Connections + DataSources + Chunks-Counts)
@ -440,11 +440,11 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.5 WorkspaceRagInsights-Backend-Route entfernen
- **Datei:** `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- **Datei:** `platform-core/modules/features/workspace/routeFeatureWorkspace.py`
- **Löschen:** Ab Z. 2219 (`@router.get("/{instanceId}/rag-statistics")`) bis Funktionsende.
- **Datei:** `gateway/modules/features/workspace/mainWorkspace.py`
- **Datei:** `platform-core/modules/features/workspace/mainWorkspace.py`
- **Löschen:** UI-Permission-Block für `ui.feature.workspace.rag-insights` an Z. 3738; Permission-Einträge an Z. 89, 100. (RBAC-Tree wird durch die nächste `_copyTemplateRoles`-Auflösung sauber.)
- **Datei:** `gateway/modules/interfaces/interfaceDbKnowledge.py`
- **Datei:** `platform-core/modules/interfaces/interfaceDbKnowledge.py`
- **Löschen oder behalten?** `getRagStatisticsForInstance` (Z. 421) — falls keine anderen Aufrufer (Audit per Suche), löschen. Sonst behalten.
### C.6 Acceptance-Gate Phase C
@ -468,7 +468,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.1 `connectionApi.ts` reduzieren
- **Datei:** `frontend_nyla/src/api/connectionApi.ts`
- **Datei:** `ui-nyla/src/api/connectionApi.ts`
- **Änderung:**
- `KnowledgePreferences`-Type: `neutralizeBeforeEmbed`, `surfaceToggles`, `mimeAllowlist` entfernen.
- **Neue API-Methoden:**
@ -485,7 +485,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.2 `useConnections` Hook erweitern
- **Datei:** `frontend_nyla/src/hooks/useConnections.ts`
- **Datei:** `ui-nyla/src/hooks/useConnections.ts`
- **Neu exportieren:**
- `setKnowledgeConsent(connectionId, enabled)` — wrapt `patchKnowledgeConsent` + `refetch()`.
- `setKnowledgePreferences(connectionId, prefs, opts)` — wrapt `patchKnowledgePreferences` + `refetch()`.
@ -494,7 +494,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.3 `AddConnectionWizard.tsx` Komplett-Refactor
- **Datei:** `frontend_nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx`
- **Datei:** `ui-nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx`
- **Entfernen:**
- `computeCostEstimate` (Z. 71151).
- Step 2 (Preferences): Z. 302397.
@ -528,7 +528,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.4 `ConnectionsPage.tsx` aufräumen
- **Datei:** `frontend_nyla/src/pages/basedata/ConnectionsPage.tsx`
- **Datei:** `ui-nyla/src/pages/basedata/ConnectionsPage.tsx`
- **Entfernen:**
- `adminConsentPending` State + Handler (Z. 57, alle Verwendungen).
- `infomaniakModal` State + `handleCreateInfomaniak`, `handleInfomaniakCancel`, `handleInfomaniakSubmit` (Z. 78...).
@ -545,7 +545,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.5 Neue Komponente `KnowledgePreferencesDrawer`
- **Datei:** `frontend_nyla/src/components/KnowledgePreferencesDrawer/KnowledgePreferencesDrawer.tsx` **(neu)**
- **Datei:** `ui-nyla/src/components/KnowledgePreferencesDrawer/KnowledgePreferencesDrawer.tsx` **(neu)**
- **Inhalt:** Felder analog zu altem Wizard-Step 2, aber **ohne** `neutralizeBeforeEmbed`:
- `mailContentDepth` (Select: metadata / snippet / full)
- `mailIndexAttachments` (Checkbox)
@ -557,7 +557,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.6 `SourcesTab.tsx` — 4. Action-Button für `ragIndexEnabled`
- **Datei:** `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- **Datei:** `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- **Erweiterungen:**
1. Type `UdbDataSource` (Z. 3645): `ragIndexEnabled: boolean` ergänzen.
2. **Konstante neu:**
@ -584,7 +584,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.7 Neue Seite `RagInventoryPage.tsx`
- **Datei:** `frontend_nyla/src/pages/system/RagInventoryPage.tsx` **(neu)**
- **Datei:** `ui-nyla/src/pages/system/RagInventoryPage.tsx` **(neu)**
- **3 Tabs (`PageTabsLayout`-Komponente):**
| Tab | Endpoint | Sichtbarkeit | Inhalt |
|-----|----------|--------------|--------|
@ -595,7 +595,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.8 Navigation: `Start > Nutzung > RAG-Inventar`
- **Datei:** `gateway/modules/system/mainSystem.py`
- **Datei:** `platform-core/modules/system/mainSystem.py`
- **Neuer Eintrag** unter Gruppe „Nutzung" (vermutlich `usage` / `nutzung`):
```python
{
@ -608,7 +608,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
"order": NN,
}
```
- **Datei:** `frontend_nyla/src/config/pageRegistry.tsx`
- **Datei:** `ui-nyla/src/config/pageRegistry.tsx`
- **Mapping:**
```tsx
'page.system.ragInventory': { component: lazy(() => import('../pages/system/RagInventoryPage')), icon: FaDatabase },
@ -616,7 +616,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.9 Header-Badge `RagRunningBadge`
- **Datei:** `frontend_nyla/src/components/Header/RagRunningBadge.tsx` **(neu)**
- **Datei:** `ui-nyla/src/components/Header/RagRunningBadge.tsx` **(neu)**
- **Logik:**
- `useEffect`: alle 5s `getRagJobsActive()`; State `count: number`.
- Render: nur wenn `count > 0` — kleines Icon (`FaSync` rotierend) mit Badge `count`; Click → Navigate `/system/rag-inventory`.
@ -625,13 +625,13 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.10 Workspace-Insights-Seite löschen
- **Löschen:**
- `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx`
- `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.module.css`
- **Datei:** `frontend_nyla/src/pages/FeatureView.tsx`
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx`
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.module.css`
- **Datei:** `ui-nyla/src/pages/FeatureView.tsx`
- **Entfernen:** Import Z. 38, Mapping `'rag-insights': WorkspaceRagInsightsPage` Z. 158.
- **Datei:** `frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx`
- **Datei:** `ui-nyla/src/pages/views/workspace/WorkspacePage.tsx`
- **Prüfen:** Ob Verweise auf die Insights-Seite (Buttons, Links) drin sind — entfernen.
- **Datei:** `frontend_nyla/src/api/mandate.ts` (oder vergleichbare Mapping-Stelle)
- **Datei:** `ui-nyla/src/api/mandate.ts` (oder vergleichbare Mapping-Stelle)
- **Prüfen:** Ob Workspace-Sub-View `'rag-insights'` enumeriert ist — entfernen.
### D.11 Acceptance-Gate Phase D
@ -652,7 +652,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### E.1 Backend-Integrationstests
- **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/tests/test_bootstrapDispatcher.py` (neu/erweitern)
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/tests/test_bootstrapDispatcher.py` (neu/erweitern)
- **Tests:**
- `test_bootstrap_skipsIfNoRagEnabledDataSources`
- `test_bootstrap_iteratesOnlyRagEnabledDataSources`
@ -667,7 +667,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### E.3 Frontend-Integrationstests
- **Datei:** `frontend_nyla/cypress/integration/ragConsentControl.spec.ts` (neu, falls Cypress vorhanden)
- **Datei:** `ui-nyla/cypress/integration/ragConsentControl.spec.ts` (neu, falls Cypress vorhanden)
- **Tests:**
- Wizard MSFT-Flow inkl. Admin-Consent-Step
- Wizard Infomaniak-Flow inkl. PAT-Cancel

View file

@ -1,7 +1,7 @@
<!-- status: done -->
<!-- started: 2026-05-12 -->
<!-- lastReviewed: 2026-05-15 -->
<!-- component: gateway | frontend-nyla | platform -->
<!-- component: gateway | ui-nyla | platform -->
# Unified RAG Consent, Neutralization and Visibility — Single Source of Truth
@ -169,27 +169,27 @@ Diese Frage muss **drei** UI-Plätze ohne Lücke abdecken:
### Kritische Stellen im Code
- `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py` — Bootstrap-Dispatcher: muss Walker auf DataSource-Iteration umstellen + Cancel-Flag prüfen.
- `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorSync*.py` (5 Walker) — konsumieren `DataSource`-Liste statt globalem Authority-Walk; lesen `neutralize` aus DataSource; prüfen periodisch `cancelRequested`.
- `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py` — `neutralizeBeforeEmbed`, `mimeAllowlist`, `surfaceToggles` raus.
- `gateway/modules/datamodels/datamodelUam.py` — `knowledgePreferences` Schema-Doku anpassen.
- `gateway/modules/datamodels/datamodelDataSource.py` — `autoSync``ragIndexEnabled` (oder umdokumentieren); ggf. `lastIndexed`-Feld hinzufügen.
- `gateway/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py` — `cancelJob(jobId)` API hinzufügen; `JobProgressCallback` um `isCancelled()` erweitern.
- `gateway/modules/routes/routeDataConnections.py` — `GET` liefert Knowledge-Felder; neue PATCH-Endpoints für Consent + Preferences + Stop.
- `gateway/modules/routes/routeDataSources.py` — neuer PATCH `/{id}/rag-index` mit Purge bei Off-Toggle.
- `gateway/modules/interfaces/interfaceDbKnowledge.py` — `deleteFileContentIndexByConnectionAndPathPrefix(connectionId, pathPrefix)` und `listFileContentIndexByConnection(connectionId)` und `listFileContentIndexByDataSource(dataSourceId)`.
- `gateway/modules/features/workspace/routeFeatureWorkspace.py` — `rag-statistics` Methode löschen.
- **NEU** `gateway/modules/routes/routeRagInventory.py` — `/api/rag/inventory/{me,mandate,platform}` und `/api/rag/connection/{id}/status`.
- `gateway/modules/system/mainSystem.py` — Navigation `Nutzung > RAG-Inventar`.
- `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx` + `.module.css`**löschen**.
- `frontend_nyla/src/types/mandate.ts` — `rag-insights` raus.
- `frontend_nyla/src/pages/FeatureView.tsx`, `App.tsx` — Route + Mapping raus.
- `frontend_nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx` — Connector-Type-Aware Step-Definition; integrierte Microsoft-Admin-Consent + Infomaniak-PAT Steps; Kostenabschätzung + Preferences-Step entfernen.
- `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx` — vierter Action-Button für `ragIndexEnabled` (analog zu 🔒/Neutralize) **inklusive Vererbungs-Visualisierung** (`inheritedRagIndexEnabled`-Prop, gestrichelt/gedimmt für vererbte Werte).
- `frontend_nyla/src/api/connectionApi.ts` — `KnowledgePreferences` reduzieren; neue API-Methoden.
- **NEU** `frontend_nyla/src/pages/system/RagInventoryPage.tsx` — Drei-Tab-Seite (Meine / Mandant / Plattform).
- `frontend_nyla/src/pages/basedata/ConnectionsPage.tsx` — Buttons „Admin-Zustimmung" + „Infomaniak" + Modal **entfernen**; Master-Toggle pro Row + Status-Pill + Stop-Button bei laufendem Bootstrap hinzufügen.
- **NEU** `frontend_nyla/src/components/Header/RagRunningBadge.tsx` — globales Header-Badge mit Anzahl laufender Bootstrap-Jobs + Click-through zur RAG-Inventar.
- `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py` — Bootstrap-Dispatcher: muss Walker auf DataSource-Iteration umstellen + Cancel-Flag prüfen.
- `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorSync*.py` (5 Walker) — konsumieren `DataSource`-Liste statt globalem Authority-Walk; lesen `neutralize` aus DataSource; prüfen periodisch `cancelRequested`.
- `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py` — `neutralizeBeforeEmbed`, `mimeAllowlist`, `surfaceToggles` raus.
- `platform-core/modules/datamodels/datamodelUam.py` — `knowledgePreferences` Schema-Doku anpassen.
- `platform-core/modules/datamodels/datamodelDataSource.py` — `autoSync``ragIndexEnabled` (oder umdokumentieren); ggf. `lastIndexed`-Feld hinzufügen.
- `platform-core/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py` — `cancelJob(jobId)` API hinzufügen; `JobProgressCallback` um `isCancelled()` erweitern.
- `platform-core/modules/routes/routeDataConnections.py` — `GET` liefert Knowledge-Felder; neue PATCH-Endpoints für Consent + Preferences + Stop.
- `platform-core/modules/routes/routeDataSources.py` — neuer PATCH `/{id}/rag-index` mit Purge bei Off-Toggle.
- `platform-core/modules/interfaces/interfaceDbKnowledge.py` — `deleteFileContentIndexByConnectionAndPathPrefix(connectionId, pathPrefix)` und `listFileContentIndexByConnection(connectionId)` und `listFileContentIndexByDataSource(dataSourceId)`.
- `platform-core/modules/features/workspace/routeFeatureWorkspace.py` — `rag-statistics` Methode löschen.
- **NEU** `platform-core/modules/routes/routeRagInventory.py` — `/api/rag/inventory/{me,mandate,platform}` und `/api/rag/connection/{id}/status`.
- `platform-core/modules/system/mainSystem.py` — Navigation `Nutzung > RAG-Inventar`.
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx` + `.module.css`**löschen**.
- `ui-nyla/src/types/mandate.ts` — `rag-insights` raus.
- `ui-nyla/src/pages/FeatureView.tsx`, `App.tsx` — Route + Mapping raus.
- `ui-nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx` — Connector-Type-Aware Step-Definition; integrierte Microsoft-Admin-Consent + Infomaniak-PAT Steps; Kostenabschätzung + Preferences-Step entfernen.
- `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` — vierter Action-Button für `ragIndexEnabled` (analog zu 🔒/Neutralize) **inklusive Vererbungs-Visualisierung** (`inheritedRagIndexEnabled`-Prop, gestrichelt/gedimmt für vererbte Werte).
- `ui-nyla/src/api/connectionApi.ts` — `KnowledgePreferences` reduzieren; neue API-Methoden.
- **NEU** `ui-nyla/src/pages/system/RagInventoryPage.tsx` — Drei-Tab-Seite (Meine / Mandant / Plattform).
- `ui-nyla/src/pages/basedata/ConnectionsPage.tsx` — Buttons „Admin-Zustimmung" + „Infomaniak" + Modal **entfernen**; Master-Toggle pro Row + Status-Pill + Stop-Button bei laufendem Bootstrap hinzufügen.
- **NEU** `ui-nyla/src/components/Header/RagRunningBadge.tsx` — globales Header-Badge mit Anzahl laufender Bootstrap-Jobs + Click-through zur RAG-Inventar.
### Bekannte Fallstricke
@ -299,7 +299,7 @@ Diese Frage muss **drei** UI-Plätze ohne Lücke abdecken:
- [x] **DSGVO-Audit-Log:** `knowledge_consent_changed`, `rag_index_toggled`, `knowledge_jobs_stopped` werden via `audit_logger` geloggt.
- [x] **Backend-Integrationstests:** manuell verifiziert (Smoke-Tests, 2026-05-15).
- [x] **Frontend-Tests:** manuell verifiziert (2026-05-15).
- [x] **Wiki-Updates:** `b-reference/gateway/ai-agent.md` aktualisiert; `TOPICS.md` enthält RAG-Inventar-Eintrag.
- [x] **Wiki-Updates:** `b-reference/platform-core/ai-agent.md` aktualisiert; `TOPICS.md` enthält RAG-Inventar-Eintrag.
## Akzeptanzkriterien
@ -350,14 +350,14 @@ Diese Frage muss **drei** UI-Plätze ohne Lücke abdecken:
## Links
- Vorgänger-Plan: `wiki/c-work/4-done/2026-04-id-unified-knowledge-indexing-rag-concept.md`
- Architektonisch betroffen: `wiki/b-reference/platform/neutralization.md`, `wiki/b-reference/gateway/ai-agent.md`, `wiki/b-reference/frontend-nyla/architecture.md`
- Architektonisch betroffen: `wiki/b-reference/platform/neutralization.md`, `wiki/b-reference/platform-core/ai-agent.md`, `wiki/b-reference/ui-nyla/architecture.md`
- Code-Touchpoints: siehe Abschnitt „Kritische Stellen im Code"
## Abschluss
- [x] `b-reference/gateway/ai-agent.md` aktualisiert (Knowledge Lifecycle, DataSource-getriebener Walker, Cancel-Mechanismus)
- [x] `b-reference/platform-core/ai-agent.md` aktualisiert (Knowledge Lifecycle, DataSource-getriebener Walker, Cancel-Mechanismus)
- [x] `b-reference/platform/neutralization.md` aktualisiert (DataSource = SSoT, kein neutralizeBeforeEmbed mehr, Tree-Vererbung via subPolicyResolver) — 2026-05-15
- [x] `b-reference/frontend-nyla/architecture.md` aktualisiert (RagInventoryPage, UDB 4. Action-Button, RagRunningBadge, AddConnectionWizard) — 2026-05-15
- [x] `b-reference/ui-nyla/architecture.md` aktualisiert (RagInventoryPage, UDB 4. Action-Button, RagRunningBadge, AddConnectionWizard) — 2026-05-15
- [x] `TOPICS.md` aktualisiert (RAG-Inventar als neuer Kanon-Eintrag)
- [x] Dieses Dokument in `c-work/4-done/` (Status → `done`, 2026-05-15)
- [x] Eintrag im `c-work/_CHANGELOG.md`

View file

@ -1,9 +1,9 @@
<!-- status: done -->
<!-- started: 2026-05-18 -->
<!-- completed: 2026-05-18 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
<!-- lastReviewed: 2026-05-18 -->
<!-- verifiedAgainst: gateway/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py | gateway/modules/routes/routeDataSources.py | frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx -->
<!-- verifiedAgainst: platform-core/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py | platform-core/modules/routes/routeDataSources.py | ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx -->
# UDB Cascade-Inherit für DataSource-Flags (neutralize, ragIndexEnabled, scope)
@ -106,7 +106,7 @@ UI-Verhalten beim Toggle:
- Migration-Skript `script_db_migrate_datasource_inherit.py` (additiv-idempotent): ALTER COLUMN für die Spalten zu nullable. Bestehende Werte bleiben.
### S2: Cascade-Helper im Backend
- Neue Datei `gateway/modules/serviceCenter/services/serviceUdb/_cascadeInherit.py`:
- Neue Datei `platform-core/modules/serviceCenter/services/serviceUdb/_cascadeInherit.py`:
- `cascadeResetDescendants(rootIf, dataSourceId, flag) -> int` — gibt Anzahl betroffener Records zurück
- Audit-Logging via `recordModify` mit Reason `cascade_reset_<flag>`
@ -137,7 +137,7 @@ UI-Verhalten beim Toggle:
- Manuell: Connection mit Sub-Folders, Toggle Parent → Sub-Folder folgen ohne Cascade-DELETE
### S8: Wiki + Changelog
- `b-reference/gateway/architecture.md`: neuer Abschnitt "DataSource Cascade-Inherit"
- `b-reference/platform-core/architecture.md`: neuer Abschnitt "DataSource Cascade-Inherit"
- `_CHANGELOG.md` mit Begründung
## Risiken

View file

@ -1,7 +1,7 @@
<!-- status: build -->
<!-- started: 2026-05-17 -->
<!-- completed: 2026-05-17 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
# UDB DataSource Settings (⚙️) + konfigurierbare RAG-Limits
@ -14,6 +14,14 @@
> Das Modal zeigt fehlende Werte als Placeholder aus dem Cost-Estimate-Endpoint
> an, damit der User immer eine konkrete Zahl sieht — ohne die Datenbank-Zeile
> dafür anfassen zu müssen. Siehe CHANGELOG 2026-05-17 für die Detail-Liste.
>
> **Update 2026-05-28:** Minimale `ragLimits`-Vererbung implementiert.
> Das UI speichert Limits auf der Connection-Root-DataSource (path `/`),
> aber die Walker iterieren über Kind-DataSources (z.B. `sharepointFolder`),
> die `settings.ragLimits = null` haben. Fix: `_loadRagEnabledDataSources`
> in `subConnectorIngestConsumer.py` kopiert jetzt `ragLimits` vom Root
> auf Kinder ohne eigene Werte. `_finalizeResult` in allen 4 Walkern
> zeigt effektive Limits statt hartkodierter Defaults.
## Beschreibung und Kontext
@ -53,7 +61,7 @@ Wichtiger Architektur-Constraint:
- **Nicht-Ziel:**
- Mandate-weite Defaults / Override-Schichten / Resolver-Layer.
- Hard-Caps (User/Admin trägt Verantwortung).
- Settings-Vererbung im Tree (Parent-Folder → Children) aktuell wirkt eine Änderung nur auf die konkrete DataSource.
- ~~Settings-Vererbung im Tree (Parent-Folder → Children) aktuell wirkt eine Änderung nur auf die konkrete DataSource.~~ **Update 2026-05-28:** Minimale Vererbung implementiert: `ragLimits` auf der Connection-Root-DataSource (path `/`) werden an Kind-DataSources vererbt, die keine eigenen Werte haben. Dies behebt den Bug, dass im UI gesetzte Limits vom Walker ignoriert wurden (weil das UI auf dem Root speichert, der Walker aber Kind-Records liest). Volle Parent→Child-Vererbung im Tree bleibt Nicht-Ziel.
- Eigene Settings für Mail-Connectors (`Outlook`, `Gmail`) auf DataSource-Ebene die haben keine Folder-Hierarchie. Die Mail-Preferences bleiben Connection-weit und werden im Modal in der "Connection"-Sektion editiert.
## Architektur-Skizze
@ -100,7 +108,7 @@ MAX_ITEMS_DEFAULT = 10_000
```
Wird zu:
```python
# gateway/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py
# platform-core/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py
RAG_LIMITS_DEFAULT = {
"maxBytes": 200 * 1024 * 1024,
"maxFileSize": 25 * 1024 * 1024,
@ -167,15 +175,15 @@ Auf der `RagInventoryPage`-Partial-Banner-Komponente:
## Schritte
- [ ] S1 — Datenmodell: `settings: JSON` an `DataSource` und `FeatureDataSource` ergänzen (`gateway/modules/datamodels/datamodelDataSource.py`, `datamodelFeatureDataSource.py`); SQL-Migration in `gateway/scripts/script_db_migrate_datasource_settings.py`.
- [ ] S2 — Zentralisierte Defaults: `gateway/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py` neu mit `RAG_LIMITS_DEFAULT`, `getRagLimits()`, `lazyFillRagLimits()`.
- [ ] S1 — Datenmodell: `settings: JSON` an `DataSource` und `FeatureDataSource` ergänzen (`platform-core/modules/datamodels/datamodelDataSource.py`, `datamodelFeatureDataSource.py`); SQL-Migration in `platform-core/scripts/script_db_migrate_datasource_settings.py`.
- [ ] S2 — Zentralisierte Defaults: `platform-core/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py` neu mit `RAG_LIMITS_DEFAULT`, `getRagLimits()`, `lazyFillRagLimits()`.
- [ ] S3 — Walker-Refactor: `subConnectorSyncSharepoint.py`, `subConnectorSyncKdrive.py`, `subConnectorSyncGdrive.py`, `subConnectorSyncClickup.py` lesen Limits via `getRagLimits()` und schreiben Defaults via `lazyFillRagLimits()` zurück.
- [ ] S4 — Backend-Endpunkte: `PATCH /api/datasources/{id}/settings`, `PATCH /api/feature-data-sources/{id}/settings`, `GET /api/datasources/{id}/cost-estimate` in `routeDataSources.py` (und `routeFeatureDataSources.py`, falls noch nicht da). RBAC: Owner für DataSource, Owner + `workspace-admin` für FeatureDataSource.
- [ ] S5 — Frontend ⚙️-Button in `SourcesTab.tsx` (Tree-Row, zwischen 🧠 und 💬), Opacity-Logik: voll sichtbar, wenn `settings` befüllt sind, sonst gedimmt.
- [ ] S6 — Frontend `DataSourceSettingsModal.tsx`: drei Sektionen (Connection / RAG-Limits / Kostenschätzung), per-Feld-Validation, Speichern via API.
- [ ] S7 — `RagInventoryPage.tsx` Partial-Banner: Link "Limit anpassen" öffnet Modal für die betroffene DataSource (Heuristik: DS, die `stoppedAtLimit` ausgelöst hat bei mehreren: die mit den meisten verarbeiteten Bytes).
- [ ] S8 — Audit-Logging in den neuen Settings-Endpunkten.
- [ ] S9 — Cost-Estimate-Engine: `gateway/modules/serviceCenter/services/serviceKnowledge/_costEstimate.py` mit Heuristik (Items × Tokens × Embedding-Preis) und Basis-Annahmen-Output.
- [ ] S9 — Cost-Estimate-Engine: `platform-core/modules/serviceCenter/services/serviceKnowledge/_costEstimate.py` mit Heuristik (Items × Tokens × Embedding-Preis) und Basis-Annahmen-Output.
- [ ] S10 — Tests: Unit-Tests für `getRagLimits()` / `lazyFillRagLimits()`, API-Tests für PATCH-Endpunkte (RBAC), Cost-Estimate-Unit-Test, Frontend-Smoke-Test (Modal öffnet, speichert, refetch, Cost-Anzeige).
- [ ] S11 — Doku: `wiki/b-reference/platform/rag-pipeline.md` Abschnitt "Limits & Settings" ergänzen, plus Eintrag in `wiki/TOPICS.md`. CHANGELOG-Zeile.

View file

@ -1,9 +1,9 @@
<!-- status: done -->
<!-- started: 2026-05-18 -->
<!-- completed: 2026-05-18 -->
<!-- component: gateway | frontend-nyla -->
<!-- component: gateway | ui-nyla -->
<!-- lastReviewed: 2026-05-18 -->
<!-- verifiedAgainst: gateway/modules/serviceCenter/services/serviceKnowledge/_buildTree.py | gateway/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py | gateway/modules/features/workspace/routeFeatureWorkspace.py | gateway/modules/routes/routeDataSources.py | gateway/modules/datamodels/datamodelFeatureDataSource.py | frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx -->
<!-- verifiedAgainst: platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py | platform-core/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py | platform-core/modules/features/workspace/routeFeatureWorkspace.py | platform-core/modules/routes/routeDataSources.py | platform-core/modules/datamodels/datamodelFeatureDataSource.py | ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx -->
# UDB Generic Tree Refactor (Backend authoritativ, FE pure Renderer)
@ -62,7 +62,7 @@ Stable, parsebar, kollisionsfrei. Pipe-Separator:
### Builder
`gateway/modules/serviceCenter/services/serviceKnowledge/_buildTree.py` orchestriert pro Request:
`platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py` orchestriert pro Request:
- Vor-Laden aller DataSource-Records des Users (`recordFilter={"userId": userId}`) und aller FeatureDataSource-Records des Workspaces (`recordFilter={"workspaceInstanceId": instanceId}`) einmal.
- Dispatch pro Parent-Kind:
- `null` -> aktive Connections + zugaengliche Mandanten-Gruppen
@ -143,7 +143,7 @@ Erhalten (haben weitere Konsumenten ausserhalb UDB):
## Tests
Neu:
- `gateway/tests/unit/services/test_buildTree.py` (10 Tests): Key-Encoding/Decoding, `_effectiveTripletDs/Fds` Defaults+Inheritance, Record-Lookup (DS path-normalisation; FDS record-filter equality), `getChildrenForParents`-Smoke (unknown parent -> `[]`, leeres Top-Level).
- `platform-core/tests/unit/services/test_buildTree.py` (10 Tests): Key-Encoding/Decoding, `_effectiveTripletDs/Fds` Defaults+Inheritance, Record-Lookup (DS path-normalisation; FDS record-filter equality), `getChildrenForParents`-Smoke (unknown parent -> `[]`, leeres Top-Level).
- 5 neue Tests in `test_inheritFlags.py::TestResolveEffectiveForFds`: RAG inherits when only neutralize overridden; RAG aggregate-mixed; `_INHERITABLE_FDS_FLAGS` contains all 3 keys.
- `TestCascadeResetFdsRag::test_cascade_resets_rag_on_descendants`.
@ -153,9 +153,9 @@ Frontend: `npx tsc --noEmit --skipLibCheck` clean.
## Verifizierte Datei-Pfade
- Backend: `gateway/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`, `_inheritFlags.py`, `gateway/modules/features/workspace/routeFeatureWorkspace.py`, `gateway/modules/routes/routeDataSources.py`, `gateway/modules/datamodels/datamodelFeatureDataSource.py`
- Frontend: `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- Tests: `gateway/tests/unit/services/test_buildTree.py`, `test_inheritFlags.py`
- Backend: `platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`, `_inheritFlags.py`, `platform-core/modules/features/workspace/routeFeatureWorkspace.py`, `platform-core/modules/routes/routeDataSources.py`, `platform-core/modules/datamodels/datamodelFeatureDataSource.py`
- Frontend: `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- Tests: `platform-core/tests/unit/services/test_buildTree.py`, `test_inheritFlags.py`
## Nachtrag 2026-05-26: Spec Recovery

View file

@ -8,12 +8,38 @@ Eine Zeile pro Change, NEUESTE EINTRAEGE ZUOBERST. Begruendungen gehoeren ins zu
`c-work/<phase>/<feature>.md` oder die PR-Beschreibung.
Format: `- YYYY-MM-DD | <type> | <scope> | <Kurzbeschreibung> [(c-work: <relPfad>)] [(PR: #123)]`
type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `gateway` `frontend-nyla` `private-llm` `teams-bot` `wiki` `infra` `*`
type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `platform-core` `ui-nyla` `service-llm-private` `service-preprocessing` `teams-bot` `wiki` `infra` `*`
Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler.
## 2026-05-31
- 2026-05-31 | fix | ui-nyla | **UDB Sources panel compact**: Reduced tree indent from 24px to 16px, shrunk compact row height to 28px, smaller chevrons/icons/action buttons in compact mode for better label visibility
- 2026-05-31 | fix | ui-nyla | **Mobile FormGeneratorTable/Controls**: Controls stay horizontal (row wrap) on mobile instead of going vertical, reduced padding/gap/font-size on mobile for table cells and pagination
- 2026-05-31 | fix | ui-nyla | **Chat DataSource attach sends DataSource ID**: SourcesTab now resolves DataSource UUID via ensureDataSourceId before attaching (was incorrectly sending connectionId)
- 2026-05-31 | fix | platform-core | **TEXT to VECTOR schema migration**: Added auto-migration for TEXT->VECTOR columns in PostgreSQL connector, fixing broken semantic search on databases created before pgvector was declared
- 2026-05-31 | fix | platform-core | **ChatDocument DB fallback**: getChatDocumentsFromDocumentList now queries ChatDocument table directly when in-memory workflow lookup fails, preventing orphaned document references
- 2026-05-31 | fix | platform-core | **Table section string content normalization**: subStructureFilling validates table elements after AI JSON parse; string content (CSV/markdown/pipe) is parsed into {headers, rows} instead of crashing rendererMarkdown
## 2026-05-30
- 2026-05-30 | docs | wiki | **Depoformance Property Match — Backend ueber PORTA (Idee)**: 0-ideas-Dokument, das die Backend-Wuensche aus ihrer Techdoku (Kap. 11) in PORTA-Faehigkeiten uebersetzt statt Schlagworte woertlich zu nehmen. Mapping: 18 Provider-Interfaces -> generische RBAC-CRUD-Schicht; OpenRouter-Proxy -> unser AI-Gateway (serviceAi, kein OpenRouter); JWT-Felder -> PORTA Auth+RBAC (organizationId=mandateId); offene Punkte (Realtime/Upload/Mail/i18n/CI-CD) -> bereits PORTA-Plattformfunktionen; Security-Gate weitgehend abgedeckt. Keine Neutralisierung, CH-Residenz. Architektur: dedizierter Partner-Router (`/api/v1/depoformance/*`), der ihre Endpunkte durchschleift. Pricing: einmalig CHF 24'000 + API-Grundgebuehr CHF 600/Mo (inkl. 100k Calls) + AI pay-as-you-go. (c-work: 0-ideas/2026-05-depoformance-api-integration.md)
## 2026-05-29
- 2026-05-29 | docs | wiki | **Repo-Namen auf git.poweron.swiss/PowerOn migriert**: Wiki-weit alte Repo-/Pfad-Namen ersetzt (`frontend_nyla`/`frontend-nyla`→`ui-nyla`, `gateway`→`platform-core`, `private-llm`→`service-llm-private`). b-reference-Ordner umbenannt (gateway/ui-nyla/service-llm-private), README+product Komponenten-Tabellen aktualisiert, `service-preprocessing` ergaenzt, Changelog-Scope-Legende angepasst. Konzeptionelle Prosa-Begriffe (Gateway, Private-LLM) und z-archive/Changelog-Historie bewusst belassen.
- 2026-05-29 | feat | platform-core | **Anthropic Claude Opus 4.8 hinzugefuegt**: `aicorePluginAnthropic.py` um Opus 4.8 (`claude-opus-4-8`) erweitert -- Basic- + Vision-Variante, 1M Context, 128K max output, gleiche Preise wie 4.7 ($5/$25 pro M Tokens). `_supportsCustomTemperature` erkennt 4.8 als Extended-Thinking-Modell (sendet kein `temperature`).
- 2026-05-29 | feat | platform-core | **Private-LLM Next-Gen Modelle vorbereitet**: `aicorePluginPrivateLlm.py` um 3 neue Modell-Definitionen erweitert (deepseek-r1:70b Reasoning, llama4:scout Vision, nomic-embed-text Embedding). Werden automatisch aktiv wenn in Ollama verfuegbar -- kein Impact auf laufenden Betrieb.
- 2026-05-29 | feat | private-llm | **Config fuer GPU-Migration vorbereitet**: `config.py` Next-Gen MODEL_MAPPING als kommentierter Block, `_isVisionModel` um llama4/scout erweitert.
- 2026-05-29 | docs | wiki | **Private-LLM Architektur-Seite aktualisiert**: Migrations-Plan Infomaniak→FireStorm, geplante Modelle, Kostenvergleich dokumentiert.
- 2026-05-29 | feat | ui-nyla | **SourcesTab sendToChat fuer Mobile**: Chat-Icon (💬) im Sources-Tab reaktiviert -- `onSendToChat_FeatureSource` und `onAttachDataSource` an FormGeneratorTree durchgereicht. Mobile-User koennen nun Source-Objekte per Tap in den Chat senden.
- 2026-05-29 | fix | infra | **Gateway Workers auf 2 erhoeht** (prod+int): Single-Worker-Bottleneck behoben -- RAG-Indexierung blockierte User-Requests nicht mehr.
## 2026-05-28
- 2026-05-28 | fix | platform-core | **RAG ragLimits Vererbung**: `ragLimits` (z.B. `maxBytes`) auf der Connection-Root-DataSource (path `/`) wurden nicht an Kind-DataSources vererbt -- Walker fielen immer auf den 200 MB Default zurueck. Fix: `_loadRagEnabledDataSources` propagiert `settings.ragLimits` vom Connection-Root auf Kinder ohne eigene Werte. `_finalizeResult` in allen 4 Walkern (SharePoint, GDrive, kDrive, ClickUp) zeigt nun effektive Limits statt hartkodierter Defaults.
- 2026-05-28 | feat | platform-core+ui-nyla | **DB Migration Streaming Import**: Import grosser JSON-Dateien (>1 GB) lief bisher komplett im RAM (`json.load()`), was OOM verursachte. Neuer Two-Pass-Ansatz mit `ijson` fuer speicher-effizientes Parsen: Pass 1 validiert + extrahiert Metadaten, Pass 2 splittet in per-Table JSONL-Dateien. Neuer `GET /process-import-stream` Endpoint mit `StreamingResponse` (ndjson) fuer Echtzeit-Fortschritt waehrend Validierung und Split. Frontend zeigt dynamischen Progress (Phase, DB, Tabelle, Datensatzzahl).
- 2026-05-28 | feat | platform-core+ui-nyla | **DB Migration Streaming Export**: Export lief bisher client-seitig (`JSON.stringify`) und schlug bei grossen DBs fehl (`RangeError: Invalid string length`). Neuer `GET /export-stream` Endpoint streamt die gesamte Export-JSON inkrementell via `StreamingResponse`. Frontend nutzt `fetch()` + `ReadableStream` + File System Access API fuer direktes Streaming-to-Disk. Fortschrittslog zeigt aktuelle DB x/n mit MB-Angabe.
- 2026-05-28 | fix | private-llm+infra | **LLM-Server Recovery**: Ollama-Modelle (`qwen2.5:7b`, `qwen2.5vl:7b`, `granite3.2-vision`) auf Infomaniak GPU-Server neu installiert (waren nach Instanz-Neustart verloren). NVIDIA-Treiber-Mismatch per Reboot behoben. pgvector Extension auf prod+int DB-Servern installiert (OS-Package + CREATE EXTENSION). Doku aktualisiert: `setupserver.md`, `README.md`, `infrastructure.md` (DB-Setup-Anleitung fuer neue Installationen).
## 2026-05-27

View file

@ -1,6 +1,6 @@
<!-- status: plan | build | validate | done -->
<!-- started: YYYY-MM-DD -->
<!-- component: gateway | frontend-nyla | private-llm | teams-bot | platform -->
<!-- component: gateway | ui-nyla | service-llm-private | teams-bot | platform -->
# <Feature/Refactor Titel>
@ -52,7 +52,7 @@ Welche Abhängigkeiten bestehen? Was ist das Risiko wenn wir es NICHT machen?
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | ja | gateway/tests/... | pending |
| T1 | 1 | api | ja | platform-core/tests/... | pending |
## Links

View file

@ -147,7 +147,7 @@ Referenz-Implementation: `modules/features/trustee/accounting/accountingDataSync
Backend-Code, der **gespeicherte** Zeitstempel produziert (DB-Felder, Audit-Logs, Token-Expiry), nutzt **UTC** via `getUtcTimestamp()`, `getUtcNow()` oder `getIsoTimestamp()` aus `modules/shared/timeUtils.py`.
Backend-Code, der **user-sichtbare** "jetzt"-Werte produziert (AI-Agent-System-Prompt, gerenderte Display-Strings, formatierte Logs an den Endnutzer), nutzt `getRequestNow()` / `getRequestTimezone()`. Diese lesen die Browser-Zeitzone, die das Frontend per `X-User-Timezone`-Header schickt (Axios-Interceptor in `frontend_nyla/src/api.ts`) und die `_requestContextMiddleware` (`app.py`) in eine `ContextVar` schreibt — analog zum `_setLanguage`-Pattern.
Backend-Code, der **user-sichtbare** "jetzt"-Werte produziert (AI-Agent-System-Prompt, gerenderte Display-Strings, formatierte Logs an den Endnutzer), nutzt `getRequestNow()` / `getRequestTimezone()`. Diese lesen die Browser-Zeitzone, die das Frontend per `X-User-Timezone`-Header schickt (Axios-Interceptor in `ui-nyla/src/api.ts`) und die `_requestContextMiddleware` (`app.py`) in eine `ContextVar` schreibt — analog zum `_setLanguage`-Pattern.
```python
from modules.shared.timeUtils import getUtcTimestamp, getRequestNow
@ -158,7 +158,7 @@ nowForUser = getRequestNow() # Anzeige/Prompt -> tz-aware datetime
**Verboten:** Hardcoded-Zeitzonen wie `ZoneInfo("Europe/Zurich")` als Default fuer User-Anzeige. Stattdessen die Request-TZ benutzen; ohne HTTP-Kontext (z.B. Scheduler) faellt `getRequestNow()` automatisch auf UTC zurueck.
**Frontend:** User-sichtbare Zeitstempel werden mit `formatUnixTimestamp()` aus `frontend_nyla/src/utils/time.ts` formatiert; ohne expliziten `timeZone`-Override nimmt `toLocaleString` die Browser-TZ. Backend-Felder bleiben UTC-Floats (`number`).
**Frontend:** User-sichtbare Zeitstempel werden mit `formatUnixTimestamp()` aus `ui-nyla/src/utils/time.ts` formatiert; ohne expliziten `timeZone`-Override nimmt `toLocaleString` die Browser-TZ. Backend-Felder bleiben UTC-Floats (`number`).
### Debug-File-Dumps: nur DEV, niemals INT/PROD
@ -303,7 +303,7 @@ Legacy `{en, de, fr}`-Dicts werden via `_extractRegistrySourceText()` auf den `x
## Projektstruktur Gateway
```
gateway/
platform-core/
app.py # FastAPI-App, Middleware, Startup
config.ini # Statische Konfiguration
modules/
@ -392,7 +392,7 @@ def getAgentOntology() -> OntologyDescriptor:
return _ONTOLOGY
```
**Warum:** Die Ontologie ist die Single Source of Truth fuer Prompt **und** Validator. Aenderungen an einer `Constraint` wirken sowohl auf den AI-Steering-Block als auch auf die deterministische Pre-Execute-Validierung -- es gibt keine Drift zwischen Prompt-Text und Tool-Reject-Logik mehr. Mehr Hintergrund: `b-reference/gateway/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie" und `b-reference/gateway/features/trustee.md` als Referenz-Pilot.
**Warum:** Die Ontologie ist die Single Source of Truth fuer Prompt **und** Validator. Aenderungen an einer `Constraint` wirken sowohl auf den AI-Steering-Block als auch auf die deterministische Pre-Execute-Validierung -- es gibt keine Drift zwischen Prompt-Text und Tool-Reject-Logik mehr. Mehr Hintergrund: `b-reference/platform-core/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie" und `b-reference/platform-core/features/trustee.md` als Referenz-Pilot.
**Backward-Compatibility:** Features, die `getAgentOntology()` (noch) nicht haben, behalten ihren bestehenden `getAgentDomainHints()`-Pfad ohne Code-Change. Der Sub-Agent nutzt automatisch den passenden Block.

View file

@ -13,7 +13,7 @@
## Gateway starten
```bash
cd gateway/
cd platform-core/
# Python-Umgebung aktivieren (Conda oder venv)
conda activate <env>
# oder: python -m venv .venv && .\.venv\Scripts\Activate.ps1
@ -21,7 +21,7 @@ conda activate <env>
pip install -r requirements.txt
# Config vorbereiten:
# 1. config.ini muss im gateway/ Verzeichnis liegen (statische Settings)
# 1. config.ini muss im platform-core/ Verzeichnis liegen (statische Settings)
# 2. .env Datei aus env_dev.env kopieren/symlinken:
# copy env_dev.env .env
# 3. APP_KEY_SYSVAR in config.ini zeigt auf Master-Key (OS-Variable oder Dateipfad)
@ -33,11 +33,11 @@ uvicorn app:app --host 0.0.0.0 --port 8000
| Datei | Zweck |
|-------|-------|
| `gateway/config.ini` | Statische Settings (Auth-Defaults, Upload-Limits, Operator-Text) |
| `gateway/.env` | Runtime-Env (DB, API-Keys, Secrets) -- wird aus `env_dev.env` kopiert |
| `gateway/env_dev.env` | Dev-Umgebung Template (verschluesselte Secrets mit `DEV_ENC:` Prefix) |
| `gateway/env_int.env` | Integration-Umgebung |
| `gateway/env_prod.env` | Produktion |
| `platform-core/config.ini` | Statische Settings (Auth-Defaults, Upload-Limits, Operator-Text) |
| `platform-core/.env` | Runtime-Env (DB, API-Keys, Secrets) -- wird aus `env_dev.env` kopiert |
| `platform-core/env_dev.env` | Dev-Umgebung Template (verschluesselte Secrets mit `DEV_ENC:` Prefix) |
| `platform-core/env_int.env` | Integration-Umgebung |
| `platform-core/env_prod.env` | Produktion |
### Wichtige Env-Variablen (Auszug)
@ -53,7 +53,7 @@ uvicorn app:app --host 0.0.0.0 --port 8000
## Frontend Nyla starten
```bash
cd frontend_nyla/
cd ui-nyla/
npm install
npm run dev
# oder: npx vite --port 5176 --mode dev
@ -65,9 +65,9 @@ Frontend laeuft auf **http://localhost:5176** und erwartet Gateway auf **http://
| Datei | Zweck |
|-------|-------|
| `frontend_nyla/config/.env.dev` | Dev-Mode Env (VITE_API_BASE_URL etc.) |
| `frontend_nyla/config/.env.int` | Integration |
| `frontend_nyla/config/.env.prod` | Produktion |
| `ui-nyla/config/.env.dev` | Dev-Mode Env (VITE_API_BASE_URL etc.) |
| `ui-nyla/config/.env.int` | Integration |
| `ui-nyla/config/.env.prod` | Produktion |
## Secrets-Verwaltung

View file

@ -6,9 +6,9 @@ Diese Anleitung beschreibt, wie das PowerOn-Gateway-Tool `scripts/script_securit
### 1) Einsatz in beliebigen Repositories & Voraussetzungen
Das Tool kann in jedem Repository eingesetzt werden, sofern die untenstehenden Vorbedingungen erfüllt sind. Standardmäßig ist es im Ordner `gateway` integriert und erwartet dort seine Abhängigkeiten. In anderen Repos müssen Sie die Gateway-Komponenten bereitstellen oder den `PYTHONPATH` entsprechend setzen.
Das Tool kann in jedem Repository eingesetzt werden, sofern die untenstehenden Vorbedingungen erfüllt sind. Standardmäßig ist es im Ordner `platform-core` integriert und erwartet dort seine Abhängigkeiten. In anderen Repos müssen Sie die Gateway-Komponenten bereitstellen oder den `PYTHONPATH` entsprechend setzen.
- **Ausführungspfad**: Entweder im Verzeichnis, das die Gateway-Module `modules/shared` enthält (z. B. `gateway`), oder mit gesetztem `PYTHONPATH`, sodass `modules/shared/configuration.py` importiert werden kann.
- **Ausführungspfad**: Entweder im Verzeichnis, das die Gateway-Module `modules/shared` enthält (z. B. `platform-core`), oder mit gesetztem `PYTHONPATH`, sodass `modules/shared/configuration.py` importiert werden kann.
- **Python**: Python 3.10+ mit Abhängigkeiten (siehe Kapitel „Vorbedingungen“). Installation z. B.:
- Windows PowerShell im Repo-Root: `python -m venv .venv && .\.venv\Scripts\Activate.ps1`
- `pip install -r requirements.txt`
@ -17,7 +17,7 @@ Das Tool kann in jedem Repository eingesetzt werden, sofern die untenstehenden V
- Die zu verarbeitenden Env-Dateien: `env_dev.env`, `env_int.env`, `env_prod.env` (oder eine Teilmenge via `--files`).
- **Rechte**: Schreibrechte auf die Env-Dateien, Leserechte auf die Masterkey-Quelle (siehe Punkt 2).
Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py`. Stellen Sie sicher, dass dieser Pfad importierbar ist (Start im Gateway-Verzeichnis oder `PYTHONPATH` setzen). Das Script fuegt `gateway` automatisch zu `sys.path` hinzu.
Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py`. Stellen Sie sicher, dass dieser Pfad importierbar ist (Start im Gateway-Verzeichnis oder `PYTHONPATH` setzen). Das Script fuegt `platform-core` automatisch zu `sys.path` hinzu.
---
@ -27,9 +27,9 @@ Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py
```
cryptography>=41.0.0
```
Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `gateway/requirements.txt`.
Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `platform-core/requirements.txt`.
2. Notwendige Gateway-Komponenten (sofern außerhalb von `gateway` verwendet):
2. Notwendige Gateway-Komponenten (sofern außerhalb von `platform-core` verwendet):
- `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_getMasterKey`, `encryptValue`, `decryptValue`)
- Optional, aber unterstützt: `modules/shared/auditLogger.py` (Audit-Events; Ausfall ist toleriert)
- `config.ini` im gleichen Baum wie `modules`, mit mindestens:
@ -37,7 +37,7 @@ Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py
- `APP_KEY_SYSVAR = <OS_ENV_NAME|Pfad_zur_Keydatei>`
3. Struktur/Importpfade sicherstellen:
- Entweder das Tool im Ordner ausführen, der die `modules`-Struktur enthält (z. B. `gateway`).
- Entweder das Tool im Ordner ausführen, der die `modules`-Struktur enthält (z. B. `platform-core`).
- Oder `PYTHONPATH` so setzen, dass `modules` auflösbar ist, z. B. PowerShell:
```powershell
$env:PYTHONPATH = (Resolve-Path .)
@ -70,7 +70,7 @@ Wichtig: Die Umgebung für die Verschlüsselung wird pro Datei aus der jeweilige
### 3) Anwendung und Verhalten
Tool: `gateway/tool_security_encrypt_all_env_files.py`
Tool: `platform-core/tool_security_encrypt_all_env_files.py`
- Standardlauf (alle drei Dateien, mit Backup):
```bash
@ -125,7 +125,7 @@ Fehlerbilder und Checks:
### Referenz
- Schlüsselauflösung und Verschlüsselung: `gateway/modules/shared/configuration.py` (`_get_master_key`, `_derive_encryption_key`, `encrypt_value`).
- Batch-Tool: `gateway/tool_security_encrypt_all_env_files.py` (`encrypt_all_secrets_in_file`, `process_all_env_files`).
- Schlüsselauflösung und Verschlüsselung: `platform-core/modules/shared/configuration.py` (`_get_master_key`, `_derive_encryption_key`, `encrypt_value`).
- Batch-Tool: `platform-core/tool_security_encrypt_all_env_files.py` (`encrypt_all_secrets_in_file`, `process_all_env_files`).

View file

@ -29,7 +29,7 @@ This guide explains how to set up Google OAuth 2.0 authentication for the Porta
3. If prompted, configure the OAuth consent screen first:
- Choose "External" user type
- Fill in the required fields (App name, User support email, Developer contact information)
- Add scopes (see `gateway/modules/auth/oauthProviderConfig.py` -- `googleAuthScopes` and `googleDataScopes` are the source of truth):
- Add scopes (see `platform-core/modules/auth/oauthProviderConfig.py` -- `googleAuthScopes` and `googleDataScopes` are the source of truth):
- **Auth app** (login only):
- `openid`
- `https://www.googleapis.com/auth/userinfo.profile`
@ -68,7 +68,7 @@ This guide explains how to set up Google OAuth 2.0 authentication for the Porta
## Step 4: Configure Porta Application
1. Open your environment file (`gateway/env_dev.env` for development)
1. Open your environment file (`platform-core/env_dev.env` for development)
2. Replace the placeholder values with your actual Google OAuth credentials:
```env

View file

@ -21,7 +21,7 @@
| GCP-Projekt-ID | (siehe `env_prod.env`, `Service_GOOGLE_DATA_CLIENT_ID`) |
| Verwendete Google-Scopes | `openid`, `userinfo.email`, `userinfo.profile`, `gmail.readonly`, `drive.readonly` |
> Bei jeder Änderung an Scopes (`gateway/modules/auth/oauthProviderConfig.py::googleDataScopes`)
> Bei jeder Änderung an Scopes (`platform-core/modules/auth/oauthProviderConfig.py::googleDataScopes`)
> diese Tabelle, die OAuth-Consent-Screen-Konfiguration in der GCP-Console
> **und** die Privacy-Policy synchron halten — Google bouncet sonst die
> Verification.
@ -350,7 +350,7 @@ Vor dem (erneuten) Klick auf „Submit for verification" alles abhaken:
* Application privacy policy link: `https://porta.poweron.swiss/poweron-privacy.html`.
* Application terms of service link: `https://porta.poweron.swiss/poweron-terms.html`.
* [ ] Scope-Liste im Consent-Screen identisch zu `googleDataScopes` in
`gateway/modules/auth/oauthProviderConfig.py`.
`platform-core/modules/auth/oauthProviderConfig.py`.
* [ ] Jeder Scope hat eine Justification (Kapitel 2 dieses Dokuments).
* [ ] Demo-Video (Kapitel 3) auf YouTube unlisted, Link im Antrag.
* [ ] Developer-E-Mail `p.motsch@poweron.swiss` empfangsbereit; Eingangs-Mail

View file

@ -28,7 +28,7 @@ Projekt auswählen → **APIs & Services** → **Library**.
- App-Name, Support-Mail, Developer Contact wie von Google gefordert.
- **Scopes** müssen zur Code-Basis passen (Single Source of Truth):
`gateway/modules/auth/oauthProviderConfig.py` → `googleAuthScopes`, `googleDataScopes`
`platform-core/modules/auth/oauthProviderConfig.py` → `googleAuthScopes`, `googleDataScopes`
Kurzreferenz:
@ -61,15 +61,15 @@ Das Gateway unterstützt **getrennte Auth- und Data-Clients** (unterschiedliche
- PROD: `https://gateway-prod.poweron.swiss`
- Forgejo/ALT-Prod (falls genutzt): `https://api.poweron.swiss` — in `env-gateway-prod-forgejo.env` Google `*_REDIRECT_URI` ggf. noch setzen.
Backend-Routing: `gateway/modules/routes/routeSecurityGoogle.py`.
Backend-Routing: `platform-core/modules/routes/routeSecurityGoogle.py`.
---
## 4) Speech / Voice (ohne User-OAuth)
**Credentials** → **API key** (empfohlen:auf Speech + TTS beschränken) **oder** Service-Account nach Vorgabe des Connector (siehe `gateway/modules/connectors/connectorVoiceGoogle.py`: `Connector_GoogleSpeech_API_KEY_SECRET` kann API-Key oder SA-JSON sein).
**Credentials** → **API key** (empfohlen:auf Speech + TTS beschränken) **oder** Service-Account nach Vorgabe des Connector (siehe `platform-core/modules/connectors/connectorVoiceGoogle.py`: `Connector_GoogleSpeech_API_KEY_SECRET` kann API-Key oder SA-JSON sein).
Doku STT/TTS: [`b-reference/gateway/voice-google.md`](../b-reference/gateway/voice-google.md).
Doku STT/TTS: [`b-reference/platform-core/voice-google.md`](../b-reference/platform-core/voice-google.md).
---
@ -87,7 +87,7 @@ Alle Werte **ohne** echte Secrets im Wiki; in den Deploy-Envs mit eurem Verschl
| `Service_GOOGLE_DATA_REDIRECT_URI` | Muss **1:1** mit Google Console Connect-Callback übereinstimmen |
| `Connector_GoogleSpeech_API_KEY_SECRET` | Speech/TTS API-Key oder SA-JSON (verschlüsselt) |
**Dateien (Stand Repo):** `gateway/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `gateway/.env`.
**Dateien (Stand Repo):** `platform-core/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `platform-core/.env`.
Zusätzlich — wenn neues **Frontend** oder neuer **API-Host**:
@ -100,11 +100,11 @@ Zusätzlich — wenn neues **Frontend** oder neuer **API-Host**:
| Datei | Wann anfassen |
|-------|----------------|
| `gateway/modules/auth/oauthProviderConfig.py` | Neue/entfernte Google-Scopes für Login oder Datenverbindung |
| `gateway/modules/routes/routeSecurityGoogle.py` | Nur bei Flow-/Route-Änderungen (unüblich) |
| `gateway/modules/auth/tokenManager.py` | Nutzt `Service_GOOGLE_DATA_*` für Refresh — keine manuelle Anpassung bei reiner Registrierung |
| `platform-core/modules/auth/oauthProviderConfig.py` | Neue/entfernte Google-Scopes für Login oder Datenverbindung |
| `platform-core/modules/routes/routeSecurityGoogle.py` | Nur bei Flow-/Route-Änderungen (unüblich) |
| `platform-core/modules/auth/tokenManager.py` | Nutzt `Service_GOOGLE_DATA_*` für Refresh — keine manuelle Anpassung bei reiner Registrierung |
Token-Refresh und Microsoft/Google Data: `gateway/modules/auth/tokenManager.py`.
Token-Refresh und Microsoft/Google Data: `platform-core/modules/auth/tokenManager.py`.
---

View file

@ -43,7 +43,7 @@ Pro öffentlich erreichbare Gateway-URL **drei** URIs (exakt, inkl. Schema):
Implizite Flow / SPA: für dieses Gateway-Backend-Redirect-Muster **nicht** nötig (Confidential Client mit Secret).
Backend-Routing: `gateway/modules/routes/routeSecurityMsft.py` (Prefix `/api/msft`).
Backend-Routing: `platform-core/modules/routes/routeSecurityMsft.py` (Prefix `/api/msft`).
---
@ -61,7 +61,7 @@ Verschlüsselung siehe [`encrypt-env-secrets.md`](encrypt-env-secrets.md).
**API permissions** → **Add a permission****Microsoft Graph****Delegated permissions**.
Single Source of Truth für die Scope-Liste: `gateway/modules/auth/oauthProviderConfig.py` → `msftAuthScopes`, `msftDataScopes`
Single Source of Truth für die Scope-Liste: `platform-core/modules/auth/oauthProviderConfig.py` → `msftAuthScopes`, `msftDataScopes`
| Zweck | Graph permissions (delegated) |
|-------|-------------------------------|
@ -88,7 +88,7 @@ Zusätzlicher Flow im Gateway: Admin-Consent-URL unter **`/api/msft/adminconsent
| `Service_MSFT_DATA_REDIRECT_URI` | Muss **1:1** mit Entra Connect-Redirect übereinstimmen |
| `Service_MSFT_TENANT_ID` | `common` (Multi-Tenant-Anmeldung) **oder** Verzeichnis-ID (GUID) des Tenants **poweron.swiss** für Single-Tenant-Authority |
**Dateien (Stand Repo):** `gateway/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `gateway/.env`.
**Dateien (Stand Repo):** `platform-core/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `platform-core/.env`.
Wenn neues **Frontend** oder neuer **API-Host**:
@ -101,10 +101,10 @@ Wenn neues **Frontend** oder neuer **API-Host**:
| Datei | Inhalt |
|-------|--------|
| `gateway/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` |
| `gateway/modules/routes/routeSecurityMsft.py` | Login, Connect, Admin-Consent; liest alle `Service_MSFT_*` |
| `gateway/modules/auth/tokenManager.py` | Refresh für Microsoft Data (`Service_MSFT_DATA_*`, `Service_MSFT_TENANT_ID`) |
| `gateway/modules/auth/csrf.py` | CSRF-Ausnahmen für `/api/msft/auth/*` und `/api/msft/adminconsent*` — bei **neuen** OAuth-Pfaden ggf. erweitern (selten) |
| `platform-core/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` |
| `platform-core/modules/routes/routeSecurityMsft.py` | Login, Connect, Admin-Consent; liest alle `Service_MSFT_*` |
| `platform-core/modules/auth/tokenManager.py` | Refresh für Microsoft Data (`Service_MSFT_DATA_*`, `Service_MSFT_TENANT_ID`) |
| `platform-core/modules/auth/csrf.py` | CSRF-Ausnahmen für `/api/msft/auth/*` und `/api/msft/adminconsent*` — bei **neuen** OAuth-Pfaden ggf. erweitern (selten) |
Keine Code-Änderung nötig, solange **gleiche Routen** und **gleiche Scope-Menge** wie in `oauthProviderConfig.py` verwendet werden.

View file

@ -23,7 +23,7 @@ Top-Up-Rechnungen automatisch konform erstellt.
| Bereich | Datei | Was passiert |
|---------|-------|--------------|
| Mandant-Modell | `gateway/modules/datamodels/datamodelUam.py` -- `Mandate.invoice*` (10 strukturierte Felder) | Rechnungsadresse als einzelne Felder: `invoiceCompanyName`, `invoiceContactName`, `invoiceEmail`, `invoiceLine1`, `invoiceLine2`, `invoicePostalCode`, `invoiceCity`, `invoiceState`, `invoiceCountry` (default `CH`), `invoiceVatNumber`. Der FormGenerator rendert die Felder ueber `order: 200..209` automatisch gruppiert am Ende des Edit-Formulars. |
| Mandant-Modell | `platform-core/modules/datamodels/datamodelUam.py` -- `Mandate.invoice*` (10 strukturierte Felder) | Rechnungsadresse als einzelne Felder: `invoiceCompanyName`, `invoiceContactName`, `invoiceEmail`, `invoiceLine1`, `invoiceLine2`, `invoicePostalCode`, `invoiceCity`, `invoiceState`, `invoiceCountry` (default `CH`), `invoiceVatNumber`. Der FormGenerator rendert die Felder ueber `order: 200..209` automatisch gruppiert am Ende des Edit-Formulars. |
| Stripe-Customer | `serviceCenter/services/serviceBilling/stripeCheckout.py` -- `_ensureStripeCustomer` | Bei jedem Checkout wird ein Stripe-Customer angelegt/aktualisiert: `name` = `invoiceCompanyName` (Fallback Mandant-Label), `email` = `invoiceEmail`, `address` = strukturiertes `{ line1, line2, postal_code, city, state, country }`, `shipping` = z. H. + Adresse, beim _Create_ ausserdem `tax_id_data` aus `invoiceVatNumber` (CHE -> `ch_vat`, LI -> `li_uid`, EU -> `eu_vat`). Die `stripeCustomerId` wird im `BillingSettings` gecacht. |
| Rechnungserzeugung | `create_checkout_session` setzt `invoice_creation: { enabled: true, invoice_data: {...} }` | Stripe erzeugt automatisch eine **Rechnung** (statt nur einer Quittung) mit Status `paid`, der vollstaendigen Customer-Adresse, unserem Footer-Hinweis "bereits via Kreditkarte bezahlt" und (bei vorhandener UID/z.H.) `invoice_data.custom_fields` mit `UID-Nr. Empfaenger` / `z. H.`. |
| MWST | `create_checkout_session` -- `automatic_tax` ODER `tax_rates` | Wenn `STRIPE_AUTOMATIC_TAX_ENABLED=true`, wird Stripe Tax verwendet. Andernfalls wird der Tax-Rate aus `STRIPE_TAX_RATE_ID_CH_VAT` an jede Line-Item gehaengt. |

View file

@ -12,7 +12,7 @@
/ Unit \ <- pytest (Models, Utils, Logic)
```
## Gateway: `gateway/tests/`
## Gateway: `platform-core/tests/`
### Test-Kategorien
@ -49,7 +49,7 @@ tests/
### Tests ausfuehren
```bash
cd gateway/
cd platform-core/
# Standard (ohne expensive-Marker):
pytest
@ -71,7 +71,7 @@ pytest --cov=modules tests/unit/
### Konfiguration
`pytest.ini` im `gateway/`-Root:
`pytest.ini` im `platform-core/`-Root:
- `testpaths = tests`, `pythonpath = .`
- Log-Output: `logs/test_logs.log`
- Default: `-v --tb=short -m 'not expensive'`
@ -98,8 +98,8 @@ Then <erwartetes Ergebnis>
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | gateway/tests/unit/... | pending |
| T2 | 2 | integration | ja | gateway/tests/integration/... | pending |
| T1 | 1 | unit | ja | platform-core/tests/unit/... | pending |
| T2 | 2 | integration | ja | platform-core/tests/integration/... | pending |
| T3 | 3 | api | nein | -- | pending |
Referenz: -> `c-work/_TEMPLATE.md` (Testplan-Section)