Compare commits

..

No commits in common. "244726a7167096a5f348ac93cc31abc3197cac4b" and "a9241c6e475fce9f92f269f275a82ede7267bff4" have entirely different histories.

96 changed files with 1288 additions and 1639 deletions

View file

@ -7,12 +7,11 @@
PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung. PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-Agent-Workspace und mandantenweiter Datenneutralisierung.
| Komponente | Repository (Forgejo: git.poweron.swiss/PowerOn) | Technologie | Beschreibung | | Komponente | Repository | Technologie | Beschreibung |
|-----------|-----------|-------------|-------------| |-----------|-----------|-------------|-------------|
| Frontend Nyla | `ui-nyla` | React/TypeScript, Vite | Zentrales UI für alle Features | | Frontend Nyla | `frontend_nyla` | React/TypeScript, Vite | Zentrales UI für alle Features |
| Platform Core | `platform-core` | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core | | Gateway | `gateway` | FastAPI, Python, PostgreSQL | Backend REST-API, Services, AI-Core |
| Private LLM | `service-llm-private` | Python | Internes LLM für Neutralisierung + sensitive Daten | | Private LLM | `private-llm` | 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 | | Teams Bot | `service-teams-browser-bot` | TypeScript/Node.js | Bot für Teams-Meeting-Teilnahme |
| Wiki | `wiki` | Markdown | Dokumentation (dieses Repo) | | Wiki | `wiki` | Markdown | Dokumentation (dieses Repo) |
@ -54,7 +53,7 @@ PowerOn PORTA ist eine Multi-Tenant SaaS-Plattform mit Feature-Store-Modell, AI-
``` ```
b-reference/ b-reference/
├── product.md Komponentenübersicht, Repo-Map, Tech-Stack ├── product.md Komponentenübersicht, Repo-Map, Tech-Stack
├── platform-core/ Backend-Komponente ├── gateway/ Backend-Komponente
│ ├── architecture.md Module, Services, Interfaces │ ├── architecture.md Module, Services, Interfaces
│ ├── ai-agent.md Agent Core, Tools, Knowledge/RAG │ ├── ai-agent.md Agent Core, Tools, Knowledge/RAG
│ ├── workflow.md Workflow-Engine, Methoden, Aktionen │ ├── workflow.md Workflow-Engine, Methoden, Aktionen
@ -62,9 +61,9 @@ b-reference/
│ ├── billing.md Billing, Subscriptions │ ├── billing.md Billing, Subscriptions
│ ├── voice-google.md Google STT/TTS (VoiceObjects, Streaming-WS, Feature-Mapping) │ ├── voice-google.md Google STT/TTS (VoiceObjects, Streaming-WS, Feature-Mapping)
│ └── features/ trustee.md, commcoach.md, chatbot.md, ... │ └── features/ trustee.md, commcoach.md, chatbot.md, ...
├── ui-nyla/ Frontend-Komponente ├── frontend-nyla/ Frontend-Komponente
│ └── architecture.md Seiten, Komponenten, Hooks, Routing │ └── architecture.md Seiten, Komponenten, Hooks, Routing
├── service-llm-private/ Internes LLM ├── private-llm/ Internes LLM
│ └── architecture.md Setup, Modelle, Gateway-Integration │ └── architecture.md Setup, Modelle, Gateway-Integration
├── teams-bot/ Teams Meeting Bot ├── teams-bot/ Teams Meeting Bot
│ └── architecture.md Service, WebSocket, Architektur │ └── architecture.md Service, WebSocket, Architektur
@ -91,5 +90,5 @@ b-reference/
``` ```
<!-- status: canonical | draft | superseded --> <!-- status: canonical | draft | superseded -->
<!-- lastReviewed: YYYY-MM-DD --> <!-- lastReviewed: YYYY-MM-DD -->
<!-- verifiedAgainst: platform-core@<sha>, ui-nyla@<sha> --> <!-- verifiedAgainst: gateway@<sha>, frontend_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 | | Thema | Datei | Wann laden |
|-------|-------|------------| |-------|-------|------------|
| Komponentenübersicht | b-reference/product.md | Repo-übergreifende Fragen, Tech-Stack | | Komponentenübersicht | b-reference/product.md | Repo-übergreifende Fragen, Tech-Stack |
| Gateway-Architektur | b-reference/platform-core/architecture.md | Backend-Module, Services, Interfaces | | Gateway-Architektur | b-reference/gateway/architecture.md | Backend-Module, Services, Interfaces |
| AI Agent & Tools | b-reference/platform-core/ai-agent.md | Agent-Verhalten, Tool-Registrierung, RAG | | AI Agent & Tools | b-reference/gateway/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 | | 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/platform-core/workflow.md | Methoden, Aktionen, WorkflowManager | | Workflow-Engine | b-reference/gateway/workflow.md | Methoden, Aktionen, WorkflowManager |
| Automation | b-reference/platform-core/automation.md | Graphical Editor, Scheduler, System-Automatisierung (`/automations`, `/api/system/workflow-runs/*`) | | Automation | b-reference/gateway/automation.md | Graphical Editor, Scheduler, System-Automatisierung (`/automations`, `/api/system/workflow-runs/*`) |
| Billing & Subscriptions | b-reference/platform-core/billing.md | Abrechnung, Prepaid, State Machine | | Billing & Subscriptions | b-reference/gateway/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 | | Google Voice (STT/TTS) | b-reference/gateway/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 | | Frontend Nyla | b-reference/frontend-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 | | FormGenerator (Table, Form, Tree, Report) | b-reference/frontend-nyla/formgenerator.md | Generische UI-Komponenten, Provider-Pattern, API-Anbindung |
| Private LLM | b-reference/service-llm-private/architecture.md | Internes LLM, Neutralisierung | | Private LLM | b-reference/private-llm/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 | | 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) ## 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 | | 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 | | 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 | | Compliance & AI-Audit | b-reference/platform/audit.md | AI-Datenfluss-Log, Security-Audit, Statistiken, RBAC |
| 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 | | 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 |
## Aktive Arbeiten (c-work) ## 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 | | 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 | | 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 | | 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/platform-core/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/gateway/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 | | 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 | | 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 | | 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/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 | | **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 |
## Infrastruktur & Deployment ## Infrastruktur & Deployment

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-15 --> <!-- lastReviewed: 2026-05-15 -->
<!-- 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) --> <!-- 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) -->
# Frontend Nyla -- Architektur # 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) ## 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 `ui-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 `frontend_nyla/src/components/FlowEditor/**/*.test.tsx`.
### Picker-Komponenten ### Picker-Komponenten
@ -134,7 +134,7 @@ Seit April 2026 stuetzt sich der FlowEditor (Graphical Editor) auf eine typisier
### Tests (Vitest + RTL) ### Tests (Vitest + RTL)
`ui-nyla` nutzt seit Track A1 Vitest 2.x + jsdom + `@testing-library/react`. Die Test-Dateien liegen neben den Komponenten als `*.test.tsx`: `frontend_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 | | Test | Datei | Akzeptanzkriterium |
|------|-------|--------------------| |------|-------|--------------------|

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-04-29 --> <!-- lastReviewed: 2026-04-29 -->
<!-- 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 --> <!-- 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 -->
# Agent-Tool File Bridge # Agent-Tool File Bridge
@ -56,7 +56,7 @@ flowchart LR
### `_attachFileAsChatDocument` (Single Source of Truth) ### `_attachFileAsChatDocument` (Single Source of Truth)
Datei: `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py` Datei: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_helpers.py`
```python ```python
def _attachFileAsChatDocument( def _attachFileAsChatDocument(
@ -101,7 +101,7 @@ documentList-Pfad braucht Workflow-Kontext sowieso.
### Workflow-Propagation in `runAgent` ### Workflow-Propagation in `runAgent`
Datei: `platform-core/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py` Datei: `gateway/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py`
`runAgent(workflowId=...)` setzt das Workflow-Objekt jetzt in `runAgent(workflowId=...)` setzt das Workflow-Objekt jetzt in
`self.services.workflow` UND in `_context.workflow` aller Services `self.services.workflow` UND in `_context.workflow` aller Services
@ -139,7 +139,7 @@ die einzige Luecke.
## Tolerante `documentList`-Parsing-Schicht ## Tolerante `documentList`-Parsing-Schicht
Komplementaer dazu: `coerceDocumentReferenceList` in Komplementaer dazu: `coerceDocumentReferenceList` in
`platform-core/modules/datamodels/datamodelDocref.py` parst das, was der LLM `gateway/modules/datamodels/datamodelDocref.py` parst das, was der LLM
am anderen Ende reinschickt -- typischerweise am anderen Ende reinschickt -- typischerweise
* `["docItem:<id>", "docItem:<id2>"]` (kanonisch), * `["docItem:<id>", "docItem:<id2>"]` (kanonisch),

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-22 --> <!-- lastReviewed: 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 --> <!-- 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 -->
# AI Agent & Knowledge Store # 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. 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** (`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). 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).
--- ---
@ -52,7 +52,7 @@ Pro Request propagiert der **ServiceCenterContext** u. a. `userId`, `mandateId`,
Datenfluss der Zeitzone: Datenfluss der Zeitzone:
1. **Browser**: `Intl.DateTimeFormat().resolvedOptions().timeZone` (z. B. `"Europe/Zurich"`). 1. **Browser**: `Intl.DateTimeFormat().resolvedOptions().timeZone` (z. B. `"Europe/Zurich"`).
2. **Frontend**: `ui-nyla/src/api.ts` Axios-Interceptor sendet den IANA-Namen als `X-User-Timezone`-Header. 2. **Frontend**: `frontend_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`. 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`). 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. 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) ## FeatureDataAgent: Query-Repair-Loop + Ontologie (ab 2026-05)
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: 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:
### 1. Pre-execute Validator (`queryValidator.py`) ### 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) ### 3. Eval-Harness (Phase 1.5)
`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: `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:
| Mode | Validator | Ontologie | Prompt-Block | | 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 Registry** | `aicoreModelRegistry.py` — registriert Provider-Plugins und Modelle |
| **Model Selector** | `aicoreModelSelector.py` — Auswahl nach Operationstyp, Promptgrösse, Restriktionen, Ranking | | **Model Selector** | `aicoreModelSelector.py` — Auswahl nach Operationstyp, Promptgrösse, Restriktionen, Ranking |
### Provider-Plugins (Dateien unter `platform-core/modules/aicore/`) ### Provider-Plugins (Dateien unter `gateway/modules/aicore/`)
| Plugin-Modul | Typische Rolle | | 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) ## 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 `platform-core/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 `gateway/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`? | | Trigger | Pfad | Wer ruft `runAgent`? |
|---|---|---| |---|---|---|
@ -435,34 +435,34 @@ Siehe [`b-reference/teams-bot/architecture.md`](../teams-bot/architecture.md) f
| Datei | Rolle | | Datei | Rolle |
|-------|--------| |-------|--------|
| `platform-core/modules/serviceCenter/registry.py` | Registrierung `agent`, `knowledge`, Dependencies, `objectKey` | | `gateway/modules/serviceCenter/registry.py` | Registrierung `agent`, `knowledge`, Dependencies, `objectKey` |
| `platform-core/modules/serviceCenter/services/serviceAgent/mainServiceAgent.py` | `AgentService`, `runAgent`, Prompt-Enrichment, Registry-Orchestrierung | | `gateway/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 | | `gateway/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 | | `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_workspaceTools.py` | Dateien, Ordner, Web, Übersetzung |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py` | Externe Connections, Upload, Mail | | `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_connectionTools.py` | Externe Connections, Upload, Mail |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` | DataSource Browse/Search/Download | | `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` | DataSource Browse/Search/Download |
| `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_documentTools.py` | Container, Content-Objects, Vision | | `gateway/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 | | `gateway/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) | | `gateway/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 | | `gateway/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 | | `gateway/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 | | `gateway/modules/serviceCenter/services/serviceAgent/toolRegistry.py` | Registrierung, Dispatch, `readOnly`, Function-Calling-Format |
| `platform-core/modules/serviceCenter/services/serviceAgent/conversationManager.py` | Kontextfenster, Summarization, Systemprompt | | `gateway/modules/serviceCenter/services/serviceAgent/conversationManager.py` | Kontextfenster, Summarization, Systemprompt |
| `platform-core/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` | `AgentConfig`, Events, Trace-Modelle | | `gateway/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`) | | `gateway/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) | | `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) |
| `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` | | `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` |
| `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` | Toolbox-Definitionen, `requestToolbox` Meta-Tool-Schema | | `gateway/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, ...) | | `gateway/modules/serviceCenter/services/serviceAgent/workflowTools.py` | Workflow-Editing-Tools (readWorkflowGraph, addNode, ...) |
| `platform-core/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py` | `executeCode`-Sandbox | | `gateway/modules/serviceCenter/services/serviceAgent/sandboxExecutor.py` | `executeCode`-Sandbox |
| `platform-core/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | Index, `buildAgentContext`, Workflow-/Round-Memory-Helfer | | `gateway/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` | Index, `buildAgentContext`, Workflow-/Round-Memory-Helfer |
| `platform-core/modules/interfaces/interfaceDbKnowledge.py` | DB-Zugriff Knowledge / RAG | | `gateway/modules/interfaces/interfaceDbKnowledge.py` | DB-Zugriff Knowledge / RAG |
| `platform-core/modules/datamodels/datamodelKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory, WorkflowMemory | | `gateway/modules/datamodels/datamodelKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory, WorkflowMemory |
| `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py` | Zentrales Neutralisierungs-Gate vor LLM, Billing, Provider-Aufruf | | `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py` | Zentrales Neutralisierungs-Gate vor LLM, Billing, Provider-Aufruf |
| `platform-core/modules/aicore/aicoreModelRegistry.py` | Provider-/Modell-Registry | | `gateway/modules/aicore/aicoreModelRegistry.py` | Provider-/Modell-Registry |
| `platform-core/modules/aicore/aicoreModelSelector.py` | Modellauswahl | | `gateway/modules/aicore/aicoreModelSelector.py` | Modellauswahl |
| `platform-core/modules/aicore/aicorePlugin*.py` | Provider-Implementierungen | | `gateway/modules/aicore/aicorePlugin*.py` | Provider-Implementierungen |
| `platform-core/modules/datamodels/datamodelAi.py` | `OperationTypeEnum`, `AiCallRequest`, Optionen | | `gateway/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 ## Modulstruktur
Unter `platform-core/modules/` (Kontext-Audit): Unter `gateway/modules/` (Kontext-Audit):
| Modul | Zweck | | Modul | Zweck |
|-------|-------| |-------|-------|
@ -82,26 +82,26 @@ Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap)
| Datei / Pfad | Rolle | | Datei / Pfad | Rolle |
|--------------|-------| |--------------|-------|
| `platform-core/app.py` | FastAPI-Anwendung (generischer Entry-Point), Routen, Middleware, EventManager, Scheduler-MainLoop | | `gateway/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 | | `gateway/modules/serviceCenter/__init__.py` | Service Center: `getService`, `preWarm`, RBAC-Registrierung für Service-Objekte |
| `platform-core/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request | | `gateway/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request |
| `platform-core/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) | | `gateway/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) |
| `platform-core/modules/serviceCenter/resolver.py` | Auflösung von Service-Instanzen inkl. Cache | | `gateway/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 | | `gateway/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) | | `gateway/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) | | `gateway/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) | | `gateway/modules/connectors/*.py` | Vendor-spezifische Adapter (Auth, Transport, Mapping) |
| `platform-core/modules/security/*` | RBAC-Auswertung, RBAC-Katalog, Root-Access | | `gateway/modules/security/*` | RBAC-Auswertung, RBAC-Katalog, Root-Access |
| `platform-core/modules/auth/*` | CSRF, Token-Refresh-Middleware, JWT, OAuth | | `gateway/modules/auth/*` | CSRF, Token-Refresh-Middleware, JWT, OAuth |
| `platform-core/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities | | `gateway/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
| `platform-core/modules/system/registry.py` | Feature-Discovery, Router-Laden, Katalog-Registrierung beim App-Start | | `gateway/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) | | `gateway/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 | | `gateway/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 | | `gateway/modules/workflows/scheduler/mainScheduler.py` | Konsolidierter Workflow-Scheduler |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) | | `gateway/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) |
| `platform-core/modules/interfaces/interfaceVoiceObjects.py` | Fassade Google STT/TTS, Billing-Callback Streaming | | `gateway/modules/interfaces/interfaceVoiceObjects.py` | Fassade Google STT/TTS, Billing-Callback Streaming |
| `platform-core/modules/connectors/connectorVoiceGoogle.py` | Google Speech v1 + Translation + TTS-Client | | `gateway/modules/connectors/connectorVoiceGoogle.py` | Google Speech v1 + Translation + TTS-Client |
| `platform-core/modules/routes/routeVoiceGoogle.py` | `/voice-google/*` inkl. STT-Streaming-WebSocket | | `gateway/modules/routes/routeVoiceGoogle.py` | `/voice-google/*` inkl. STT-Streaming-WebSocket |
## Google Voice (STT / TTS) ## 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 | | `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()` | | `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 | | `routeI18n.py` | `modules/routes/` | Admin-API: Sprachset-CRUD, AI-Uebersetzung, xx-Sync, TextMultilingual-Batch-Uebersetzung |
| `app.py` | `platform-core/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) | | `app.py` | `gateway/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) |
### Architektur-Regeln ### 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). 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** (`platform-core/modules/serviceCenter/.../subConnectorSync*.py`): **1. Walker schreibt strukturiert** (`gateway/modules/serviceCenter/.../subConnectorSync*.py`):
```python ```python
progressCb( progressCb(
@ -222,14 +222,14 @@ UI-seitig sind diese Endpunkte unter `/mandates/{m}/trustee/{i}/data-tables[?tab
## Typed Action Architecture (4-Schichten) ## 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 `platform-core/tests/unit/workflows/`, `platform-core/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 `gateway/tests/unit/workflows/`, `gateway/tests/integration/trustee/`.
| Schicht | Modul / Verantwortung | Type-Anker | | Schicht | Modul / Verantwortung | Type-Anker |
|---------|-----------------------|------------| |---------|-----------------------|------------|
| **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`) | | **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** | `platform-core/modules/workflows/methods/method<Feature>/actions/*.py` (`extractFromFiles`, `processDocuments`, `syncToAccounting`, ...) | Typisierte Pydantic-Eingabe + `ActionResult`-Output, `FeatureInstanceRef` als Discriminator-Envelope | | **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** | `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()`) | | **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** | `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` | | **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` |
Konsequenzen: Konsequenzen:

View file

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

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-15 --> <!-- lastReviewed: 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 --> <!-- 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 -->
# Feature: Trustee # Feature: Trustee
@ -31,10 +31,10 @@ Alle drei Actions konsumieren `featureInstanceId` als typisierten **`FeatureInst
| Modul | Pfad | Verantwortung | | Modul | Pfad | Verantwortung |
|-------|------|---------------| |-------|------|---------------|
| 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. | | 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 | `platform-core/modules/features/trustee/` | Datenmodell (`datamodelTrustee.py`), Interface (`interfaceTrustee.py`), Route-Module (`routeFeatureTrustee*.py`), `AccountingBridge` (`accountingBridge.py`). | | Feature-Domain | `gateway/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. | | 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 | `ui-nyla/src/components/Trustee/` + `TrusteeDataTablesView` | UI fuer Document/Position-Verwaltung, Daten-Tabellen, Connector-Konfiguration. | | Frontend | `frontend_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.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`). | | `trustee.queryData` | `featureInstanceId`, freie Filter-Argumente | `ActionResult` mit Query-Resultat | Read-only Zugriff fuer den AI-Agent (`dynamicMode=True`). |
> 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`). > 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`).
--- ---
@ -77,7 +77,7 @@ Seit Phase 5 ist `featureInstanceId` ueberall als **typisierter Envelope** persi
"featureCode": "trustee" } "featureCode": "trustee" }
``` ```
- **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). - **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).
- **Lesen:** `_unwrapTypedRef` (`graphUtils`) entpackt den Envelope vor dem Action-Call -- Trustee-Actions sehen weiterhin `featureInstanceId: "<uuid>"` und brauchen keinen Patch. - **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). - **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 ## AccountingBridge
`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. `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.
`trustee.refreshAccountingData` ruft `AccountingBridge.fetchSnapshots` -- die Tabellen `TrusteeDataAccount`, `TrusteeDataJournal*`, `TrusteeDataContact`, `TrusteeDataAccountBalance` werden read-only befuellt. `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) ## REST-Endpunkte (Auswahl)
Liste in `wiki/b-reference/platform-core/architecture.md` (Abschnitt "Feature: Trustee -- Daten-Tabellen-Endpunkte"); zentral: Liste in `wiki/b-reference/gateway/architecture.md` (Abschnitt "Feature: Trustee -- Daten-Tabellen-Endpunkte"); zentral:
| Endpunkt | Modell | Zweck | | Endpunkt | Modell | Zweck |
|----------|--------|-------| |----------|--------|-------|
@ -141,7 +141,7 @@ UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.featur
## Agent-Ontologie (ab 2026-05) ## Agent-Ontologie (ab 2026-05)
`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`: `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`:
| Bestandteil | Inhalt im Trustee-Pilot | | 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). **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 (`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". **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".
--- ---
@ -160,15 +160,15 @@ UI-Sichtbarkeit der Daten-Tabellen-Seite haengt am Permission-Eintrag `ui.featur
| Test | Datei | Was er beweist | | Test | Datei | Was er beweist |
|------|-------|----------------| |------|-------|----------------|
| Unit | `platform-core/tests/unit/methods/test_methodTrustee.py` (sofern vorhanden) | Action-Schemas + Pflicht-Felder. | | Unit | `gateway/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 == []`). | | Adapter-Drift | `gateway/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. | | FeatureInstanceRef | `gateway/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. | | Live-E2E | `gateway/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. | | DB-CLI | `gateway/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 RMA | `gateway/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 Bexio | `gateway/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 Abacus | `gateway/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). | | Balance Sync | `gateway/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 ## Builtin-Resolvers
Definiert in `platform-core/modules/routes/routeHelpers.py`: Definiert in `gateway/modules/routes/routeHelpers.py`:
| `fk_target.table` | Resolver-Funktion | Datenquelle | Label-Feld | | `fk_target.table` | Resolver-Funktion | Datenquelle | Label-Feld |
|---|---|---|---| |---|---|---|---|
@ -230,12 +230,12 @@ if mode == "filterValues":
| Datei | Zweck | | Datei | Zweck |
|---|---| |---|---|
| `platform-core/modules/routes/routeHelpers.py` | `_BUILTIN_FK_RESOLVERS`, `_buildLabelResolversFromModel`, `enrichRowsWithFkLabels` | | `gateway/modules/routes/routeHelpers.py` | `_BUILTIN_FK_RESOLVERS`, `_buildLabelResolversFromModel`, `enrichRowsWithFkLabels` |
| `platform-core/modules/shared/fkRegistry.py` | `validateFkTargets` (Startup-Validierung), FK-Discovery | | `gateway/modules/shared/fkRegistry.py` | `validateFkTargets` (Startup-Validierung), FK-Discovery |
| `platform-core/modules/features/trustee/routeFeatureTrustee.py` | `_buildFeatureInternalResolvers` (Referenz-Implementierung) | | `gateway/modules/features/trustee/routeFeatureTrustee.py` | `_buildFeatureInternalResolvers` (Referenz-Implementierung) |
| `platform-core/modules/features/trustee/datamodelFeatureTrustee.py` | Beispiel-Annotationen (`fk_target` auf allen Modellen) | | `gateway/modules/features/trustee/datamodelFeatureTrustee.py` | Beispiel-Annotationen (`fk_target` auf allen Modellen) |
## Siehe auch ## Siehe auch
- [FormGenerator Referenz](../ui-nyla/formgenerator.md) — Frontend-Darstellung der aufgeloesten Labels - [FormGenerator Referenz](../frontend-nyla/formgenerator.md) — Frontend-Darstellung der aufgeloesten Labels
- [Gateway Architektur](architecture.md) — Modulstruktur und routeHelpers - [Gateway Architektur](architecture.md) — Modulstruktur und routeHelpers

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-10 --> <!-- lastReviewed: 2026-05-10 -->
<!-- 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 --> <!-- 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 -->
# Google Voice (STT / TTS) # Google Voice (STT / TTS)

View file

@ -22,7 +22,7 @@ Die Workflow-Engine im Gateway orchestriert KI-gestützte Aufgabenpläne und die
## WorkflowManager ## WorkflowManager
Zentrale Steuerung in `platform-core/modules/workflows/workflowManager.py` (grosse Datei; Einstieg für Start/Stopp und Hauptloop). Zentrale Steuerung in `gateway/modules/workflows/workflowManager.py` (grosse Datei; Einstieg für Start/Stopp und Hauptloop).
**Öffentliche / zentrale Verantwortlichkeiten (Konzept):** **Öffentliche / zentrale Verantwortlichkeiten (Konzept):**
@ -45,7 +45,7 @@ Zusätzlich definiert `WorkflowModeEnum` den Modus **`WORKFLOW_CHATBOT`** (Chatb
## Methoden ## Methoden
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. 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.
| Method (`self.name`) | Actions (Registry-Keys) | | 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 ### Action-Signaturen + Catalog
- `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`). - `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`).
- `FeatureInstanceRef` (`{$type, id, featureCode}`) ist der **Discriminator-Envelope** fuer feature-instance-Parameter -- ersetzt rohe UUID-Strings, behaelt Backwards-Compat durch Auto-Unwrap im Runtime. - `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. - `/api/automation2/catalog` exportiert die normalisierten Signaturen; Editor + AI-Agent + Adapter konsumieren genau diesen Stream.
### Adapter-Layer (`registerNodeWithMethod`) ### Adapter-Layer (`registerNodeWithMethod`)
- `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). - `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 `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()`). - 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()`).
- 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. - 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 ### Runtime (`executeGraph`) -- Pick-not-Push + Materialisierung
- `platform-core/modules/workflows/automation2/executionEngine.py::executeGraph` ruft beim Start zwei Migrations-Helper: - `gateway/modules/workflows/automation2/executionEngine.py::executeGraph` ruft beim Start zwei Migrations-Helper:
- `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) -- wandelt rohe `featureInstanceId: "<uuid>"` in `FeatureInstanceRef`-Envelope. - `materializeFeatureInstanceRefs` (`automation2/featureInstanceRefMigration.py`) -- wandelt rohe `featureInstanceId: "<uuid>"` in `FeatureInstanceRef`-Envelope.
- `materializeConnectionRefs` (`automation2/pickNotPushMigration.py`) -- resolviert leere `connectionReference` aus Upstream-DataRefs. - `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`). - `resolveParameterReferences` / `_unwrapTypedRef` (`graphUtils`) entpacken Envelopes vor dem Action-Call -- Legacy-Aktionen sehen weiterhin den nackten Wert (`id`).
- 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). - 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).
### Bindings-Resolver mit `*`-Wildcard ### Bindings-Resolver mit `*`-Wildcard
@ -117,7 +117,7 @@ Seit April 2026 ist jede Action typisiert; Editor, Adapter und Runtime lesen die
## Schlüssel-Dateien ## Schlüssel-Dateien
| Pfad (unter `platform-core/modules/`) | Rolle | | Pfad (unter `gateway/modules/`) | Rolle |
|--------------------------------|--------| |--------------------------------|--------|
| `workflows/workflowManager.py` | Workflow-Orchestrierung fuer Workspace/Chat (Einstieg) | | `workflows/workflowManager.py` | Workflow-Orchestrierung fuer Workspace/Chat (Einstieg) |
| `workflows/processing/` | Processor, Modi (`modeDynamic`, `modeAutomation`), `ActionExecutor` | | `workflows/processing/` | Processor, Modi (`modeDynamic`, `modeAutomation`), `ActionExecutor` |

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-28 --> <!-- lastReviewed: 2026-04-26 -->
<!-- verifiedAgainst: platform-core+ui-nyla (streaming migration update 2026-05-28) --> <!-- verifiedAgainst: gateway+frontend-nyla (codebase audit 2026-04-26) -->
# Datenbank-Architektur # Datenbank-Architektur
@ -319,22 +319,10 @@ mandateId: str = Field(
Alle Endpunkte: SysAdmin-only via `requireSysAdminRole`. 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`) ### Frontend (`AdminDatabaseHealthPage.tsx`)
- Tab "Statistiken": Sortierbare Tabelle mit DB-Filter und Summary-Leiste - 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 "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)
--- ---
@ -342,21 +330,20 @@ Alle Endpunkte: SysAdmin-only via `requireSysAdminRole`.
| Thema | Pfad | | Thema | Pfad |
|-------|------| |-------|------|
| PostgreSQL Connector | `platform-core/modules/connectors/connectorDbPostgre.py` | | PostgreSQL Connector | `gateway/modules/connectors/connectorDbPostgre.py` |
| DB-Registry | `platform-core/modules/shared/dbRegistry.py` | | DB-Registry | `gateway/modules/shared/dbRegistry.py` |
| FK-Registry | `platform-core/modules/shared/fkRegistry.py` | | FK-Registry | `gateway/modules/shared/fkRegistry.py` |
| Database Health | `platform-core/modules/system/databaseHealth.py` | | Database Health | `gateway/modules/system/databaseHealth.py` |
| Health API Route | `platform-core/modules/routes/routeAdminDatabaseHealth.py` | | Health API Route | `gateway/modules/routes/routeAdminDatabaseHealth.py` |
| App-DB Interface | `platform-core/modules/interfaces/interfaceDbApp.py` | | App-DB Interface | `gateway/modules/interfaces/interfaceDbApp.py` |
| Chat-DB Interface | `platform-core/modules/interfaces/interfaceDbChat.py` | | Chat-DB Interface | `gateway/modules/interfaces/interfaceDbChat.py` |
| Management-DB Interface | `platform-core/modules/interfaces/interfaceDbManagement.py` | | Management-DB Interface | `gateway/modules/interfaces/interfaceDbManagement.py` |
| Knowledge-DB Interface | `platform-core/modules/interfaces/interfaceDbKnowledge.py` | | Knowledge-DB Interface | `gateway/modules/interfaces/interfaceDbKnowledge.py` |
| Billing-DB Interface | `platform-core/modules/interfaces/interfaceDbBilling.py` | | Billing-DB Interface | `gateway/modules/interfaces/interfaceDbBilling.py` |
| Subscription Interface | `platform-core/modules/interfaces/interfaceDbSubscription.py` | | Subscription Interface | `gateway/modules/interfaces/interfaceDbSubscription.py` |
| RBAC in DB-Schicht | `platform-core/modules/interfaces/interfaceRbac.py` | | RBAC in DB-Schicht | `gateway/modules/interfaces/interfaceRbac.py` |
| Feature-Interface (Template) | `platform-core/modules/interfaces/interfaceFeatures.py` | | Feature-Interface (Template) | `gateway/modules/interfaces/interfaceFeatures.py` |
| Bootstrap / DB-Seed | `platform-core/modules/interfaces/interfaceBootstrap.py` | | Bootstrap / DB-Seed | `gateway/modules/interfaces/interfaceBootstrap.py` |
| DB-Migration (Streaming) | `platform-core/modules/system/databaseMigration.py` | | DB-Migration Script | `gateway/scripts/script_db_export_migration.py` |
| DB-Migration Script | `platform-core/scripts/script_db_export_migration.py` | | Datenmodelle (Pydantic) | `gateway/modules/datamodels/` |
| Datenmodelle (Pydantic) | `platform-core/modules/datamodels/` | | Frontend Health Page | `frontend_nyla/src/pages/admin/AdminDatabaseHealthPage.tsx` |
| Frontend Health Page | `ui-nyla/src/pages/admin/AdminDatabaseHealthPage.tsx` |

View file

@ -62,14 +62,6 @@ 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) | | `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) #### Projekt: Service-Teamsbot (PCP-KO2UYXT)
| Instanzname | Env | Komponente | Flavor | Floating IP | DNS | | Instanzname | Env | Komponente | Flavor | Floating IP | DNS |

View file

@ -1,6 +1,6 @@
<!-- status: canonical --> <!-- status: canonical -->
<!-- lastReviewed: 2026-04-18 --> <!-- lastReviewed: 2026-04-18 -->
<!-- verifiedAgainst: gateway + ui-nyla (codebase audit 2026-04-18) --> <!-- verifiedAgainst: gateway + frontend_nyla (codebase audit 2026-04-18) -->
# Mandate-Identifier: `name` (Kurzzeichen) und `label` (Voller Name) # Mandate-Identifier: `name` (Kurzzeichen) und `label` (Voller Name)
@ -56,7 +56,7 @@ Beispiele:
| `Müller AG` (zweites Mal) | `mueller-ag-2` | | `Müller AG` (zweites Mal) | `mueller-ag-2` |
| ` ` (leer) | `mn` (Fallback) | | ` ` (leer) | `mn` (Fallback) |
Code: `platform-core/modules/shared/mandateNameUtils.py` (Backend) und `ui-nyla/src/utils/slugUtils.ts` + `mandateNameUtils.ts` (Frontend, mirror). Code: `gateway/modules/shared/mandateNameUtils.py` (Backend) und `frontend_nyla/src/utils/slugUtils.ts` + `mandateNameUtils.ts` (Frontend, mirror).
## RBAC und Editierbarkeit ## 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. 3. Stable order ueber `id`-String, deterministisch.
4. Zweiter Lauf ist No-op. 4. Zweiter Lauf ist No-op.
Tests: `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`. Tests: `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`.
## UI-Anzeige (Konvention) ## UI-Anzeige (Konvention)
@ -90,7 +90,7 @@ Tests: `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`.
## Verwandte Dateien ## Verwandte Dateien
- 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`. - 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: `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). - 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: `platform-core/tests/unit/shared/test_mandateNameUtils.py`, `platform-core/tests/unit/bootstrap/test_mandateNameMigration.py`, `platform-core/tests/integration/mandates/`. - Tests: `gateway/tests/unit/shared/test_mandateNameUtils.py`, `gateway/tests/unit/bootstrap/test_mandateNameMigration.py`, `gateway/tests/integration/mandates/`.
- Plan-Doku: `wiki/c-work/1-plan/2026-04-mandate-name-label-logic.md`. - 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`. **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` (`ui-nyla`). Aktuelle UI-Bezüge im Kontext: `MandateNavigation`, Hook `useNavigation` (`frontend_nyla`).
## Block-Struktur ## 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` | | 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` | | Admin-Feature-Permission (Ist teils feature-spezifisch) | `routeAdminFeatures.py` — z. B. `_deriveViewPermissions` |
| Frontend: Navigation | `MandateNavigation.tsx`, `useNavigation` | | Frontend: Navigation | `MandateNavigation.tsx`, `useNavigation` |
| Frontend: Registry | `ui-nyla/src/config/pageRegistry.tsx` — `PAGE_REGISTRY`, `FEATURE_REGISTRY` | | Frontend: Registry | `frontend_nyla/src/config/pageRegistry.tsx` — `PAGE_REGISTRY`, `FEATURE_REGISTRY` |
| Legacy-Duplikate (Audit) | `mandate.ts``FEATURE_REGISTRY` / View-Definitionen parallel zum Backend | | Legacy-Duplikate (Audit) | `mandate.ts``FEATURE_REGISTRY` / View-Definitionen parallel zum Backend |
## Regeln / Invarianten ## Regeln / Invarianten

View file

@ -68,7 +68,7 @@ Vollstaendige Doku: `b-reference/platform/unified-data-bar.md`. Hier nur Bezug z
## NeutralizationPanel (Frontend) ## NeutralizationPanel (Frontend)
`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: [...] }`. `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: [...] }`.
## Schlüssel-Dateien ## Schlüssel-Dateien

View file

@ -422,11 +422,11 @@ graph TB
end end
subgraph "Integration Points" subgraph "Integration Points"
WF_DIR[platform-core/modules/workflows/methods/] WF_DIR[gateway/modules/workflows/methods/]
SVC_DIR[platform-core/modules/serviceCenter/services/] SVC_DIR[gateway/modules/serviceCenter/services/]
CONN_DIR[platform-core/modules/connectors/] CONN_DIR[gateway/modules/connectors/]
ROUTE_DIR[platform-core/modules/routes/] ROUTE_DIR[gateway/modules/routes/]
FEAT_DIR[platform-core/modules/features/] FEAT_DIR[gateway/modules/features/]
end end
subgraph "Development Workflow" 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-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: `platform-core/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: `gateway/modules/shared/frontendTypes.py`.
--- ---
@ -341,14 +341,14 @@ Felder `id` und Namen mit fuehrendem `_` (z.B. `_createdBy`, `_createdAt`) sind
| Thema | Pfad | | Thema | Pfad |
|-------|------| |-------|------|
| RBAC-Auswertung, SQL-Integration | `platform-core/modules/interfaces/interfaceRbac.py` | | RBAC-Auswertung, SQL-Integration | `gateway/modules/interfaces/interfaceRbac.py` |
| AccessRule/Permission-Modelle | `platform-core/modules/datamodels/datamodelRbac.py` | | AccessRule/Permission-Modelle | `gateway/modules/datamodels/datamodelRbac.py` |
| Membership-Modelle | `platform-core/modules/datamodels/datamodelMembership.py` | | Membership-Modelle | `gateway/modules/datamodels/datamodelMembership.py` |
| Bootstrap (System Templates, Copy) | `platform-core/modules/interfaces/interfaceBootstrap.py` | | Bootstrap (System Templates, Copy) | `gateway/modules/interfaces/interfaceBootstrap.py` |
| Feature-Template-Copy | `platform-core/modules/interfaces/interfaceFeatures.py` | | Feature-Template-Copy | `gateway/modules/interfaces/interfaceFeatures.py` |
| Feature-Registrierung | `platform-core/modules/system/registry.py` | | Feature-Registrierung | `gateway/modules/system/registry.py` |
| RBAC-Rule-Resolution | `platform-core/modules/security/rbac.py` | | RBAC-Rule-Resolution | `gateway/modules/security/rbac.py` |
| TEMPLATE_ROLES (Beispiel) | `platform-core/modules/features/workspace/mainWorkspace.py` | | TEMPLATE_ROLES (Beispiel) | `gateway/modules/features/workspace/mainWorkspace.py` |
## Feature-Admin-Gate fuer UDB-Flag-Edits ## Feature-Admin-Gate fuer UDB-Flag-Edits

View file

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

View file

@ -0,0 +1,66 @@
<!-- status: canonical -->
<!-- lastReviewed: 2026-04-05 -->
<!-- verifiedAgainst: private-llm (codebase review 2026-04-05) -->
# 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.
## Technologie-Stack
| Layer | Technologie |
|-------|------------|
| Framework | FastAPI (Python) |
| AI Runtime | Ollama (lokale Vision/Text-Modelle) |
| PDF-Support | PyMuPDF (fitz) |
| Hosting | Infomaniak Swiss Cloud (GPU) |
| Deployment | GitHub 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 |
## API-Routen
| Modul | Zweck |
|-------|-------|
| `routeApi.py` | Analyse-API: Bild-/PDF-Analyse mit Prompt, Modellauswahl |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-Completion-API (für Cursor-Integration) |
| `routeWeb.py` | Web-UI für manuelle Tests |
## Integration mit Gateway
Der Gateway nutzt das Private LLM über `aicorePluginPrivateLlm.py` als Provider für:
- **Neutralisierung:** Text-Analyse mit `poweron-text-general`
- **Sensitive Datenverarbeitung:** Vision-Analyse von Dokumenten (Rechnungen, Belege, Handschrift)
- **Keine Billing-Kosten** für mandanteninterne LLM-Calls (eigene Infrastruktur)
## Sicherheit
- API-Key-Authentifizierung (`X-API-Key` Header)
- Separater Cursor-API-Key für OpenAI-kompatible Endpoints (Bearer Token)
- Rate-Limiting per API-Key (Token Bucket, konfigurierbar)
- Konfiguration über `config.ini` + Environment-Variablen (Secrets nie im Code)
## Schlüssel-Dateien
| Datei | Rolle |
|-------|-------|
| `app.py` | FastAPI-Einstieg, Router-Mount |
| `config.py` | Konfiguration, Model-Mapping, Auth, Rate-Limiting, Request/Response-Modelle |
| `routeApi.py` | Analyse-Endpunkte (Bild, PDF) |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-API |
| `routeWeb.py` | Test-UI |
## Regeln / Invarianten
- Alle Daten werden **lokal** verarbeitet -- kein Weiterleiten an externe APIs
- 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)

View file

@ -14,7 +14,6 @@ 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 | | 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 | | 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 | | 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 | | Teams Bot | service-teams-browser-bot | TypeScript/Node.js | Bot für Teams-Meeting-Teilnahme |
| Wiki | wiki | Markdown | Dokumentation (dieses Repo) | | Wiki | wiki | Markdown | Dokumentation (dieses Repo) |

View file

@ -1,140 +0,0 @@
<!-- status: canonical -->
<!-- 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 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/Reasoning-Modelle) |
| PDF-Support | PyMuPDF (fitz) |
| Hosting | Aktuell: Infomaniak (GPU L4, 24 GB) / Geplant: FireStorm (RTX PRO 6000, 96 GB) |
| Deployment | Forgejo Actions → `main` Branch |
## Modelle
### 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
| Modul | Zweck |
|-------|-------|
| `routeApi.py` | Analyse-API: Bild-/PDF-Analyse mit Prompt, Modellauswahl |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-Completion-API (für Cursor-Integration) |
| `routeWeb.py` | Web-UI für manuelle Tests |
## Integration mit Gateway
Der Gateway nutzt das Private LLM über `aicorePluginPrivateLlm.py` als Provider für:
- **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
- API-Key-Authentifizierung (`X-API-Key` Header)
- Separater Cursor-API-Key für OpenAI-kompatible Endpoints (Bearer Token)
- Rate-Limiting per API-Key (Token Bucket, konfigurierbar)
- Konfiguration über `config.ini` + Environment-Variablen (Secrets nie im Code)
## Schlüssel-Dateien
| Datei | Rolle |
|-------|-------|
| `app.py` | FastAPI-Einstieg, Router-Mount |
| `config.py` | Konfiguration, Model-Mapping, Auth, Rate-Limiting, Request/Response-Modelle |
| `routeApi.py` | Analyse-Endpunkte (Bild, PDF) |
| `routeOpenAi.py` | OpenAI-kompatibles Chat-API |
| `routeWeb.py` | Test-UI |
## Regeln / Invarianten
- Alle Daten werden **lokal** verarbeitet -- kein Weiterleiten an externe APIs
- 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 --> <!-- status: canonical -->
<!-- lastReviewed: 2026-05-12 --> <!-- 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); 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) --> <!-- 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) -->
# Teams Meeting Bot -- Architektur # Teams Meeting Bot -- Architektur
@ -70,9 +70,9 @@ Der Gateway (Feature `teamsbot`) verwaltet Sessions und stellt die AI-Pipeline b
| Datei / Bereich | Rolle | | Datei / Bereich | Rolle |
|-----------------|-------| |-----------------|-------|
| `platform-core/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul (inkl. `dashboard/stream`, Session-SSE, Module-CRUD) | | `gateway/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 | | `frontend_nyla/src/pages/views/teamsbot/` | Dashboard (SSE), Assistent, Module, Live-Session, Einstellungen |
| `ui-nyla/src/api/teamsbotApi.ts` | u.a. `createDashboardStream`, `createSessionStream`, Module-API | | `frontend_nyla/src/api/teamsbotApi.ts` | u.a. `createDashboardStream`, `createSessionStream`, Module-API |
| `service-teams-browser-bot/` | Eigenständiger Bot-Service (separates Repository) | | `service-teams-browser-bot/` | Eigenständiger Bot-Service (separates Repository) |
## Regeln / Invarianten ## 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 - 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 - 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](../platform-core/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](../gateway/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. **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`) | | Persistenz + Lifecycle | `interfaceFeatureTeamsbot.py` (`createDirectorPrompt`, `getActivePersistentPrompts`, `updateDirectorPrompt`, `deleteDirectorPrompt`) |
| Orchestrierung + Agent-Lauf + SSE | `service.py` (`submitDirectorPrompt`, `_processDirectorPrompt`, `_runAgentForMeeting`, `_buildPersistentDirectorContext`, `removePersistentPrompt`) | | Orchestrierung + Agent-Lauf + SSE | `service.py` (`submitDirectorPrompt`, `_processDirectorPrompt`, `_runAgentForMeeting`, `_buildPersistentDirectorContext`, `removePersistentPrompt`) |
| HTTP + RBAC + Limits | `routeFeatureTeamsbot.py` (POST/GET/DELETE `/sessions/{id}/directorPrompts`) | | HTTP + RBAC + Limits | `routeFeatureTeamsbot.py` (POST/GET/DELETE `/sessions/{id}/directorPrompts`) |
| Frontend Regie-Panel + UDB-Sidebar + SSE-Listener | `ui-nyla/src/pages/views/teamsbot/TeamsbotSessionView.tsx` + `Teamsbot.module.css` | | Frontend Regie-Panel + UDB-Sidebar + SSE-Listener | `frontend_nyla/src/pages/views/teamsbot/TeamsbotSessionView.tsx` + `Teamsbot.module.css` |
| Frontend API-Wrapper | `ui-nyla/src/api/teamsbotApi.ts` (`submitDirectorPrompt`, `listDirectorPrompts`, `deleteDirectorPrompt`) | | Frontend API-Wrapper | `frontend_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) | | Tests | `gateway/tests/unit/teamsbot/test_directorPrompts.py` (26 Tests, AC 5 + 6 abgedeckt; AC 14 manuell live) |

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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | platform-core/tests/test_google_connector.py | pending | | T1 | 1 | integration | ja | gateway/tests/test_google_connector.py | pending |
| T2 | 2 | unit | ja | platform-core/tests/test_google_connector.py | pending | | T2 | 2 | unit | ja | gateway/tests/test_google_connector.py | pending |
| T3 | 3 | api | ja | platform-core/tests/test_search_images_action.py | pending | | T3 | 3 | api | ja | gateway/tests/test_search_images_action.py | pending |
## Links ## Links
- Google Custom Search API: https://developers.google.com/custom-search/v1/overview - Google Custom Search API: https://developers.google.com/custom-search/v1/overview
- Bestehender Tavily Connector: `platform-core/modules/aicore/aicorePluginTavily.py` - Bestehender Tavily Connector: `gateway/modules/aicore/aicorePluginTavily.py`
## Abschluss ## Abschluss
- [ ] b-reference/platform-core/ai-agent.md aktualisiert (neuer OperationType) - [ ] b-reference/gateway/ai-agent.md aktualisiert (neuer OperationType)
- [ ] TOPICS.md aktualisiert (falls neues Thema) - [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben - [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -1,6 +1,6 @@
<!-- status: plan --> <!-- status: plan -->
<!-- started: 2026-04-16 --> <!-- started: 2026-04-16 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-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 --> <!-- 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 # 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` - 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` - 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` - UI-Enhancements Plan (ersetzt): `c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md`
- Investor-Demo (Referenz): `platform-core/modules/demoConfigs/investorDemo2026.py` - Investor-Demo (Referenz): `gateway/modules/demoConfigs/investorDemo2026.py`
- Frontend-Referenz: `b-reference/ui-nyla/architecture.md` - Frontend-Referenz: `b-reference/frontend-nyla/architecture.md`
- Trustee Main (Prompts): `platform-core/modules/features/trustee/mainTrustee.py` - Trustee Main (Prompts): `gateway/modules/features/trustee/mainTrustee.py`
- CommCoach Personas: `platform-core/modules/features/commcoach/serviceCommcoachPersonas.py` - CommCoach Personas: `gateway/modules/features/commcoach/serviceCommcoachPersonas.py`
- Neutralisierung: `platform-core/modules/features/neutralization/` - Neutralisierung: `gateway/modules/features/neutralization/`
- Graph-Editor Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/` - Graph-Editor Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/`
- Demo-Daten: `platform-core/demoData/` - Demo-Daten: `gateway/demoData/`
- UDM-Konzept: `c-work/0-ideas/unified-document-model.md` - UDM-Konzept: `c-work/0-ideas/unified-document-model.md`
## Abschluss ## Abschluss

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: validate --> <!-- status: validate -->
<!-- started: 2026-05-18 --> <!-- started: 2026-05-18 -->
<!-- component: ui-nyla | gateway --> <!-- component: frontend-nyla | gateway -->
# UDB Sources Recovery: einheitliche Tree-Mechanik via FormGeneratorTree # UDB Sources Recovery: einheitliche Tree-Mechanik via FormGeneratorTree
@ -159,7 +159,7 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
## Betroffene Module ## Betroffene Module
- **Gateway**: - **Gateway**:
- `platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`: - `gateway/modules/serviceCenter/services/serviceKnowledge/_buildTree.py`:
`_topLevel` umbauen, sodass es **eine** synthetische Wurzel `srcRoot` mit `_topLevel` umbauen, sodass es **eine** synthetische Wurzel `srcRoot` mit
zwei Sub-Knoten zurueckliefert (`personalRoot`, `mandateRoot`); Connections zwei Sub-Knoten zurueckliefert (`personalRoot`, `mandateRoot`); Connections
werden Children von `personalRoot`, Mandate-Groups Children von `mandateRoot`. 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- - Optional: `getChildrenForParents` so erweitern, dass die drei neuen Synthese-
Keys gehandhabt werden (Dispatch). Keys gehandhabt werden (Dispatch).
- **Frontend**: - **Frontend**:
- `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx`: - `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`:
komplett ersetzen (~555 LOC -> erwartet ~80-120 LOC), nur noch ein duenner komplett ersetzen (~555 LOC -> erwartet ~80-120 LOC), nur noch ein duenner
Wrapper um `FormGeneratorTree` mit eigenem Provider und Settings-Modal-Ankopplung. Wrapper um `FormGeneratorTree` mit eigenem Provider und Settings-Modal-Ankopplung.
- `ui-nyla/src/components/FormGenerator/FormGeneratorTree/types.ts`: - `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/types.ts`:
Optional, je nach gewaehltem Approach (siehe Entscheidung E1): Optional, je nach gewaehltem Approach (siehe Entscheidung E1):
- Variante A: `TreeNode.ragIndexEnabled?: boolean | 'mixed'` als drittes - Variante A: `TreeNode.ragIndexEnabled?: boolean | 'mixed'` als drittes
First-Class-Feld + Provider-Methode `patchRagIndex?(ids, value)`. First-Class-Feld + Provider-Methode `patchRagIndex?(ids, value)`.
- Variante B: RAG ueber `extraActions[]` mit `value: 'mixed'|true|false` -- - Variante B: RAG ueber `extraActions[]` mit `value: 'mixed'|true|false` --
schon heute unterstuetzt, Tree braucht nichts neues. schon heute unterstuetzt, Tree braucht nichts neues.
- `ui-nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`: - `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`:
eine generische Prop `refreshAfterAction?: boolean` (Default: `false`, eine generische Prop `refreshAfterAction?: boolean` (Default: `false`,
backward-compatible), und ein generischer Refresh-Hook der nach backward-compatible), und ein generischer Refresh-Hook der nach
`_handleCycleScope`/`_handleToggleNeutralize`/`_handleExtraAction` (NUR `_handleCycleScope`/`_handleToggleNeutralize`/`_handleExtraAction` (NUR
wenn aktiviert) `provider.loadChildren(...)` fuer **alle expandierten wenn aktiviert) `provider.loadChildren(...)` fuer **alle expandierten
Parents + `null`** aufruft und die Nodes ersetzt. Ohne UDB-Vokabular. Parents + `null`** aufruft und die Nodes ersetzt. Ohne UDB-Vokabular.
- Neuer Datei `ui-nyla/src/components/UnifiedDataBar/UdbSourcesProvider.ts`: - Neuer Datei `frontend_nyla/src/components/UnifiedDataBar/UdbSourcesProvider.ts`:
`TreeNodeProvider`-Implementierung, die `POST /tree/children` aufruft und `TreeNodeProvider`-Implementierung, die `POST /tree/children` aufruft und
Backend-`TreeNode` auf den generischen `FormGeneratorTree.TreeNode` mappt. Backend-`TreeNode` auf den generischen `FormGeneratorTree.TreeNode` mappt.
- **DB-Migration**: nein. - **DB-Migration**: nein.
@ -348,15 +348,15 @@ Drift zwischen den beiden Tree-Renderern, wachsende Test-Luecke.
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1, 8 | unit | ja | `platform-core/tests/unit/services/test_buildTree.py::TestSyntheticRoots` | DONE -- 7/7 | | T1 | 1, 8 | unit | ja | `gateway/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 | | T2 | 8 | unit | ja | `gateway/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 | | T3 | 8 | unit | ja | `gateway/tests/unit/services/test_inheritFlags.py` (regress.) | DONE -- 72/72 |
| T4 | 2, 3 | unit | ja | `FormGeneratorTree.test.tsx::refreshAfterAction` | DONE -- 2/2 | | 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 | | 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 | | 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 | | 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 | | 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 ui-nyla && npx tsc --noEmit --skipLibCheck && npm run build` | OPEN | | T9 | 9 | build | ja | `cd frontend_nyla && npx tsc --noEmit --skipLibCheck && npm run build` | OPEN |
## Links ## 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-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` - 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` - Settings-Modal-Plan: `wiki/c-work/4-done/2026-05-udb-datasource-settings.md`
- Backend-Helpers (nicht antasten): `platform-core/modules/serviceCenter/services/serviceKnowledge/_inheritFlags.py`, `_buildTree.py` - Backend-Helpers (nicht antasten): `gateway/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` - Backend-Routes (nicht antasten): `gateway/modules/routes/routeDataSources.py`, `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- Tree-Komponente: `ui-nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx` - Tree-Komponente: `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx`
- Referenz-Implementierung (nicht antasten): `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx` - Referenz-Implementierung (nicht antasten): `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- Wegzuwerfender Code: `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` - Wegzuwerfender Code: `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- PR: noch nicht erstellt. - PR: noch nicht erstellt.
## Abschluss ## Abschluss
- [ ] `b-reference/ui-nyla/formgenerator.md` aktualisieren: Abschnitt - [ ] `b-reference/frontend-nyla/formgenerator.md` aktualisieren: Abschnitt
"FormGeneratorTree" um die neuen Props (`refreshAfterAction`, "FormGeneratorTree" um die neuen Props (`refreshAfterAction`,
`node.ragIndexEnabled`, `provider.patchRagIndex`) ergaenzen. `node.ragIndexEnabled`, `provider.patchRagIndex`) ergaenzen.
- [ ] `b-reference/ui-nyla/architecture.md` aktualisieren: UDB-Abschnitt - [ ] `b-reference/frontend-nyla/architecture.md` aktualisieren: UDB-Abschnitt
so umschreiben, dass SourcesTab als duenner Wrapper um FormGeneratorTree so umschreiben, dass SourcesTab als duenner Wrapper um FormGeneratorTree
beschrieben ist; Files-Tab bleibt unveraendert beschrieben. beschrieben ist; Files-Tab bleibt unveraendert beschrieben.
- [ ] `b-reference/platform/neutralization.md` Querschnitt pruefen - [ ] `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 | | Datei | Beschreibung |
|---|---| |---|---|
| `platform-core/modules/features/codeeditor/__init__.py` | Package init | | `gateway/modules/features/codeeditor/__init__.py` | Package init |
| `platform-core/modules/features/codeeditor/datamodelCodeeditor.py` | Pydantic Models: FileContext, ResponseSegment, FileEditProposal, FileVersion, MIME-Type Validierung | | `gateway/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) | | `gateway/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 | | `gateway/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 | | `gateway/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) | | `gateway/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 | | `gateway/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 | | `gateway/modules/features/codeeditor/routeFeatureCodeeditor.py` | 8 FastAPI Endpoints inkl. SSE Stream |
### Frontend (Nyla UI) ### Frontend (Nyla UI)
| Datei | Beschreibung | | Datei | Beschreibung |
|---|---| |---|---|
| `ui-nyla/src/pages/views/codeeditor/CodeEditorPage.tsx` | Drei-Panel-Layout mit resizable Panels | | `frontend_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 | | `frontend_nyla/src/pages/views/codeeditor/FileListPanel.tsx` | Datei-Auswahl mit Checkboxen |
| `ui-nyla/src/pages/views/codeeditor/DiffPreviewPanel.tsx` | Diff-Anzeige mit Accept/Reject | | `frontend_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 | | `frontend_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 | | `frontend_nyla/src/pages/views/codeeditor/CodeEditor.module.css` | Styling |
| `ui-nyla/src/pages/views/codeeditor/index.ts` | Export | | `frontend_nyla/src/pages/views/codeeditor/index.ts` | Export |
## Geaenderte Dateien ## Geaenderte Dateien
| Datei | Aenderung | | Datei | Aenderung |
|---|---| |---|---|
| `platform-core/modules/datamodels/datamodelChat.py` | `WORKFLOW_CODEEDITOR = "CodeEditor"` zu `WorkflowModeEnum` hinzugefuegt | | `gateway/modules/datamodels/datamodelChat.py` | `WORKFLOW_CODEEDITOR = "CodeEditor"` zu `WorkflowModeEnum` hinzugefuegt |
| `platform-core/modules/routes/routeSystem.py` | `codeeditor` in `_getFeatureUiObjects()` fuer Navigation API | | `gateway/modules/routes/routeSystem.py` | `codeeditor` in `_getFeatureUiObjects()` fuer Navigation API |
| `platform-core/modules/system/mainSystem.py` | Store-Resource `resource.store.codeeditor` | | `gateway/modules/system/mainSystem.py` | Store-Resource `resource.store.codeeditor` |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | `resource.store.codeeditor` in `storeResources` | | `gateway/modules/interfaces/interfaceBootstrap.py` | `resource.store.codeeditor` in `storeResources` |
| `ui-nyla/src/pages/FeatureView.tsx` | Import + `codeeditor` in `VIEW_COMPONENTS` Registry | | `frontend_nyla/src/pages/FeatureView.tsx` | Import + `codeeditor` in `VIEW_COMPONENTS` Registry |
| `ui-nyla/src/config/pageRegistry.tsx` | `feature.codeeditor` Icon (FaFileAlt) | | `frontend_nyla/src/config/pageRegistry.tsx` | `feature.codeeditor` Icon (FaFileAlt) |
| `ui-nyla/src/types/mandate.ts` | `codeeditor` in `FEATURE_REGISTRY` mit Views | | `frontend_nyla/src/types/mandate.ts` | `codeeditor` in `FEATURE_REGISTRY` mit Views |
| `ui-nyla/src/pages/Store.tsx` | Icon + Beschreibung fuer Feature Store | | `frontend_nyla/src/pages/Store.tsx` | Icon + Beschreibung fuer Feature Store |
| `ui-nyla/src/App.tsx` | Route `editor` fuer CodeEditorPage | | `frontend_nyla/src/App.tsx` | Route `editor` fuer CodeEditorPage |
## API Endpoints ## API Endpoints

View file

@ -96,7 +96,7 @@ Fuer das Backend bauen wir denselben Mechanismus. Der Kontext wird automatisch a
### Neues Modul: `i18nRegistry.py` ### Neues Modul: `i18nRegistry.py`
```python ```python
# platform-core/modules/shared/i18nRegistry.py # gateway/modules/shared/i18nRegistry.py
_REGISTRY: Dict[str, I18nRegistryEntry] = {} # key -> {context, value} _REGISTRY: Dict[str, I18nRegistryEntry] = {} # key -> {context, value}
_CACHE: Dict[str, Dict[str, str]] = {} # lang -> {key -> translation} _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 - [x] Nach jedem Batch: Gateway starten und pruefen
### Phase 3: HTTPException-Texte umstellen (~21 Dateien, ~150 Stellen) -- Cursor: **Auto / Fast** ### 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: `platform-core/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: `gateway/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] Alle UI-sichtbaren `HTTPException(detail="...")` in `modules/**/route*.py` auf `routeApiMsg(...)` umgestellt
- [x] Interne/technische Fehlermeldungen (`detail=str(e)`, `detail=f"...{e}..."`) unveraendert gelassen - [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`: 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 HTTPException-Texte mit routeApiMsg()
- [x] `d-guides/coding-conventions.md`: Regel fuer neue Pydantic-Models (@i18nModel Pflicht) - [x] `d-guides/coding-conventions.md`: Regel fuer neue Pydantic-Models (@i18nModel Pflicht)
- [x] `b-reference/platform-core/architecture.md`: i18n-Architektur dokumentiert (i18nRegistry, Boot-Sync, Cache, Context-Namensraeume, Entry-Identitaet) - [x] `b-reference/gateway/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] `b-reference/frontend-nyla/architecture.md`: TextMultilingual dynamisch + AdminLanguagesKeepAlive dokumentiert
- [x] `TOPICS.md`: Thema "i18n / Mehrsprachigkeit" hinzugefuegt (Cross-Cutting + Aktive Arbeiten) - [x] `TOPICS.md`: Thema "i18n / Mehrsprachigkeit" hinzugefuegt (Cross-Cutting + Aktive Arbeiten)
### Abschluss ### Abschluss
@ -434,12 +434,12 @@ in alle **anderen** Sprachfelder uebernimmt — dieselbe Logik wie die Admin-Spr
## Links ## Links
- Frontend i18n: `ui-nyla/src/providers/language/LanguageContext.tsx` - Frontend i18n: `frontend_nyla/src/providers/language/LanguageContext.tsx`
- Frontend Key-Scanner: `ui-nyla/vite.config.ts` (extractI18nKeys Plugin) - Frontend Key-Scanner: `frontend_nyla/vite.config.ts` (extractI18nKeys Plugin)
- Gateway Model-Labels: `platform-core/modules/shared/attributeUtils.py` - Gateway Model-Labels: `gateway/modules/shared/attributeUtils.py`
- Gateway i18n API: `platform-core/modules/routes/routeI18n.py` - Gateway i18n API: `gateway/modules/routes/routeI18n.py`
- UiLanguageSet Model: `platform-core/modules/datamodels/datamodelUiLanguage.py` - UiLanguageSet Model: `gateway/modules/datamodels/datamodelUiLanguage.py`
- TextMultilingual: `platform-core/modules/datamodels/datamodelUtils.py` - TextMultilingual: `gateway/modules/datamodels/datamodelUtils.py`
## Phase 7 (Vorschlag): RBAC-Labels & Quick Actions — Abgleich mit dem Code ## 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 | | Mechanismus | Code / Pfad | Befund |
|-------------|-------------|--------| |-------------|-------------|--------|
| **TextMultilingual** | `platform-core/modules/datamodels/datamodelUtils.py` | Pydantic-Modell: **`en` Pflicht**, `de`/`fr`/`it` optional; `get_text(lang)` mit Fallback auf `en`. | | **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** | `platform-core/modules/datamodels/datamodelRbac.py` — `Role.description: TextMultilingual` | Feld ist **explizit mehrsprachig**; im Schema `frontend_type: "multilingual"`. | | **Rollenbeschreibung in der DB** | `gateway/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). | | **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. | | **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. | | **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 ## Abschluss
- [x] b-reference/ aktualisiert (platform-core/architecture.md, ui-nyla/architecture.md) - [x] b-reference/ aktualisiert (gateway/architecture.md, frontend-nyla/architecture.md)
- [x] TOPICS.md aktualisiert (neues Thema: i18n/Mehrsprachigkeit) - [x] TOPICS.md aktualisiert (neues Thema: i18n/Mehrsprachigkeit)
- [ ] Dieses Dokument -> z-archive/ verschoben (nach finaler Validierung) - [ ] 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 ## Berührte Dateien
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/email.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/email.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/clickup.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/clickup.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/context.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/context.py`
- `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py` - `gateway/tests/unit/graphicalEditor/test_adapter_validator.py`
Keine Action-Implementierungen geändert → kein Runtime-Regressionsrisiko. Keine Action-Implementierungen geändert → kein Runtime-Regressionsrisiko.
@ -115,6 +115,6 @@ Keine Action-Implementierungen geändert → kein Runtime-Regressionsrisiko.
## Links ## Links
- Architektur-Plan: [../3-validate/2026-04-typed-action-architecture.md](../3-validate/2026-04-typed-action-architecture.md) - Architektur-Plan: [../3-validate/2026-04-typed-action-architecture.md](../3-validate/2026-04-typed-action-architecture.md)
- Validator: `platform-core/modules/features/graphicalEditor/adapterValidator.py` - Validator: `gateway/modules/features/graphicalEditor/adapterValidator.py`
- Snapshot-Test: `platform-core/tests/unit/graphicalEditor/test_adapter_validator.py` - Snapshot-Test: `gateway/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) - 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 --> <!-- implemented: 2026-04-29 -->
<!-- reviewed: 2026-04-29 (critical review passed, corrections applied) --> <!-- reviewed: 2026-04-29 (critical review passed, corrections applied) -->
<!-- completed: 2026-05-01 --> <!-- completed: 2026-05-01 -->
<!-- component: gateway, ui-nyla --> <!-- component: gateway, frontend-nyla -->
# AI Reports: Generisches Style-Management, AI-Call-Konfiguration, Inline-Bilder # AI Reports: Generisches Style-Management, AI-Call-Konfiguration, Inline-Bilder
@ -98,38 +98,38 @@ explizit und auditierbar.
## Betroffene Module ## Betroffene Module
- Gateway: - Gateway:
- `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py` - `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`
-- `_markdownToDocumentJson` (nested in `_registerMediaTools`, Z. 27-163) -- `_markdownToDocumentJson` (nested in `_registerMediaTools`, Z. 27-163)
entfernen, Aufruf auf `subDocumentUtility.markdownToDocumentJson` entfernen, Aufruf auf `subDocumentUtility.markdownToDocumentJson`
umleiten. Image-Resolution-Logik (Z. 241-277, loest fileId -> base64 umleiten. Image-Resolution-Logik (Z. 241-277, loest fileId -> base64
aus KnowledgeStore/Chat) VERBLEIBT in `_mediaTools` als Post- aus KnowledgeStore/Chat) VERBLEIBT in `_mediaTools` als Post-
Processing-Schritt nach dem Parser-Aufruf. Processing-Schritt nach dem Parser-Aufruf.
`renderDocument`-Tool-Schema ergaenzt um optionalen `style`-Parameter. `renderDocument`-Tool-Schema ergaenzt um optionalen `style`-Parameter.
- `platform-core/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py` - `gateway/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`
-- alleinige MD->JSON-Funktion mit Inline-Run-Modell. -- alleinige MD->JSON-Funktion mit Inline-Run-Modell.
- `platform-core/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py` - `gateway/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py`
-- `_resolveStyle(metadata.style) -> ResolvedStyle` (Defaults + -- `_resolveStyle(metadata.style) -> ResolvedStyle` (Defaults +
Agent-Overrides). Agent-Overrides).
- `platform-core/modules/serviceCenter/services/serviceGeneration/renderers/*` - `gateway/modules/serviceCenter/services/serviceGeneration/renderers/*`
-- alle 5 Renderer auf Style-Lookup umstellen, Inline-Run-Renderer. -- alle 5 Renderer auf Style-Lookup umstellen, Inline-Run-Renderer.
NUR neues Format (InlineRun); altes String-Format wird nicht mehr NUR neues Format (InlineRun); altes String-Format wird nicht mehr
unterstuetzt. unterstuetzt.
- `platform-core/modules/datamodels/datamodelJson.py` -- Schema-Erweiterung - `gateway/modules/datamodels/datamodelJson.py` -- Schema-Erweiterung
fuer Inline-Runs und `cellContent`. fuer Inline-Runs und `cellContent`.
- `platform-core/modules/datamodels/datamodelAi.py` -- - `gateway/modules/datamodels/datamodelAi.py` --
`AiCallOptions.allowedModels: Optional[List[str]]` (Whitelist; `AiCallOptions.allowedModels: Optional[List[str]]` (Whitelist;
analog `allowedProviders` Z. 164). analog `allowedProviders` Z. 164).
- `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py` - `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`
-- `_calculateEffectiveModels()` (Z. ~1196, analog zu -- `_calculateEffectiveModels()` (Z. ~1196, analog zu
`_calculateEffectiveProviders`); Whitelist-Check vor Modellwahl, `_calculateEffectiveProviders`); Whitelist-Check vor Modellwahl,
Fail-fast wenn keiner uebrig. `_ServicesAdapter.__getattr__` Fail-fast wenn keiner uebrig. `_ServicesAdapter.__getattr__`
(Z. 88-90) um `"allowedModels"` ergaenzen. (Z. 88-90) um `"allowedModels"` ergaenzen.
- `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py` - `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`
-- Standardparameter `requireNeutralization` + `allowedModels` zu -- Standardparameter `requireNeutralization` + `allowedModels` zu
allen `ai.*`-Nodes (gemeinsamer Helper `_AI_COMMON_PARAMS`). allen `ai.*`-Nodes (gemeinsamer Helper `_AI_COMMON_PARAMS`).
- `platform-core/modules/workflows/methods/methodAi/actions/*.py` -- Node- - `gateway/modules/workflows/methods/methodAi/actions/*.py` -- Node-
Parameter durchreichen in den `AiCallRequest`. Parameter durchreichen in den `AiCallRequest`.
- `platform-core/modules/serviceCenter/services/serviceAgent/conversationManager.py` - `gateway/modules/serviceCenter/services/serviceAgent/conversationManager.py`
-- Workspace-Kontext-Defaults fuer `requireNeutralization` / -- Workspace-Kontext-Defaults fuer `requireNeutralization` /
`allowedModels` aus Workspace-Config in `ServiceCenterContext` `allowedModels` aus Workspace-Config in `ServiceCenterContext`
setzen. 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 `generateImage`/`writeFile` oder DataSource-Download erzeugt sein und
liegt bereits als `FileItem` vor). liegt bereits als `FileItem` vor).
**Defaults (`platform-core/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`):** **Defaults (`gateway/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`):**
neutrale Default-Werte fuer alle Felder. `_resolveStyle(agentStyle) -> neutrale Default-Werte fuer alle Felder. `_resolveStyle(agentStyle) ->
ResolvedStyle` macht ein deep-merge `defaults <- agentStyle`. Renderer ResolvedStyle` macht ein deep-merge `defaults <- agentStyle`. Renderer
sieht immer eine vollstaendig aufgeloeste Struktur. sieht immer eine vollstaendig aufgeloeste Struktur.
@ -261,7 +261,7 @@ zu einem `image`-Run. Listen-Items dasselbe.
- **`AiCallRequest.requireNeutralization`** existiert (`datamodelAi.py` Z. 177). - **`AiCallRequest.requireNeutralization`** existiert (`datamodelAi.py` Z. 177).
- **`AiCallOptions.allowedProviders`** existiert (`datamodelAi.py` Z. 164) -- - **`AiCallOptions.allowedProviders`** existiert (`datamodelAi.py` Z. 164) --
Provider-Whitelist auf Anbieter-Ebene (z.B. `anthropic`, `openai`, Provider-Whitelist auf Anbieter-Ebene (z.B. `anthropic`, `openai`,
`service-llm-private`). `private-llm`).
- **`Workflow.allowedProviders`** wird ueber `__getattr__` durchgereicht - **`Workflow.allowedProviders`** wird ueber `__getattr__` durchgereicht
(`mainServiceAi.py` Z. 89). (`mainServiceAi.py` Z. 89).
- **`_calculateEffectiveProviders()`** macht RBAC ∩ Workflow.allowedProviders - **`_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) ### Beispiel: AI-Node-Definition (gekuerzt)
```python ```python
# in platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py # in gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py
# (allowedProviders existiert bereits auf Workflow-Ebene; hier nur die # (allowedProviders existiert bereits auf Workflow-Ebene; hier nur die
# zwei NEUEN Felder pro AI-Node) # zwei NEUEN Felder pro AI-Node)
_AI_COMMON_PARAMS = [ _AI_COMMON_PARAMS = [
@ -414,7 +414,7 @@ flowchart LR
### Phase 2 -- Style-System ### Phase 2 -- Style-System
- [x] Defaults-Modul `platform-core/modules/serviceCenter/services/serviceGeneration/styleDefaults.py` - [x] Defaults-Modul `gateway/modules/serviceCenter/services/serviceGeneration/styleDefaults.py`
mit neutralen Default-Werten fuer alle Style-Felder. mit neutralen Default-Werten fuer alle Style-Felder.
- [x] Style-Resolver in `mainServiceGeneration.py`: - [x] Style-Resolver in `mainServiceGeneration.py`:
`_resolveStyle(metadataStyle: dict | None) -> ResolvedStyle` `_resolveStyle(metadataStyle: dict | None) -> ResolvedStyle`
@ -471,15 +471,15 @@ flowchart LR
### Phase 5 -- AI-Call-Konfiguration pro Node (Datenmodell + Backend) ### Phase 5 -- AI-Call-Konfiguration pro Node (Datenmodell + Backend)
- [x] `platform-core/modules/datamodels/datamodelAi.py`: - [x] `gateway/modules/datamodels/datamodelAi.py`:
- `AiCallOptions.allowedModels: Optional[List[str]] = None` - `AiCallOptions.allowedModels: Optional[List[str]] = None`
(analog zu `allowedProviders` in Z. 164 -- KEIN neues Feld in (analog zu `allowedProviders` in Z. 164 -- KEIN neues Feld in
`AiCallRequest`). `AiCallRequest`).
- [x] `platform-core/modules/datamodels/datamodelAuto.py` (oder wo immer das - [x] `gateway/modules/datamodels/datamodelAuto.py` (oder wo immer das
`Workflow`-Modell liegt): `Workflow`-Modell liegt):
- `Workflow.allowedModels: Optional[List[str]] = None` (analog - `Workflow.allowedModels: Optional[List[str]] = None` (analog
`Workflow.allowedProviders`). `Workflow.allowedProviders`).
- [x] `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`: - [x] `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`:
- Neue private Methode `_calculateEffectiveModels()` analog zu - Neue private Methode `_calculateEffectiveModels()` analog zu
`_calculateEffectiveProviders()` (Z. ~1196). RBAC-Modelle ∩ `_calculateEffectiveProviders()` (Z. ~1196). RBAC-Modelle ∩
`Workflow.allowedModels``request.options.allowedModels`. `Workflow.allowedModels``request.options.allowedModels`.
@ -540,12 +540,12 @@ flowchart LR
### Phase 5b -- AI-Nodes im FlowEditor ### Phase 5b -- AI-Nodes im FlowEditor
- [x] `platform-core/modules/features/graphicalEditor/nodeDefinitions/ai.py`: - [x] `gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py`:
- Modul-lokaler Helper `_AI_COMMON_PARAMS = [...]` mit den 2 - Modul-lokaler Helper `_AI_COMMON_PARAMS = [...]` mit den 2
neuen Parametern. neuen Parametern.
- In ALLE 8 Eintraege von `AI_NODES` als `*_AI_COMMON_PARAMS` - In ALLE 8 Eintraege von `AI_NODES` als `*_AI_COMMON_PARAMS`
anhaengen. anhaengen.
- [x] `platform-core/modules/workflows/methods/methodAi/actions/*.py`: - [x] `gateway/modules/workflows/methods/methodAi/actions/*.py`:
- In jeder Action (`process.py`, `webResearch.py`, - In jeder Action (`process.py`, `webResearch.py`,
`summarizeDocument.py`, `translateDocument.py`, `summarizeDocument.py`, `translateDocument.py`,
`convertDocument.py`, `generateDocument.py`, `convertDocument.py`, `generateDocument.py`,
@ -612,37 +612,37 @@ flowchart LR
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1,2 | snapshot | ja | platform-core/tests/serviceGeneration/test_agent_style_docx.py | done | | T1 | 1,2 | snapshot | ja | gateway/tests/serviceGeneration/test_agent_style_docx.py | done |
| T2 | 3 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_paragraph.py | done | | T2 | 3 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_paragraph.py | done |
| T3 | 4 | integration | ja | platform-core/tests/serviceGeneration/test_inline_image_table_cell.py | done | | T3 | 4 | integration | ja | gateway/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 | | T4 | 5 | integration | ja | gateway/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 | | T5 | 6 | integration | ja | gateway/tests/serviceGeneration/test_inline_image_pptx_fallback.py | done |
| T6 | 7 | integration | ja | platform-core/tests/serviceAi/test_node_neutralization_flag.py | done | | T6 | 7 | integration | ja | gateway/tests/serviceAi/test_node_neutralization_flag.py | done |
| T7 | 8,9 | integration | ja | platform-core/tests/serviceAi/test_allowed_models_whitelist.py | done | | T7 | 8,9 | integration | ja | gateway/tests/serviceAi/test_allowed_models_whitelist.py | done |
| T8 | 10 | integration | ja | platform-core/tests/features/workspace/test_user_settings_persistence.py | done | | T8 | 10 | integration | ja | gateway/tests/features/workspace/test_user_settings_persistence.py | done |
| T9 | 11 | integration | ja | platform-core/tests/serviceAi/test_workspace_propagates_settings.py | done | | T9 | 11 | integration | ja | gateway/tests/serviceAi/test_workspace_propagates_settings.py | done |
| T10 | 12 | unit | ja | platform-core/tests/serviceAi/test_effective_models_and_providers.py | done | | T10 | 12 | unit | ja | gateway/tests/serviceAi/test_effective_models_and_providers.py | done |
| T11 | 13 | unit | ja | platform-core/tests/serviceCenter/test_md_to_json_consolidation.py | done | | T11 | 13 | unit | ja | gateway/tests/serviceCenter/test_md_to_json_consolidation.py | done |
| T12 | -- | unit | ja | ui-nyla/src/components/flowEditor/__tests__/AiNodeProperties.test.tsx | deferred | | T12 | -- | unit | ja | frontend_nyla/src/components/flowEditor/__tests__/AiNodeProperties.test.tsx | deferred |
## Links ## Links
- Aktuelle Pipeline-Architektur: Subagent-Report 2026-04-29. - Aktuelle Pipeline-Architektur: Subagent-Report 2026-04-29.
- Renderer-Code: `platform-core/modules/serviceCenter/services/serviceGeneration/renderers/`. - Renderer-Code: `gateway/modules/serviceCenter/services/serviceGeneration/renderers/`.
- MD->JSON-Code: - MD->JSON-Code:
`platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`, `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_mediaTools.py`,
`platform-core/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`. `gateway/modules/serviceCenter/services/serviceGeneration/subDocumentUtility.py`.
- AI-Gate: `platform-core/modules/serviceCenter/services/serviceAi/mainServiceAi.py`. - AI-Gate: `gateway/modules/serviceCenter/services/serviceAi/mainServiceAi.py`.
- Neutralisierung: `wiki/b-reference/platform/neutralization.md`. - Neutralisierung: `wiki/b-reference/platform/neutralization.md`.
- Wiki: `wiki/b-reference/platform-core/ai-agent.md`, - Wiki: `wiki/b-reference/gateway/ai-agent.md`,
`wiki/b-reference/platform-core/agent-file-bridge.md`, `wiki/b-reference/gateway/agent-file-bridge.md`,
`wiki/b-reference/platform-core/workflow.md`. `wiki/b-reference/gateway/workflow.md`.
## Abschluss ## Abschluss
- [ ] `wiki/b-reference/platform-core/ai-agent.md` -- Style-System + per-call - [ ] `wiki/b-reference/gateway/ai-agent.md` -- Style-System + per-call
Konfiguration ergaenzen (TODO: bei naechster Wiki-Review-Runde) Konfiguration ergaenzen (TODO: bei naechster Wiki-Review-Runde)
- [ ] `wiki/b-reference/platform-core/workflow.md` -- AI-Node-Standardparameter - [ ] `wiki/b-reference/gateway/workflow.md` -- AI-Node-Standardparameter
dokumentieren (TODO: bei naechster Wiki-Review-Runde) dokumentieren (TODO: bei naechster Wiki-Review-Runde)
- [ ] `wiki/b-reference/platform/neutralization.md` -- per-Node-Trigger - [ ] `wiki/b-reference/platform/neutralization.md` -- per-Node-Trigger
ergaenzen (TODO: bei naechster Wiki-Review-Runde) ergaenzen (TODO: bei naechster Wiki-Review-Runde)

View file

@ -1,6 +1,6 @@
<!-- status: validate --> <!-- status: validate -->
<!-- started: 2026-04-12 --> <!-- started: 2026-04-12 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# Automatisierung — Zentrale Administration aller Workflows # Automatisierung — Zentrale Administration aller Workflows
@ -78,6 +78,6 @@ Die Seite "Automatisierung" in "Meine Sicht" zeigt aktuell nur ein Dashboard mit
## Abschluss ## Abschluss
- [x] b-reference/ aktualisiert — [`b-reference/platform-core/automation.md`](../../b-reference/platform-core/automation.md) (Abschnitt System-Automatisierung) - [x] b-reference/ aktualisiert — [`b-reference/gateway/automation.md`](../../b-reference/gateway/automation.md) (Abschnitt System-Automatisierung)
- [x] TOPICS.md — Verweis unter „Aktive Arbeiten“ ergänzt - [x] TOPICS.md — Verweis unter „Aktive Arbeiten“ ergänzt
- [ ] Dieses Dokument → `z-archive/` verschieben (nach Abnahme / wenn kein offenes Follow-up) - [ ] 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 --> <!-- started: 2026-04-05 -->
<!-- completed: 2026-04-07 --> <!-- completed: 2026-04-07 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
# Automation Unification -- Konsolidierung v1/v2/Workspace # 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) ## Backend Code-Struktur (Ziel)
``` ```
platform-core/modules/ gateway/modules/
| |
+-- features/ +-- features/
| +-- graphicalEditor/ <-- NEUES FEATURE (ersetzt automation2) | +-- graphicalEditor/ <-- NEUES FEATURE (ersetzt automation2)
@ -964,7 +964,7 @@ platform-core/modules/
## Frontend Code-Struktur (umgesetzt) ## Frontend Code-Struktur (umgesetzt)
``` ```
ui-nyla/src/ frontend_nyla/src/
| |
+-- components/ <-- SHARED COMPONENTS +-- components/ <-- SHARED COMPONENTS
| +-- UnifiedDataBar/ <-- BLEIBT (Files + Sources Tabs, Mandate-gefiltert) | +-- UnifiedDataBar/ <-- BLEIBT (Files + Sources Tabs, Mandate-gefiltert)
@ -1152,11 +1152,11 @@ ui-nyla/src/
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | platform-core/tests/test_automation2_scheduler.py | pending | | T1 | 1 | integration | ja | gateway/tests/test_automation2_scheduler.py | pending |
| T2 | 2 | integration | ja | platform-core/tests/test_agent_toolbox.py | pending | | T2 | 2 | integration | ja | gateway/tests/test_agent_toolbox.py | pending |
| T3 | 3 | api | ja | platform-core/tests/test_workflow_pause_resume.py | pending | | T3 | 3 | api | ja | gateway/tests/test_workflow_pause_resume.py | pending |
| T4 | 4 | integration | ja | platform-core/tests/test_editor_chat_graph.py | pending | | T4 | 4 | integration | ja | gateway/tests/test_editor_chat_graph.py | pending |
| T5 | 5 | unit | ja | platform-core/tests/test_workflow_versioning.py | pending | | T5 | 5 | unit | ja | gateway/tests/test_workflow_versioning.py | pending |
## Glossar ## Glossar
@ -1182,7 +1182,7 @@ ui-nyla/src/
- Detail-Spec (Business): z-archive/b-reference/automation-business-spec.md - Detail-Spec (Business): z-archive/b-reference/automation-business-spec.md
- Detail-Spec (Datenmodell): z-archive/b-reference/automation-data-model.md - Detail-Spec (Datenmodell): z-archive/b-reference/automation-data-model.md
- Referenz (Ist-Zusammenfassung): b-reference/platform-core/automation.md - Referenz (Ist-Zusammenfassung): b-reference/gateway/automation.md
## Abschluss ## Abschluss
@ -1201,6 +1201,6 @@ ui-nyla/src/
- Custom Script Node (Python Sandbox) - Custom Script Node (Python Sandbox)
- Sub-Agent Pattern fuer weitere Features - Sub-Agent Pattern fuer weitere Features
- [ ] b-reference/platform-core/automation.md aktualisiert - [ ] b-reference/gateway/automation.md aktualisiert
- [ ] TOPICS.md aktualisiert - [ ] TOPICS.md aktualisiert
- [ ] Dieses Dokument -> z-archive/ verschoben - [ ] Dieses Dokument -> z-archive/ verschoben

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: plan --> <!-- status: plan -->
<!-- started: 2026-04-09 --> <!-- started: 2026-04-09 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
# Customer Demo Enablement — Bling, PWG, Quid/ServiceHunter # 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` - 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` - 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` - INT-Stabilität (parallel): `c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`
- CommCoach-Feature: `platform-core/modules/features/commcoach/` - CommCoach-Feature: `gateway/modules/features/commcoach/`
- Neutralisierung-Feature: `platform-core/modules/features/neutralization/` - Neutralisierung-Feature: `gateway/modules/features/neutralization/`
- Trustee-Feature: `platform-core/modules/features/trustee/` - Trustee-Feature: `gateway/modules/features/trustee/`
- Workspace-Feature: `platform-core/modules/features/workspace/` - Workspace-Feature: `gateway/modules/features/workspace/`
## Abschluss ## Abschluss
- [ ] b-reference/ aktualisiert (ggf. neue Feature-Docs unter `b-reference/platform-core/features/`) - [ ] b-reference/ aktualisiert (ggf. neue Feature-Docs unter `b-reference/gateway/features/`)
- [ ] TOPICS.md aktualisiert (falls neues Thema) - [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben - [ ] Dieses Dokument → z-archive/ verschoben

View file

@ -1,6 +1,6 @@
<!-- status: build --> <!-- status: build -->
<!-- started: 2026-04-09 --> <!-- started: 2026-04-09 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
# Quick Actions — Feature-Dashboard mit One-Click-Aktionen # 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 ### Ist-Zustand: Trustee Dashboard
`ui-nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` zeigt aktuell: `frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` zeigt aktuell:
- **Stats-Grid:** 4 Kacheln (Positionen, Dokumente, Buchhaltungs-Sync, Rollen) - **Stats-Grid:** 4 Kacheln (Positionen, Dokumente, Buchhaltungs-Sync, Rollen)
- **Info-Sektion:** Instanz-Label, Mandant, Buchhaltungssystem - **Info-Sektion:** Instanz-Label, Mandant, Buchhaltungssystem
@ -395,7 +395,7 @@ const _navigateToWorkspaceWithPrompt = async (config: QuickActionConfig) => {
| ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status | | ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status |
|----|----|-----|--------------|---------------------|--------| |----|----|-----|--------------|---------------------|--------|
| T1 | 1, 5 | api | ja | `platform-core/tests/features/trustee/test_quick_actions_api.py` — Endpoint liefert gefilterte Actions pro Rolle | pending | | T1 | 1, 5 | api | ja | `gateway/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 | | 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 | | 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 | | 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` - Kundenwünsche: `local/notes/use-cases-inputs-customers.md`
- Customer Demo Enablement: `c-work/1-plan/2026-04-customer-demo-enablement.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 Tooling: `c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md`
- Trustee Dashboard (Frontend): `ui-nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` - Trustee Dashboard (Frontend): `frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx`
- Trustee Feature (Gateway): `platform-core/modules/features/trustee/mainTrustee.py` - Trustee Feature (Gateway): `gateway/modules/features/trustee/mainTrustee.py`
- Trustee Routes (Gateway): `platform-core/modules/features/trustee/routeFeatureTrustee.py` - Trustee Routes (Gateway): `gateway/modules/features/trustee/routeFeatureTrustee.py`
- Workspace Routes (Gateway): `platform-core/modules/features/workspace/routeFeatureWorkspace.py` - Workspace Routes (Gateway): `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- Workspace Page (Frontend): `ui-nyla/src/pages/views/workspace/WorkspacePage.tsx` - Workspace Page (Frontend): `frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx`
- FeatureView Registry (Frontend): `ui-nyla/src/pages/FeatureView.tsx` - FeatureView Registry (Frontend): `frontend_nyla/src/pages/FeatureView.tsx`
- Quick Action Board (Frontend, neu): `ui-nyla/src/components/QuickActionBoard/` - Quick Action Board (Frontend, neu): `frontend_nyla/src/components/QuickActionBoard/`
- Navigation API: `wiki/b-reference/platform/navigation.md` - Navigation API: `wiki/b-reference/platform/navigation.md`
## Abschluss ## Abschluss
- [ ] b-reference/ aktualisiert (`b-reference/platform-core/features/trustee.md` — neu anlegen mit Quick Actions) - [ ] b-reference/ aktualisiert (`b-reference/gateway/features/trustee.md` — neu anlegen mit Quick Actions)
- [ ] b-reference/ui-nyla/architecture.md aktualisiert (QuickActionBoard-Komponente) - [ ] b-reference/frontend-nyla/architecture.md aktualisiert (QuickActionBoard-Komponente)
- [ ] TOPICS.md aktualisiert (neues Thema "Quick Actions") - [ ] TOPICS.md aktualisiert (neues Thema "Quick Actions")
- [ ] Dieses Dokument → z-archive/ verschoben - [ ] 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | nein (manuell mit Abacus-Sandbox) | — | pending | | T1 | 1 | api | nein (manuell mit Abacus-Sandbox) | — | pending |
| T2 | 2 | api | ja | platform-core/tests/features/trustee/test_refresh_tool.py | pending | | T2 | 2 | api | ja | gateway/tests/features/trustee/test_refresh_tool.py | pending |
| T3 | 3 | api | ja | platform-core/tests/features/trustee/test_aggregate_table.py | pending | | T3 | 3 | api | ja | gateway/tests/features/trustee/test_aggregate_table.py | pending |
| T4 | 4 | api | ja | platform-core/tests/serviceAgent/test_feature_data_cache.py | pending | | T4 | 4 | api | ja | gateway/tests/serviceAgent/test_feature_data_cache.py | pending |
| T5 | 5 | ui | nein (manuell) | — | pending | | T5 | 5 | ui | nein (manuell) | — | pending |
| T6 | 6 | e2e | nein (manuell) | — | pending | | T6 | 6 | e2e | nein (manuell) | — | pending |
| T7 | 7 | api | ja | platform-core/tests/workflows/graphicalEditor/test_node_chaining.py | pending | | T7 | 7 | api | ja | gateway/tests/workflows/graphicalEditor/test_node_chaining.py | pending |
| T8 | 8 | e2e | nein (manuell) | — | pending | | T8 | 8 | e2e | nein (manuell) | — | pending |
## Links ## Links
- Use Cases: `pamocreate/projects/poweron/customer-pwg/20260407 use-cases-workshop.md` - 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` - Automation Unification (done): `wiki/c-work/3-validate/2026-04-automation-unification.md`
- Trustee Accounting Bridge: `platform-core/modules/features/trustee/accounting/accountingBridge.py` - Trustee Accounting Bridge: `gateway/modules/features/trustee/accounting/accountingBridge.py`
- Accounting Data Sync: `platform-core/modules/features/trustee/accounting/accountingDataSync.py` - Accounting Data Sync: `gateway/modules/features/trustee/accounting/accountingDataSync.py`
- Feature Data Agent: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py` - Feature Data Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Feature Data Provider: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` - Feature Data Provider: `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py`
- Feature Sub-Agent Tool: `platform-core/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py` - Feature Sub-Agent Tool: `gateway/modules/serviceCenter/services/serviceAgent/coreTools/_featureSubAgentTools.py`
- Toolbox Registry: `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` - Toolbox Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- Abacus Connector: `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py` - Abacus Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Node Registry: `platform-core/modules/features/graphicalEditor/nodeRegistry.py` - Node Registry: `gateway/modules/features/graphicalEditor/nodeRegistry.py`
- Trustee Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py` - Trustee Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/trustee.py`
- SharePoint Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py` - SharePoint Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/sharepoint.py`
- Flow Nodes: `platform-core/modules/features/graphicalEditor/nodeDefinitions/flow.py` - Flow Nodes: `gateway/modules/features/graphicalEditor/nodeDefinitions/flow.py`
- Action Node Executor: `platform-core/modules/workflows/automation2/executors/actionNodeExecutor.py` - Action Node Executor: `gateway/modules/workflows/automation2/executors/actionNodeExecutor.py`
- Execution Engine: `platform-core/modules/workflows/automation2/executionEngine.py` - Execution Engine: `gateway/modules/workflows/automation2/executionEngine.py`
- Scheduler: `platform-core/modules/workflows/scheduler/mainScheduler.py` - Scheduler: `gateway/modules/workflows/scheduler/mainScheduler.py`
- Trustee Workflow Method: `platform-core/modules/workflows/methods/methodTrustee/methodTrustee.py` - Trustee Workflow Method: `gateway/modules/workflows/methods/methodTrustee/methodTrustee.py`
- Graphical Editor Feature: `platform-core/modules/features/graphicalEditor/mainGraphicalEditor.py` - Graphical Editor Feature: `gateway/modules/features/graphicalEditor/mainGraphicalEditor.py`
- Graphical Editor Datenmodell: `platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py` - Graphical Editor Datenmodell: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
## Abschluss ## Abschluss
- [x] b-reference/platform-core/workflow.md aktualisiert (neue Action `trustee.refreshAccountingData`) - [x] b-reference/gateway/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/gateway/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) - [x] b-reference/gateway/automation.md aktualisiert (neue Trustee-Nodes + Kategorie in Node-Palette)
- [ ] TOPICS.md aktualisiert (falls neues Thema) - [ ] TOPICS.md aktualisiert (falls neues Thema)
- [ ] Dieses Dokument → z-archive/ verschoben - [ ] Dieses Dokument → z-archive/ verschoben

View file

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

View file

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

View file

@ -1,7 +1,7 @@
<!-- status: done (superseded) --> <!-- status: done (superseded) -->
<!-- started: 2026-04-29 --> <!-- started: 2026-04-29 -->
<!-- completed: 2026-05-15 --> <!-- completed: 2026-05-15 -->
<!-- component: ui-nyla | gateway --> <!-- component: frontend-nyla | gateway -->
<!-- note: Original plan (saveGroupTree/groupId/handleGroupingInRequest) was superseded by <!-- note: Original plan (saveGroupTree/groupId/handleGroupingInRequest) was superseded by
View-based GroupLayout strategy (TableListView with groupByLevels + GroupBand response). View-based GroupLayout strategy (TableListView with groupByLevels + GroupBand response).
The implemented approach uses datamodelPagination.GroupByLevel/GroupBand/GroupLayout 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 - [ ] i18n: alle neuen UI-Texte mit `t('...')` getaggt
- [ ] CSS Modules für alle neuen Komponenten - [ ] CSS Modules für alle neuen Komponenten
- [ ] `b-reference/ui-nyla/formgenerator.md` aktualisieren - [ ] `b-reference/frontend-nyla/formgenerator.md` aktualisieren
- [ ] `b-reference/platform-core/architecture.md` — `PaginationParams`/`PaginatedResponse`-Erweiterung dokumentieren - [ ] `b-reference/gateway/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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|----|--------------|-----------|--------| |----|----|----|--------------|-----------|--------|
| T1 | 1, 2 | api | ja | `platform-core/tests/test_grouping_helpers.py` | pending | | T1 | 1, 2 | api | ja | `gateway/tests/test_grouping_helpers.py` | pending |
| T2 | 3, 4, 5, 6 | api | ja | `platform-core/tests/test_grouping_helpers.py` | pending | | T2 | 3, 4, 5, 6 | api | ja | `gateway/tests/test_grouping_helpers.py` | pending |
| T3 | 7 | component | nein | manuell | pending | | T3 | 7 | component | nein | manuell | pending |
| T4 | 8 | api + component | nein | manuell | pending | | T4 | 8 | api + component | nein | manuell | pending |
| T5 | 9 | component | nein | manuell | pending | | T5 | 9 | component | nein | manuell | pending |
@ -451,8 +451,8 @@ Pro Route: `handleGroupingInRequest` am Anfang + `applyGroupScopeFilter` vor Pag
## Links ## Links
- PR: — - PR: —
- Referenz FormGenerator: `b-reference/ui-nyla/formgenerator.md` - Referenz FormGenerator: `b-reference/frontend-nyla/formgenerator.md`
- Referenz Gateway-Architektur: `b-reference/platform-core/architecture.md` - Referenz Gateway-Architektur: `b-reference/gateway/architecture.md`
- Referenz DB-Architektur: `b-reference/platform/database-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 ## Vollständige Liste der Duplikate
Ermittelt per AST-Scan über `platform-core/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen): Ermittelt per AST-Scan über `gateway/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen):
### Kritisch: Pydantic-Modelle mit `@i18nModel` (i18n-Dict-Kollision) ### Kritisch: Pydantic-Modelle mit `@i18nModel` (i18n-Dict-Kollision)

View file

@ -49,7 +49,7 @@ flowchart LR
### A.1 Inhalt ### A.1 Inhalt
1. In `platform-core/modules/shared/i18nRegistry.py` Funktion **`_registerRbacLabels()`** implementieren (falls noch nicht vorhanden): 1. In `gateway/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). - 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`: - Pro Eintrag: `label` ist **Dict**`key = label.get("de") or label.get("en")` (nicht-leer); `context`:
- `rbac.data` fuer DATA_OBJECTS - `rbac.data` fuer DATA_OBJECTS
@ -63,9 +63,9 @@ flowchart LR
| Datei | Aenderung | | Datei | Aenderung |
|-------|-----------| |-------|-----------|
| `platform-core/modules/shared/i18nRegistry.py` | `_registerRbacLabels`, Aufruf in `_syncRegistryToDb` | | `gateway/modules/shared/i18nRegistry.py` | `_registerRbacLabels`, Aufruf in `_syncRegistryToDb` |
| `platform-core/modules/system/mainSystem.py` | Nur falls DATA/RESOURCE dort noch nicht importiert werden — Scan | | `gateway/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 | | `gateway/modules/routes/routeI18n.py` | Nur falls Sync-Logik `rbac.*` explizit filtern muss — pruefen |
### A.3 Abnahme ### A.3 Abnahme
@ -123,7 +123,7 @@ flowchart LR
### D.1 Inhalt ### D.1 Inhalt
1. Neuer Endpoint in `platform-core/modules/routes/routeI18n.py`, z. B.: 1. Neuer Endpoint in `gateway/modules/routes/routeI18n.py`, z. B.:
- `POST /api/i18n/translate-field` - `POST /api/i18n/translate-field`
- Body: `{ "sourceText": string, "sourceLang": string, "targetLangs": string[] }` - Body: `{ "sourceText": string, "sourceLang": string, "targetLangs": string[] }`
- Response: `{ "translations": { "de": "...", "fr": "..." } }` (ohne Source-Lang) - Response: `{ "translations": { "de": "...", "fr": "..." } }` (ohne Source-Lang)
@ -203,8 +203,8 @@ Rollback: WP-A durch Entfernen des Aufrufs `_registerRbacLabels()` deaktivieren;
## 12. Links ## 12. Links
- Konzept & Phase-7-Text: `c-work/2-build/2026-04 gateway-i18n-unified.md` - Konzept & Phase-7-Text: `c-work/2-build/2026-04 gateway-i18n-unified.md`
- i18n Registry: `platform-core/modules/shared/i18nRegistry.py` - i18n Registry: `gateway/modules/shared/i18nRegistry.py`
- i18n API: `platform-core/modules/routes/routeI18n.py` - i18n API: `gateway/modules/routes/routeI18n.py`
- Formular: `ui-nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx` - Formular: `frontend_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. **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 `platform-core`; keine zwingende Frontend-Änderung, ausser Tool-Beschreibungen/UX explizit angepasst werden. **Abhängigkeiten:** Änderungen betreffen primär `gateway`; keine zwingende Frontend-Änderung, ausser Tool-Beschreibungen/UX explizit angepasst werden.
## Fokus und kritische Details ## 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. - **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. - **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:** `platform-core/modules/interfaces/interfaceDbManagement.py`, `platform-core/modules/routes/routeDataFiles.py` (`_autoIndexFile`). - **Code:** `gateway/modules/interfaces/interfaceDbManagement.py`, `gateway/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. - **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` ### Thema B — Agent-Tool-JSON-Schema: Arrays ohne `items`
- **Fragil:** `ActionToolAdapter` mappt `List[str]` auf JSON-Schema `type: array` **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. - **Edge Case:** OpenAI lehnt Tools mit HTTP 400 ab (*array schema missing items*); Failover zu anderen Providern maskiert das Problem.
- **Code:** `platform-core/modules/serviceCenter/services/serviceAgent/actionToolAdapter.py`; betroffene Aktion u. a. `ai.process` (`methodAi.py`, Parameter `documentList`). - **Code:** `gateway/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"}`). - **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 ### 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 ### 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). - **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:** `platform-core/modules/serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py` (`indexFile`). - **Code:** `gateway/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. - **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 ### Thema E — Workspace: Mandats-Kontext aus zwei Quellen
- **Fragil:** `_getChatInterface` nutzt `context.mandateId`; `ServiceCenterContext` für den Agent nutzt Mandat aus `_validateInstanceAccess` (Instanz). - **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). - **Edge Case:** Unterschiedliche `interfaceDbChat`-Cache-Keys für „denselben" Workspace → seltene Inkonsistenzen (Workflow sichtbar / nicht sichtbar).
- **Code:** `platform-core/modules/features/workspace/routeFeatureWorkspace.py`. - **Code:** `gateway/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`. - **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 ### 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". - **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. - **Edge Case:** Agent-Lauf endet „complete", Persistenz der Assistant-Message schlägt fehl — Ursache ohne besseres Logging schwer trennbar.
- **Code:** `platform-core/modules/interfaces/interfaceDbChat.py`. - **Code:** `gateway/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. - **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 ## Ziel und Nicht-Ziele
@ -111,7 +111,7 @@ Weitere Checkliste aus Template:
| ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status | | ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status |
|----|----|-----|--------------|---------------------|--------| |----|----|-----|--------------|---------------------|--------|
| T1 | AC1 | unit | ja | `platform-core/tests/...` — `indexFile` mit Mock neutralization, nur image `contentObjects` | pending | | T1 | AC1 | unit | ja | `gateway/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 | | 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 | | 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 | | 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 ## Abschluss
- [x] Alle Themen AF umgesetzt (2026-04-11) - [x] Alle Themen AF umgesetzt (2026-04-11)
- [ ] b-reference/ aktualisiert — z. B. `b-reference/platform-core/architecture.md` nur wenn Architektur-Entscheid (Singleton) dauerhaft geändert wird - [ ] b-reference/ aktualisiert — z. B. `b-reference/gateway/architecture.md` nur wenn Architektur-Entscheid (Singleton) dauerhaft geändert wird
- [ ] TOPICS.md aktualisiert (falls neues Thema) - [ ] 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 ### 2.2 Port-Schema Pydantic-Modelle
**Neue Datei:** `platform-core/modules/features/graphicalEditor/portTypes.py` **Neue Datei:** `gateway/modules/features/graphicalEditor/portTypes.py`
```python ```python
class PortField(BaseModel): class PortField(BaseModel):
@ -386,7 +386,7 @@ function GenericNodeConfig({ node, nodeType }) {
## 7 Execution Plan — Backend ## 7 Execution Plan — Backend
### 7.1 NEU: `platform-core/modules/features/graphicalEditor/portTypes.py` ### 7.1 NEU: `gateway/modules/features/graphicalEditor/portTypes.py`
Erstellen. Inhalt: Erstellen. Inhalt:
@ -398,7 +398,7 @@ Erstellen. Inhalt:
- Transit-Envelope-Helpers: `_wrapTransit(data, meta)`, `_unwrapTransit(output)`, `_resolveTransitChain(nodeId, nodeOutputs, connectionMap)` - Transit-Envelope-Helpers: `_wrapTransit(data, meta)`, `_unwrapTransit(output)`, `_resolveTransitChain(nodeId, nodeOutputs, connectionMap)`
- Schema-Ableitungsfunktionen: `_deriveFormPayloadSchema(node)`, `_deriveTransformSchema(node)` (Abschnitt 2.5) - Schema-Ableitungsfunktionen: `_deriveFormPayloadSchema(node)`, `_deriveTransformSchema(node)` (Abschnitt 2.5)
### 7.2 ÄNDERN: `platform-core/modules/shared/frontendTypes.py` ### 7.2 ÄNDERN: `gateway/modules/shared/frontendTypes.py`
**Aktuell:** `FrontendType` Enum mit 14 Werten (Zeilen 1663). **Aktuell:** `FrontendType` Enum mit 14 Werten (Zeilen 1663).
@ -420,7 +420,7 @@ Hinzufügen:
`CUSTOM_TYPE_OPTIONS_API` und `CUSTOM_TYPE_DESCRIPTIONS` entsprechend erweitern. `CUSTOM_TYPE_OPTIONS_API` und `CUSTOM_TYPE_DESCRIPTIONS` entsprechend erweitern.
### 7.3 NEU SCHREIBEN: `platform-core/modules/features/graphicalEditor/nodeDefinitions/*.py` ### 7.3 NEU SCHREIBEN: `gateway/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**. 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. `__init__.py`: `STATIC_NODE_TYPES` um `DATA_NODES` erweitern; `flow.py` um `flow.merge` erweitern.
### 7.4 ÄNDERN: `platform-core/modules/features/graphicalEditor/nodeRegistry.py` ### 7.4 ÄNDERN: `gateway/modules/features/graphicalEditor/nodeRegistry.py`
**Funktion `getNodeTypesForApi`** (Zeile 5475): **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. **Funktion `getNodeTypeToMethodAction`** (Zeile 7889): bleibt, `_method`/`_action` weiterhin verwendet.
### 7.5 ÄNDERN: `platform-core/modules/workflows/automation2/graphUtils.py` ### 7.5 ÄNDERN: `gateway/modules/workflows/automation2/graphUtils.py`
**Funktion `resolveParameterReferences`** (Zeile 185243): **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). **Funktion `validateGraph`** (Zeile 86120): erweitern um Port-Kompatibilitäts-Check (soft — Warnings sammeln, nicht hart ablehnen).
### 7.6 NEU SCHREIBEN: `platform-core/modules/workflows/automation2/executors/actionNodeExecutor.py` ### 7.6 NEU SCHREIBEN: `gateway/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: **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. **Keine** node-type-spezifische Logik mehr im Executor.
### 7.7 NEU: `platform-core/modules/workflows/automation2/executors/dataExecutor.py` ### 7.7 NEU: `gateway/modules/workflows/automation2/executors/dataExecutor.py`
Neuer Executor für `data.aggregate`, `data.transform`, `data.filter`: 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.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 - `data.filter`: evaluiert `condition` pro Item der Input-Liste, gibt gefilterte Liste zurück
### 7.8 ÄNDERN: `platform-core/modules/workflows/automation2/executors/flowExecutor.py` ### 7.8 ÄNDERN: `gateway/modules/workflows/automation2/executors/flowExecutor.py`
**Funktion `_ifElse`** (Zeile 5565): Output ändern zu Transit-Envelope: **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. **NEU: `_merge`** Funktion: sammelt Outputs aller verbundenen Input-Ports aus `nodeOutputs`, wendet Modus an (first/all/append), gibt `MergeResult` zurück.
### 7.9 ÄNDERN: `platform-core/modules/workflows/automation2/executors/__init__.py` ### 7.9 ÄNDERN: `gateway/modules/workflows/automation2/executors/__init__.py`
`DataExecutor` importieren und exportieren. `DataExecutor` importieren und exportieren.
### 7.10 ÄNDERN: `platform-core/modules/workflows/automation2/executionEngine.py` ### 7.10 ÄNDERN: `gateway/modules/workflows/automation2/executionEngine.py`
**Funktion `_getExecutor`** (Zeile 7185): Case für `data.*` hinzufügen → `DataExecutor`. **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`). **Pause/Resume:** Resume-Handler (`initialNodeOutputs`) — Validierung der User-Eingabe gegen Output-Schema der pausierten Node (in `executeGraph` nach Empfang von `initialNodeOutputs`).
### 7.11 ÄNDERN: `platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py` ### 7.11 ÄNDERN: `gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
**Funktion `get_node_types`** (Zeile 146168): Response-Struktur erweitern: **Funktion `get_node_types`** (Zeile 146168): Response-Struktur erweitern:
@ -540,7 +540,7 @@ return {
## 8 Execution Plan — Frontend ## 8 Execution Plan — Frontend
### 8.1 ÄNDERN: `ui-nyla/src/api/workflowApi.ts` ### 8.1 ÄNDERN: `frontend_nyla/src/api/workflowApi.ts`
**Interface `NodeTypeParameter`** (Zeile 1420): erweitern um `frontendType`, `frontendOptions`, `options`, `validation`. **Interface `NodeTypeParameter`** (Zeile 1420): erweitern um `frontendType`, `frontendOptions`, `options`, `validation`.
@ -548,7 +548,7 @@ return {
**Interface `NodeTypesResponse`** (Zeile 4649): erweitern um `portTypeCatalog`, `systemVariables`. **Interface `NodeTypesResponse`** (Zeile 4649): erweitern um `portTypeCatalog`, `systemVariables`.
### 8.2 LÖSCHEN + NEU: `ui-nyla/src/components/FlowEditor/nodes/configs/` ### 8.2 LÖSCHEN + NEU: `frontend_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`. **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. 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: `ui-nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx` ### 8.3 ÄNDERN: `frontend_nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx`
**Komplett neu.** Statt `NODE_CONFIG_REGISTRY`-Lookup: **Komplett neu.** Statt `NODE_CONFIG_REGISTRY`-Lookup:
@ -572,7 +572,7 @@ nodeType.parameters.map(param => {
}); });
``` ```
### 8.4 LÖSCHEN: `ui-nyla/src/components/FlowEditor/nodes/shared/outputPreviewRegistry.ts` ### 8.4 LÖSCHEN: `frontend_nyla/src/components/FlowEditor/nodes/shared/outputPreviewRegistry.ts`
Komplett entfernen. Ersetzen durch generische Funktion die aus dem `portTypeCatalog` + `outputPorts` Schema den Preview-Baum baut: 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: `ui-nyla/src/components/FlowEditor/nodes/shared/dataRef.ts` ### 8.5 ÄNDERN: `frontend_nyla/src/components/FlowEditor/nodes/shared/dataRef.ts`
**`DynamicValue` Union** (Zeile 20): erweitern um `SystemVarRef`: **`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. `isRef`, `isValue` etc. ergänzen um `isSystemVar` Type Guard.
### 8.6 ÄNDERN: `ui-nyla/src/components/FlowEditor/nodes/shared/DataPicker.tsx` ### 8.6 ÄNDERN: `frontend_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. - `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. - 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). - Neue Sektion **„System"** mit allen Variablen aus `systemVariables`, gruppiert (Datum/Zeit, User, Workflow).
- Bei Pick eines System-Werts: `onPick` liefert `SystemVarRef` statt `DataRef`. - Bei Pick eines System-Werts: `onPick` liefert `SystemVarRef` statt `DataRef`.
### 8.7 ÄNDERN: `ui-nyla/src/components/FlowEditor/context/Automation2DataFlowContext.tsx` ### 8.7 ÄNDERN: `frontend_nyla/src/components/FlowEditor/context/Automation2DataFlowContext.tsx`
- `Automation2DataFlowContextValue` (Zeile 1019): erweitern um `portTypeCatalog`, `systemVariables`. - `Automation2DataFlowContextValue` (Zeile 1019): erweitern um `portTypeCatalog`, `systemVariables`.
- `nodeOutputsPreview` Berechnung: aus Schema statt aus `outputPreviewRegistry`. - `nodeOutputsPreview` Berechnung: aus Schema statt aus `outputPreviewRegistry`.
### 8.8 ÄNDERN: `ui-nyla/src/components/FlowEditor/nodes/shared/graphUtils.ts` ### 8.8 ÄNDERN: `frontend_nyla/src/components/FlowEditor/nodes/shared/graphUtils.ts`
`fromApiGraph` / `toApiGraph`: `inputPorts` und `outputPorts` mitserialisieren in `CanvasNode`. `fromApiGraph` / `toApiGraph`: `inputPorts` und `outputPorts` mitserialisieren in `CanvasNode`.
### 8.9 ÄNDERN: `ui-nyla/src/components/FlowEditor/editor/FlowCanvas` (Verbindungs-Validierung) ### 8.9 ÄNDERN: `frontend_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). 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 | | Datei | Inhalt |
|-------|--------| |-------|--------|
| `platform-core/.../graphicalEditor/portTypes.py` | PortSchema, Katalog, Normalizer, Extraktoren, System-Variablen | | `gateway/.../graphicalEditor/portTypes.py` | PortSchema, Katalog, Normalizer, Extraktoren, System-Variablen |
| `platform-core/.../automation2/executors/dataExecutor.py` | Executor für data.aggregate, data.transform, data.filter | | `gateway/.../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 | | `gateway/.../nodeDefinitions/data.py` | Node-Definitionen: data.aggregate, data.transform, data.filter |
| `ui-nyla/.../nodes/frontendTypeRenderers/index.ts` | FRONTEND_TYPE_RENDERERS Registry | | `frontend_nyla/.../nodes/frontendTypeRenderers/index.ts` | FRONTEND_TYPE_RENDERERS Registry |
| `ui-nyla/.../nodes/frontendTypeRenderers/*.tsx` | Ein Renderer pro FrontendType | | `frontend_nyla/.../nodes/frontendTypeRenderers/*.tsx` | Ein Renderer pro FrontendType |
### Komplett neu geschriebene Dateien ### Komplett neu geschriebene Dateien
| Datei | Grund | | Datei | Grund |
|-------|-------| |-------|-------|
| `platform-core/.../automation2/executors/actionNodeExecutor.py` | Heuristische Merge-Logik → Normalizer + Extraktor | | `gateway/.../automation2/executors/actionNodeExecutor.py` | Heuristische Merge-Logik → Normalizer + Extraktor |
| `platform-core/.../nodeDefinitions/triggers.py` | + inputPorts, outputPorts, frontendType | | `gateway/.../nodeDefinitions/triggers.py` | + inputPorts, outputPorts, frontendType |
| `platform-core/.../nodeDefinitions/flow.py` | + flow.merge, Transit-Ports | | `gateway/.../nodeDefinitions/flow.py` | + flow.merge, Transit-Ports |
| `platform-core/.../nodeDefinitions/input.py` | + dynamische FormPayload-Schemas | | `gateway/.../nodeDefinitions/input.py` | + dynamische FormPayload-Schemas |
| `platform-core/.../nodeDefinitions/ai.py` | + AiResult-Ports, outputFormat-Param | | `gateway/.../nodeDefinitions/ai.py` | + AiResult-Ports, outputFormat-Param |
| `platform-core/.../nodeDefinitions/email.py` | + EmailDraft/EmailList-Ports | | `gateway/.../nodeDefinitions/email.py` | + EmailDraft/EmailList-Ports |
| `platform-core/.../nodeDefinitions/sharepoint.py` | + FileList/DocumentList-Ports | | `gateway/.../nodeDefinitions/sharepoint.py` | + FileList/DocumentList-Ports |
| `platform-core/.../nodeDefinitions/clickup.py` | + TaskList/TaskResult-Ports | | `gateway/.../nodeDefinitions/clickup.py` | + TaskList/TaskResult-Ports |
| `platform-core/.../nodeDefinitions/file.py` | + DocumentList-Ports | | `gateway/.../nodeDefinitions/file.py` | + DocumentList-Ports |
| `platform-core/.../nodeDefinitions/trustee.py` | + Ports | | `gateway/.../nodeDefinitions/trustee.py` | + Ports |
| `platform-core/.../nodeDefinitions/__init__.py` | + DATA_NODES Import | | `gateway/.../nodeDefinitions/__init__.py` | + DATA_NODES Import |
| `ui-nyla/.../editor/NodeConfigPanel.tsx` | Generischer Renderer statt NODE_CONFIG_REGISTRY | | `frontend_nyla/.../editor/NodeConfigPanel.tsx` | Generischer Renderer statt NODE_CONFIG_REGISTRY |
### Geänderte Dateien ### Geänderte Dateien
| Datei | Änderung | | Datei | Änderung |
|-------|----------| |-------|----------|
| `platform-core/.../shared/frontendTypes.py` | FrontendType Enum erweitern (+10 Werte) | | `gateway/.../shared/frontendTypes.py` | FrontendType Enum erweitern (+10 Werte) |
| `platform-core/.../automation2/graphUtils.py` | `resolveParameterReferences` + SystemVar, `validateGraph` + Port-Check | | `gateway/.../automation2/graphUtils.py` | `resolveParameterReferences` + SystemVar, `validateGraph` + Port-Check |
| `platform-core/.../automation2/executors/flowExecutor.py` | ifElse/switch → Transit-Envelope, + _merge | | `gateway/.../automation2/executors/flowExecutor.py` | ifElse/switch → Transit-Envelope, + _merge |
| `platform-core/.../automation2/executors/__init__.py` | + DataExecutor Export | | `gateway/.../automation2/executors/__init__.py` | + DataExecutor Export |
| `platform-core/.../automation2/executionEngine.py` | + DataExecutor, Transit-_meta, aggregate-Akkumulator, merge-Wartelogik | | `gateway/.../automation2/executionEngine.py` | + DataExecutor, Transit-_meta, aggregate-Akkumulator, merge-Wartelogik |
| `platform-core/.../graphicalEditor/nodeRegistry.py` | API-Response + portTypeCatalog, systemVariables | | `gateway/.../graphicalEditor/nodeRegistry.py` | API-Response + portTypeCatalog, systemVariables |
| `platform-core/.../graphicalEditor/routeFeatureGraphicalEditor.py` | Response-Struktur erweitern | | `gateway/.../graphicalEditor/routeFeatureGraphicalEditor.py` | Response-Struktur erweitern |
| `ui-nyla/.../api/workflowApi.ts` | Interfaces erweitern (inputPorts, outputPorts, frontendType) | | `frontend_nyla/.../api/workflowApi.ts` | Interfaces erweitern (inputPorts, outputPorts, frontendType) |
| `ui-nyla/.../nodes/shared/dataRef.ts` | + SystemVarRef | | `frontend_nyla/.../nodes/shared/dataRef.ts` | + SystemVarRef |
| `ui-nyla/.../nodes/shared/DataPicker.tsx` | Schema-basiert, Transit-Auflösung, System-Sektion | | `frontend_nyla/.../nodes/shared/DataPicker.tsx` | Schema-basiert, Transit-Auflösung, System-Sektion |
| `ui-nyla/.../nodes/shared/graphUtils.ts` | inputPorts/outputPorts serialisieren | | `frontend_nyla/.../nodes/shared/graphUtils.ts` | inputPorts/outputPorts serialisieren |
| `ui-nyla/.../context/Automation2DataFlowContext.tsx` | + portTypeCatalog, systemVariables | | `frontend_nyla/.../context/Automation2DataFlowContext.tsx` | + portTypeCatalog, systemVariables |
| `ui-nyla/.../editor/FlowCanvas` | Verbindungs-Validierung | | `frontend_nyla/.../editor/FlowCanvas` | Verbindungs-Validierung |
### Gelöschte Dateien ### Gelöschte Dateien
| Datei | Grund | | Datei | Grund |
|-------|-------| |-------|-------|
| `ui-nyla/.../nodes/configs/index.ts` | Ersetzt durch FRONTEND_TYPE_RENDERERS | | `frontend_nyla/.../nodes/configs/index.ts` | Ersetzt durch FRONTEND_TYPE_RENDERERS |
| `ui-nyla/.../nodes/configs/AiNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/AiNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/EmailNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/EmailNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/SharePointNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/SharePointNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ClickUpNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/ClickUpNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ApprovalNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/ApprovalNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/UploadNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/UploadNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/CommentNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/CommentNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ReviewNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/ReviewNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/SelectionNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/SelectionNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/ConfirmationNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/ConfirmationNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/FileCreateNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/FileCreateNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/configs/TrusteeNodeConfig.tsx` | Generischer Renderer | | `frontend_nyla/.../nodes/configs/TrusteeNodeConfig.tsx` | Generischer Renderer |
| `ui-nyla/.../nodes/shared/outputPreviewRegistry.ts` | Schema-basierte Preview | | `frontend_nyla/.../nodes/shared/outputPreviewRegistry.ts` | Schema-basierte Preview |

View file

@ -1,7 +1,7 @@
<!-- status: build --> <!-- status: build -->
<!-- started: 2026-04-16 --> <!-- started: 2026-04-16 -->
<!-- lastReviewed: 2026-04-24 --> <!-- lastReviewed: 2026-04-24 -->
<!-- component: gateway | platform | ui-nyla --> <!-- component: gateway | platform | frontend-nyla -->
# Unified Knowledge Indexing — One RAG Corpus for All Platform Information # 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. 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/platform-core/architecture.md`) ### Terminology (Gateway — see `wiki/b-reference/gateway/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`). 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** ### 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 `platform-core/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 `gateway/modules/connectors/` (e.g. **`providerMsft`**, **`providerGoogle`**, **`providerClickup`**); that mapping is **technical**, not the product wording.
**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. **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.
**Cross-cutting rules (every user-added connection):** **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). **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 (`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. **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.
#### UX when adding a connection #### 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) ### 3.3 Summary matrix (per `modules/features/` domain)
*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. *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.
| Feature | **`AgentService.runAgent`** | **Retrieval injection** (platform RAG prompt) | **Corpus injection** (typical today) | **Likely gap** (this document) | | 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`**. | | **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`. | | **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. | | **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; **`ui-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; **`frontend_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. | | **~~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. | | **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] **`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] **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] **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** (`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`. - [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`.
**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. **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/`. - **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**. - **Interfaces:** `interfaceDbKnowledge` extensions for source metadata if needed; **`interfaceDbApp`** (or adjacent) for **per-`connectionId`** ingestion preferences from **§2.6**.
- **Frontend:** `ui-nyla` — connection wizard + connection detail settings (consent, depth toggles, neutralization, time window). - **Frontend:** `frontend_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. - **Wiki / Reference:** `b-reference/gateway/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 ## Links
- **How-to / orientation:** [Unified knowledge & RAG ingestion (guide)](../../d-guides/unified-knowledge-rag.md) - **How-to / orientation:** [Unified knowledge & RAG ingestion (guide)](../../d-guides/unified-knowledge-rag.md)
- **Gateway reference (retrieval + knowledge):** `wiki/b-reference/platform-core/architecture.md`, `wiki/b-reference/platform-core/ai-agent.md` - **Gateway reference (retrieval + knowledge):** `wiki/b-reference/gateway/architecture.md`, `wiki/b-reference/gateway/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]`). - **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):** `platform-core/tests/unit/services/test_ingestion_hash_stability.py`, `platform-core/tests/unit/services/test_extraction_merge_strategy.py`. - **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):** `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 (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`.
- **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. - **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:** `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). - **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).
## Akzeptanzkriterien (Plan-Ebene) ## 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 (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-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) --> <!-- pivoted: 2026-04-29 (kDrive-Listing fuer non-admin-User leer -> `/2/drive/init?with=drives` als Discovery) -->
<!-- component: gateway, ui-nyla --> <!-- component: gateway, frontend-nyla -->
# Infomaniak Connector (kDrive + Calendar + Contacts today; Mail reserved) + UDB-Integration # 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/routeSecurityInfomaniak.py` (komplett neu: PAT-Submit-Endpoint)
- `modules/routes/routeDataConnections.py` (`connect_service` antwortet bei - `modules/routes/routeDataConnections.py` (`connect_service` antwortet bei
Infomaniak mit 400 + Hinweis) Infomaniak mit 400 + Hinweis)
- `platform-core/.env` + `env_dev/int/prod[_forgejo].env` (Service_INFOMANIAK_* raus) - `gateway/.env` + `env_dev/int/prod[_forgejo].env` (Service_INFOMANIAK_* raus)
- Frontend: - Frontend:
- `src/api/connectionApi.ts` (`submitInfomaniakToken` neu) - `src/api/connectionApi.ts` (`submitInfomaniakToken` neu)
- `src/hooks/useConnections.ts` (`createInfomaniakConnection` + - `src/hooks/useConnections.ts` (`createInfomaniakConnection` +

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
<!-- status: plan --> <!-- status: plan -->
<!-- started: 2026-04-07 --> <!-- started: 2026-04-07 -->
<!-- component: ui-nyla | platform --> <!-- component: frontend-nyla | platform -->
# PORTA UI-Enhancements (Team-Meeting Inputs, 2026-04-07) # 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. - **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. - **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). - **DB-Migration:** nein (voraussichtlich).
- **Platform / Wiki:** nach Release `b-reference/ui-nyla/architecture.md` oder `platform/navigation.md` bei Routing-Änderungen. - **Platform / Wiki:** nach Release `b-reference/frontend-nyla/architecture.md` oder `platform/navigation.md` bei Routing-Änderungen.
--- ---
## Codebase-Audit (Ist-Zustand, `ui-nyla`) ## Codebase-Audit (Ist-Zustand, `frontend_nyla`)
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). 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).
### Bereits vorhanden (positiv) ### 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 | | 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` | | 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 | `platform-core` `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 | `gateway` `NAVIGATION_SECTIONS` / `mainSystem.py` (siehe Wiki navigation.md) |
### Phase E — Feinschliff (laufend) ### 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 | | 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/` | | E2 | i18n: alle neuen Strings in `locales/` |
| E3 | Nach Merge: `b-reference/ui-nyla/architecture.md` um Workspace-UX-Notizen ergänzen | | E3 | Nach Merge: `b-reference/frontend-nyla/architecture.md` um Workspace-UX-Notizen ergänzen |
### Abhängigkeiten & Risiken ### Abhängigkeiten & Risiken
@ -159,7 +159,7 @@ Ziele: Issues I1I9 adressieren, **ohne** Billing-Logik oder Gateway-Tarife ne
| Datum | Entscheidung | Begründung | | 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 | 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 `ui-nyla` — Umsetzung in Phasen AE | Issues I1I9 und bestehende Bausteine im Dokument festgehalten | | 2026-04-07 | Codebase-Audit gegen `frontend_nyla` — Umsetzung in Phasen AE | Issues I1I9 und bestehende Bausteine im Dokument festgehalten |
*Weitere Einträge nach UX-Review und Abstimmung Partner/Hosting-Formulierung.* *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` - [ ] E1: optional File-Drop auf Prompt synchron zu `WorkspacePage`
- [ ] E2: `locales/*` für neue Strings - [ ] E2: `locales/*` für neue Strings
- [ ] E3: Wiki `b-reference/ui-nyla/architecture.md` aktualisieren - [ ] E3: Wiki `b-reference/frontend-nyla/architecture.md` aktualisieren
**Querschnitt** **Querschnitt**
@ -221,7 +221,7 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1,2 | e2e / manuell Viewports | teilweise | `ui-nyla` — `WorkspacePage.tsx` bei 1100/1200/1280/1440px | pending | | T1 | 1,2 | e2e / manuell Viewports | teilweise | `frontend_nyla` — `WorkspacePage.tsx` bei 1100/1200/1280/1440px | pending |
| T2 | 3 | manuell UX-Review | nein | — | pending | | T2 | 3 | manuell UX-Review | nein | — | pending |
| T3 | 4 | manuell Rolle Admin | nein | — | pending | | T3 | 4 | manuell Rolle Admin | nein | — | pending |
| T4 | 5,6 | manuell Explorer/Safari/Edge | 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) - Input: [input2026-04-ui-enhancement-inbputs.txt](./input2026-04-ui-enhancement-inbputs.txt)
- Produkt-Überblick: [README.md](../../README.md) - Produkt-Überblick: [README.md](../../README.md)
- Frontend-Referenz: [b-reference/ui-nyla/architecture.md](../../b-reference/ui-nyla/architecture.md) - Frontend-Referenz: [b-reference/frontend-nyla/architecture.md](../../b-reference/frontend-nyla/architecture.md)
- Navigation API: [b-reference/platform/navigation.md](../../b-reference/platform/navigation.md) - Navigation API: [b-reference/platform/navigation.md](../../b-reference/platform/navigation.md)
- Billing (Backend-Kontext): [b-reference/platform-core/billing.md](../../b-reference/platform-core/billing.md) - Billing (Backend-Kontext): [b-reference/gateway/billing.md](../../b-reference/gateway/billing.md)
- Compliance (Copy-Grundlage): [e-compliance/security-overview.md](../../e-compliance/security-overview.md) - Compliance (Copy-Grundlage): [e-compliance/security-overview.md](../../e-compliance/security-overview.md)
**Code (Haupt-Einstiegspunkte, Repo `ui-nyla`)** **Code (Haupt-Einstiegspunkte, Repo `frontend_nyla`)**
- `src/pages/views/workspace/WorkspacePage.tsx` — Layout, Mobile, Drag-Drop, UDB - `src/pages/views/workspace/WorkspacePage.tsx` — Layout, Mobile, Drag-Drop, UDB
- `src/pages/views/workspace/WorkspaceInput.tsx` — Prompt, Anhänge, STT - `src/pages/views/workspace/WorkspaceInput.tsx` — Prompt, Anhänge, STT
@ -251,6 +251,6 @@ Die detaillierte Aufgabenzerlegung steht in **Umsetzungsplan** (Phasen AE). H
## Abschluss ## Abschluss
- [ ] b-reference/ aktualisiert (`ui-nyla/architecture.md`, ggf. `platform/navigation.md`) - [ ] b-reference/ aktualisiert (`frontend-nyla/architecture.md`, ggf. `platform/navigation.md`)
- [ ] TOPICS.md aktualisiert (falls neues Thema «Trust-UI» o. ä.) - [ ] TOPICS.md aktualisiert (falls neues Thema «Trust-UI» o. ä.)
- [ ] Dieses Dokument → `z-archive/` verschoben (nach Release) - [ ] 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) --> <!-- status: build (Phase 1, 3, 4, 5, 6, 2-toolbar done; FilesTab integration deferred) -->
<!-- started: 2026-04-16 --> <!-- started: 2026-04-16 -->
<!-- updated: 2026-04-19 --> <!-- updated: 2026-04-19 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
<!-- relatedTo: c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md (1.9c) --> <!-- relatedTo: c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md (1.9c) -->
# PWG-Pilot: Jahresmietzinsbestätigungs-Workflow + Workflow-File-IO # 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). - `pages/views/workflow/` (Graph-Editor-View) — Buttons "Aus Datei importieren" + "Als Datei exportieren" (Editor-Toolbar).
- `api/workflowApi.ts` (oder analog) — neue Endpoint-Wrapper. - `api/workflowApi.ts` (oder analog) — neue Endpoint-Wrapper.
- **DB-Migration:** **nein**. - **DB-Migration:** **nein**.
- **Repo-Asset:** `platform-core/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` (NEU). - **Repo-Asset:** `gateway/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-Config:** `gateway/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). - **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 `platform-core/modules/features/trustee/promptTemplates/_pwgMietzinsCheck.py` oder direkt im Workflow-File (Decision unten). - **Andere:** Step-5-Prompt-Template als Konstante in `gateway/modules/features/trustee/promptTemplates/_pwgMietzinsCheck.py` oder direkt im Workflow-File (Decision unten).
## Entscheidungen ## 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 | 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 | 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) | 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 `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) | 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 `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) | 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) | Pilot-Workflow wird beim `load()` automatisch importiert (active=false) | Demo-User klickt nach Bootstrap nur noch "Manueller Trigger" — minimaler Klickpfad zum Wow-Effekt | | 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 ## Pilot-Workflow: Inhalt
### Datei: `platform-core/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json` ### Datei: `gateway/demoData/workflows/pwg-mietzinsbestaetigung-pilot.workflow.json`
**Knoten-Übersicht (10 Nodes — basierend auf real verfügbaren Nodes nach Codebase-Audit):** **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. - ✅ `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)** **Sub-Task 4a — Neuer Node `trustee.queryData`: ✅ DONE (2026-04-19)**
- [x] Definition in `platform-core/modules/features/graphicalEditor/nodeDefinitions/trustee.py` ergänzt (Pattern wie `trustee.refreshAccountingData`). - [x] Definition in `gateway/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). - 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" } }`. - Inputs: 1, Outputs: 1, `outputPorts: { 0: { schema: "QueryResult" } }`.
- `_method: "trustee"`, `_action: "queryData"`. - `_method: "trustee"`, `_action: "queryData"`.
- [x] Action-Implementierung `platform-core/modules/workflows/methods/methodTrustee/actions/queryData.py`: - [x] Action-Implementierung `gateway/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 `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 `raw` → liest direkt aus den 5 Trustee-Tabellen (Filter via `filterJson`).
- Mode `aggregate` → Sum/Count über JournalLines, gruppiert per `groupBy` aus `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)** **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 `nodeDefinitions/email.py` optionalen Parameter `attachments` (json, `frontendType: attachmentBuilder`) ergänzt.
- [x] In `platform-core/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py` Attachment-Handling implementiert (Helper `_resolveAttachmentSpec`): - [x] In `gateway/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. - `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`. - `csvFromVariable` → Shorthand für CSV-Ref, hängt `.csv` an, MIME `text/csv`.
- `base64Content` → direkt verwendet, MIME aus `mimeType` oder Default. - `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) ### Phase 5 — Pilot-Workflow als File ✅ DONE (2026-04-19)
- [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] 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] Lokale Validierung gegen `validateFileEnvelope()` — keine Errors, keine Warnungen. - [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 — 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. - [ ] **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. **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:** `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] **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] **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] **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:** `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] **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] **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] **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:** `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] **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] **6f — `remove()`-Pfad:** Spiegelbildlich, löscht Workflow-Records, Trustee-Seed (Lines/Entries/Contacts/Accounts), Memberships, Feature-Instances, User, Mandant. - [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. - [ ] **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) ### 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: `platform-core/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: `gateway/modules/demoConfigs/pwgDemo2026.py` `_USER` + `credentials`-Klassenattribut).
2. Mandanten-Wechsler oben links → **„Stiftung PWG"** auswählen. 2. Mandanten-Wechsler oben links → **„Stiftung PWG"** auswählen.
3. Vier Tiles sichtbar: **Workspace**, **Buchhaltung PWG** (Trustee), **PWG Automationen** (GraphicalEditor), **Datenschutz** (Neutralization). 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`). 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: 2. Property-Panel der Nodes prüfen:
- `sharepoint.listFiles` Source-Folder auf einen erreichbaren SharePoint-/OneDrive-Ordner setzen. - `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). - `email.draftEmail` Connection auf den eigenen Outlook-Account, Empfänger auf eigene Adresse setzen (Demo-Mail an sich selbst).
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. 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.
4. Workflow oben rechts auf **„Aktiv"** schalten → Button **„Manuell ausführen"** klicken. 4. Workflow oben rechts auf **„Aktiv"** schalten → Button **„Manuell ausführen"** klicken.
5. Run-Detail-Seite zeigt Step-by-Step-Logs: 5. Run-Detail-Seite zeigt Step-by-Step-Logs:
- 3 Loop-Durchläufe (1 pro PDF). - 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1, 4 | unit | ja | `platform-core/tests/unit/workflow/test_workflowFileSchema.py` (17 Tests, deckt Round-Trip + Field-Stripping + Envelope-Validierung ab) | done | | 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 | `platform-core/tests/integration/graphicalEditor/test_workflow_import.py` | abgedeckt durch T1 (Schema-Layer) + T3 (Tool-Layer); separater Route-Test deferred bis Bedarf | | 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 | `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 | | 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 |
| T4 | 7, 8, 9, 13 | e2e | manuell | PWG-Demo-Instanz mit 3 Test-Scans (über `pwgDemo2026.load()` gebootstrappt) | pending | | 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 | | T5 | 1, 2 | manuell UI | nein | Frontend FilesTab + Graph-Editor in lokaler Dev-Umgebung | pending |
| 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) | | 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) |
## Links ## Links
- Quellplan (0-ideas): `wiki/c-work/0-ideas/2026-04-pm-consolidated-customer-requirements.md` (Abschnitt 1.9c) - 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` - PWG-Workshop-Inputs: `pamocreate/projects/poweron/customer-pwg/20260415-inputs-pwg.txt`
- Graph-Editor Models: `platform-core/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py` - Graph-Editor Models: `gateway/modules/features/graphicalEditor/datamodelFeatureGraphicalEditor.py`
- Graph-Editor Routes: `platform-core/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py` - Graph-Editor Routes: `gateway/modules/features/graphicalEditor/routeFeatureGraphicalEditor.py`
- System-Templates Bootstrap: `platform-core/modules/interfaces/interfaceBootstrap.py` (`_buildSystemTemplates`) - System-Templates Bootstrap: `gateway/modules/interfaces/interfaceBootstrap.py` (`_buildSystemTemplates`)
- Agent Workflow-Tools: `platform-core/modules/serviceCenter/services/serviceAgent/workflowTools.py` - Agent Workflow-Tools: `gateway/modules/serviceCenter/services/serviceAgent/workflowTools.py`
- Toolbox-Registry: `platform-core/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py` - Toolbox-Registry: `gateway/modules/serviceCenter/services/serviceAgent/toolboxRegistry.py`
- UDB Files-Tab: `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx` - UDB Files-Tab: `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
- File-Upload-Route: `platform-core/modules/routes/routeDataFiles.py` - File-Upload-Route: `gateway/modules/routes/routeDataFiles.py`
- Trustee-Modelle: `platform-core/modules/features/trustee/datamodelFeatureTrustee.py` - Trustee-Modelle: `gateway/modules/features/trustee/datamodelFeatureTrustee.py`
- Abacus-Connector: `platform-core/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py` - Abacus-Connector: `gateway/modules/features/trustee/accounting/connectors/accountingConnectorAbacus.py`
- Feature-Sub-Agent: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py` - Feature-Sub-Agent: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`
- Demo-Config-Basis: `platform-core/modules/demoConfigs/_baseDemoConfig.py` - Demo-Config-Basis: `gateway/modules/demoConfigs/_baseDemoConfig.py`
- Investor-Demo-Vorlage: `platform-core/modules/demoConfigs/investorDemo2026.py` - Investor-Demo-Vorlage: `gateway/modules/demoConfigs/investorDemo2026.py`
- Demo-Config Auto-Discovery: `platform-core/modules/demoConfigs/__init__.py` - Demo-Config Auto-Discovery: `gateway/modules/demoConfigs/__init__.py`
- Demo-Config-Routen: `platform-core/modules/routes/routeAdminDemoConfig.py` - Demo-Config-Routen: `gateway/modules/routes/routeAdminDemoConfig.py`
- Bestehende Demo-Tests: `platform-core/tests/demo/test_demo_bootstrap.py` - Bestehende Demo-Tests: `gateway/tests/demo/test_demo_bootstrap.py`
- PR: ... - PR: ...
- Issue: ... - Issue: ...
## Abschluss ## Abschluss
- [ ] `b-reference/platform-core/architecture.md` ergänzen (Workflow-File-IO Sektion) - [ ] `b-reference/gateway/architecture.md` ergänzen (Workflow-File-IO Sektion)
- [ ] `b-reference/ui-nyla/architecture.md` ergänzen (FilesTab Workflow-Handling) - [ ] `b-reference/frontend-nyla/architecture.md` ergänzen (FilesTab Workflow-Handling)
- [ ] `TOPICS.md` ergänzen (neues Thema "Workflow Portability") - [ ] `TOPICS.md` ergänzen (neues Thema "Workflow Portability")
- [ ] PWG-Pilot-Workflow-Datei in `platform-core/demoData/workflows/` committed und im Demo-Config (`pwgDemo2026.py`) automatisch importiert (siehe Phase 6d) - [ ] PWG-Pilot-Workflow-Datei in `gateway/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 - [ ] 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 - [ ] Dieses Dokument → `c-work/2-build/` verschieben sobald Phase 1 startet

View file

@ -1,6 +1,6 @@
<!-- status: plan --> <!-- status: plan -->
<!-- started: 2026-04-21 --> <!-- started: 2026-04-21 -->
<!-- component: gateway, ui-nyla --> <!-- component: gateway, frontend-nyla -->
# Redmine Feature -- Ticket-Topologie, Browser, AI-Tools, Workflow-Nodes # 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. - **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. - **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"). - **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 `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`. - **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`.
- **Pro Feature-Instanz** eine Verbindung: `redmineBaseUrl`, `apiKey` (encrypted), `projectId`, optional Whitelist-Tracker / Default-Custom-Fields. Mehrere Instanzen pro Mandat möglich. - **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. - **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). - **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:** - **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. - **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:** - **Andere:**
- `wiki/b-reference/platform-core/features/redmine.md` (NEU, beim Done) - `wiki/b-reference/gateway/features/redmine.md` (NEU, beim Done)
- `wiki/TOPICS.md` Eintrag (beim Done) - `wiki/TOPICS.md` Eintrag (beim Done)
## Entscheidungen ## 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) - [ ] Tests: Unit-Tests für Connector (Mock-Server), Integration-Tests gegen einen lokalen Redmine-Sandbox (oder VCR-Cassette)
### Phase 4 -- Doku & Cleanup ### Phase 4 -- Doku & Cleanup
- [ ] `wiki/b-reference/platform-core/features/redmine.md` neu anlegen (mit Sektion "Statistik-Aggregationen") - [ ] `wiki/b-reference/gateway/features/redmine.md` neu anlegen (mit Sektion "Statistik-Aggregationen")
- [ ] `wiki/TOPICS.md` Eintrag - [ ] `wiki/TOPICS.md` Eintrag
- [ ] Pilot-Skript-Doku (`redmine-sync`) ergänzen: "→ produktiv via PORTA-Feature 'redmine'" - [ ] Pilot-Skript-Doku (`redmine-sync`) ergänzen: "→ produktiv via PORTA-Feature 'redmine'"
- [ ] Plan-Dokument nach `c-work/4-done/` verschieben - [ ] 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | live-integration | ja (`mark.live`) | platform-core/tests/test_connector_redmine_live.py (whoAmI, getProjectMeta, getIssue, listIssues paginated) | pending | | T1 | 1 | live-integration | ja (`mark.live`) | gateway/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 | | T2 | 1 | api | ja | gateway/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 | | 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`) | platform-core/tests/test_route_redmine_update_live.py (Read-modify-write Round-trip) | 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 | platform-core/tests/test_service_redmine_stats.py (Period-Filter, Tracker-Filter, Bucket-Aggregation auf Fixture-JSON) | 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 | platform-core/tests/test_redmine_tools.py (`mark.live` für Write-Tools) | pending | | T6 | 5,6,12 | integration | ja | gateway/tests/test_redmine_tools.py (`mark.live` für Write-Tools) | pending |
| T7 | 7 | integration | ja | platform-core/tests/test_method_redmine.py | pending | | T7 | 7 | integration | ja | gateway/tests/test_method_redmine.py | pending |
| T8 | 8 | api | ja | platform-core/tests/test_route_redmine_delete.py (Soft-Delete-Mapping + Toast-Message) | pending | | T8 | 8 | api | ja | gateway/tests/test_route_redmine_delete.py (Soft-Delete-Mapping + Toast-Message) | pending |
| T9 | 9 | ui | manuell | -- | pending | | T9 | 9 | ui | manuell | -- | pending |
| T10 | 10 | api | ja | platform-core/tests/test_route_redmine_rbac.py | pending | | T10 | 10 | api | ja | gateway/tests/test_route_redmine_rbac.py | pending |
| T11 | 4 | ui | manuell | -- (PeriodPicker-Round-trip in Stats) | pending | | T11 | 4 | ui | manuell | -- (PeriodPicker-Round-trip in Stats) | pending |
| T12 | 13 | unit | ja | platform-core/tests/test_service_redmine_stats.py::test_unassigned_bucket | pending | | T12 | 13 | unit | ja | gateway/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 | | T13 | -- | unit | ja | gateway/tests/test_service_redmine_stats_cache.py (TTL, Hit/Miss, Invalidierung bei Write) | pending |
## Links ## 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` - HTML-Pilot (Phase 0, **erledigt**): `poweron/local/notes/redmine-pilot/index.html`
- Pilot-Doku: `poweron/local/notes/redmine-pilot/README.md` - Pilot-Doku: `poweron/local/notes/redmine-pilot/README.md`
- Redmine REST-API: <https://www.redmine.org/projects/redmine/wiki/Rest_api> - Redmine REST-API: <https://www.redmine.org/projects/redmine/wiki/Rest_api>
- Vergleichs-Connector: `platform-core/modules/connectors/connectorTicketsJira.py` - Vergleichs-Connector: `gateway/modules/connectors/connectorTicketsJira.py`
- Vergleichs-Method: `platform-core/modules/workflows/methods/methodJira/methodJira.py` - Vergleichs-Method: `gateway/modules/workflows/methods/methodJira/methodJira.py`
- Vergleichs-Feature: `platform-core/modules/features/trustee/` (Config pro Instanz, Tools) - Vergleichs-Feature: `gateway/modules/features/trustee/` (Config pro Instanz, Tools)
- Bestehende Komponenten -- **wiederverwenden, nicht neubauen**: - Bestehende Komponenten -- **wiederverwenden, nicht neubauen**:
- `ui-nyla/src/components/PeriodPicker/` (Zeitraum-Auswahl mit Presets) - `frontend_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`) - `frontend_nyla/src/components/FormGenerator/FormGeneratorReport/` (Stats-Page-Renderer mit Charts via Recharts; akzeptiert PeriodPicker via `dateRangeSelector`)
- `platform-core/modules/shared/dateRange.py` (`parseIsoDateRange`, `isoDateRangeToLocalEpoch`) - `gateway/modules/shared/dateRange.py` (`parseIsoDateRange`, `isoDateRangeToLocalEpoch`)
- Stats-Vorbild im Code (Pattern für `serviceRedmineStats`): `platform-core/modules/workflows/methods/methodTrustee/actions/queryData.py` - Stats-Vorbild im Code (Pattern für `serviceRedmineStats`): `gateway/modules/workflows/methods/methodTrustee/actions/queryData.py`
## Kritischer Review (Pre-Execution) ## 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. → ✅ **Plan ist executionsbereit.** Phase 1 kann starten.
### G. Phase-1 Start-Sequenz (operative Reihenfolge) ### G. Phase-1 Start-Sequenz (operative Reihenfolge)
1. `platform-core/modules/features/redmine/datamodelRedmine.py` -- Pydantic-Modelle, **inkl.** `RedmineStatsDto` mit Roh-Bucket-Substrukturen 1. `gateway/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 2. `gateway/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 3. T1 (Live-Connector-Tests) parallel mit (2) -- Tests treiben Connector-API-Form
4. Helper-Skript `platform-core/tests/fixtures/captureRedmineSnapshot.py` -- ruft `listIssues` einmalig live, schreibt JSON-Fixture für Service-/Stats-Unit-Tests 4. Helper-Skript `gateway/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` 5. `serviceRedmine.py` (Idempotenz, Throttle) + `serviceRedmineStats.py` (Aggregationen) + `serviceRedmineStatsCache.py`
6. T3, T5, T12, T13 (Unit auf Fixture) 6. T3, T5, T12, T13 (Unit auf Fixture)
7. DB-Migration + `interfaceFeatureRedmine.py` (Config-Persistenz, Schema-Cache) 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 ## Abschluss
- [ ] `wiki/b-reference/platform-core/features/redmine.md` aktualisiert (NEU anlegen) - [ ] `wiki/b-reference/gateway/features/redmine.md` aktualisiert (NEU anlegen)
- [ ] `wiki/TOPICS.md` aktualisiert (Eintrag "Redmine Feature") - [ ] `wiki/TOPICS.md` aktualisiert (Eintrag "Redmine Feature")
- [ ] Dieses Dokument → `z-archive/` verschoben - [ ] Dieses Dokument → `z-archive/` verschoben

View file

@ -1,7 +1,7 @@
<!-- status: done --> <!-- status: done -->
<!-- started: 2026-04-17 --> <!-- started: 2026-04-17 -->
<!-- finished: 2026-04-17 --> <!-- finished: 2026-04-17 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
# SysAdmin-Authority-Modell konsolidieren: Flag + Rolle → zwei klar getrennte Flags # SysAdmin-Authority-Modell konsolidieren: Flag + Rolle → zwei klar getrennte Flags
@ -212,81 +212,81 @@ after:
| Datei | Was | Änderung | | Datei | Was | Änderung |
| --------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------ | | --------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| `platform-core/modules/datamodels/datamodelUam.py` | `User` Pydantic + `UserInDB` | Neues Feld `isPlatformAdmin: bool = False` + Validator | | `gateway/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") | | `gateway/modules/datamodels/datamodelUam.py` | Docstring `isSysAdmin` | Neue Semantik („Infrastructure/System Operator") |
### Backend — Auth ### Backend — Auth
| Datei | Was | Änderung | | Datei | Was | Änderung |
| --------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------- | | --------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------- |
| `platform-core/modules/auth/authentication.py` | `_hasSysAdminRole`, `requireSysAdminRole`, `_getRootMandateRoleIds` | **Löschen** (bzw. als deprecated Stub behalten für transitional Phase) | | `gateway/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** | | `gateway/modules/auth/authentication.py` | `RequestContext.hasSysAdminRole` | **Löschen** |
| `platform-core/modules/auth/authentication.py` | `RequestContext.isPlatformAdmin` (neu) | Property | | `gateway/modules/auth/authentication.py` | `RequestContext.isPlatformAdmin` (neu) | Property |
| `platform-core/modules/auth/authentication.py` | `requirePlatformAdmin` (neu) | Dependency | | `gateway/modules/auth/authentication.py` | `requirePlatformAdmin` (neu) | Dependency |
| `platform-core/modules/auth/__init__.py` | Exporte | `requirePlatformAdmin` exportieren | | `gateway/modules/auth/__init__.py` | Exporte | `requirePlatformAdmin` exportieren |
### Backend — Bootstrap ### Backend — Bootstrap
| Datei | Was | Änderung | | Datei | Was | Änderung |
| ----------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------ | | ----------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------ |
| `platform-core/modules/interfaces/interfaceBootstrap.py` | `_initSysAdminRole` + `_createSysAdminAccessRules` + `_ensureSysAdminAccessRules` | **Löschen** (inkl. aller damit verbundener AccessRules) | | `gateway/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` | | `gateway/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 | | `gateway/modules/interfaces/interfaceBootstrap.py` | Neu: `_migrateSysAdminRoleToPlatformAdminFlag()` | Einmalige Migration beim Boot; idempotent |
### Backend — Routen (alle Callsites von `hasSysAdminRole` / `requireSysAdminRole`) ### Backend — Routen (alle Callsites von `hasSysAdminRole` / `requireSysAdminRole`)
| Datei | Callsites | Änderung | | Datei | Callsites | Änderung |
| --------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | | --------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `platform-core/modules/routes/routeDataUsers.py` | Z.106, 159, 236, 325, 445, 517, 571, 586, 919 | `hasSysAdminRole``isPlatformAdmin` | | `gateway/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) | | `gateway/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) | | `gateway/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` | | `gateway/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** | | `gateway/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` | | `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` |
| `platform-core/modules/routes/routeAdminFeatures.py` | 22 Stellen | analog | | `gateway/modules/routes/routeAdminFeatures.py` | 22 Stellen | analog |
| `platform-core/modules/routes/routeAdminUserAccessOverview.py` | Z.78, 126, 220 | analog | | `gateway/modules/routes/routeAdminUserAccessOverview.py` | Z.78, 126, 220 | analog |
| `platform-core/modules/routes/routeAdminDatabaseHealth.py` | Z.44, 56, 68, 93 | bleibt `requireSysAdmin` (Infrastruktur) | | `gateway/modules/routes/routeAdminDatabaseHealth.py` | Z.44, 56, 68, 93 | bleibt `requireSysAdmin` (Infrastruktur) |
| `platform-core/modules/routes/routeAdminLogs.py` | Z.66, 107 | bleibt `requireSysAdmin` (Infrastruktur) | | `gateway/modules/routes/routeAdminLogs.py` | Z.66, 107 | bleibt `requireSysAdmin` (Infrastruktur) |
| `platform-core/modules/routes/routeAdminDemoConfig.py` | Z.28, 44, 69 | `isPlatformAdmin` (Data-Change-Operation) | | `gateway/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 | | `gateway/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`| | `gateway/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` | | `gateway/modules/routes/routeSubscription.py` | Z.49, 306, 488 | `isPlatformAdmin` |
| `platform-core/modules/routes/routeInvitations.py` | Z.189, 894 | `isPlatformAdmin` | | `gateway/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 | | `gateway/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) | | `gateway/modules/routes/routeAudit.py` | Z.134 | `isPlatformAdmin` (Cross-Mandate-Audit) |
| `platform-core/modules/routes/routeNotifications.py` | 518 | unverändert (`addRoleToUserMandate` betrifft keine sysadmin mehr) | | `gateway/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) | | `gateway/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 | | `gateway/modules/routes/routeDataSources.py` | Z.10, 56 | analog |
| `platform-core/modules/routes/routeWorkflowDashboard.py` | 9 Stellen | Cross-Mandate-Übersicht → `isPlatformAdmin` | | `gateway/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`) | | `gateway/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` | | `gateway/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` | | `gateway/modules/features/chatbot/routeFeatureChatbot.py` | Z.105 | `isPlatformAdmin` |
| `platform-core/modules/features/realEstate/routeFeatureRealEstate.py` | Z.119 | `isPlatformAdmin` | | `gateway/modules/features/realEstate/routeFeatureRealEstate.py` | Z.119 | `isPlatformAdmin` |
| `platform-core/modules/routes/routeRealEstate.py` | Z.124 | `isPlatformAdmin` | | `gateway/modules/routes/routeRealEstate.py` | Z.124 | `isPlatformAdmin` |
| `platform-core/modules/features/workspace/...` | (suchen) | pro Callsite prüfen | | `gateway/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) | | `gateway/modules/interfaces/interfaceDbManagement.py` | Z.637643 `_isSysAdmin` | Bleibt an Flag gebunden (RBAC-Bypass in Data-Management) |
### Backend — Services / Demo / Tests ### Backend — Services / Demo / Tests
| Datei | Was | Änderung | | Datei | Was | Änderung |
| -------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------- | | -------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------- |
| `platform-core/modules/demoConfigs/investorDemo2026.py` | Z.188, 222 | `isPlatformAdmin=True` statt Rolle; `isSysAdmin` wie gehabt | | `gateway/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 | | `gateway/modules/serviceCenter/services/serviceAgent/...` | Z.568 | Liest Flag — kein Change |
| `platform-core/tests/**` | alle `hasSysAdminRole`/`requireSysAdminRole` Mentions | Tests anpassen | | `gateway/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` | | | `gateway/tests/integration/rbac/test_sysadmin_sync.py` (geplant Phase 1) | **entfällt** bzw. wird zu `test_platform_admin_flag.py` | |
### Frontend ### Frontend
| Datei | Was | Änderung | | Datei | Was | Änderung |
| --------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- | | --------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- |
| `ui-nyla/src/types/mandate.ts` | User-Typ Z.143 | `isPlatformAdmin: boolean` ergänzen | | `frontend_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 | | `frontend_nyla/src/api/userApi.ts` / `authApi.ts` | User-Schema | `isPlatformAdmin?: boolean` ergänzen |
| `ui-nyla/src/utils/userCache.ts` | User-Cache | `isPlatformAdmin` ergänzen | | `frontend_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 | | `frontend_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 | | `frontend_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 | | `frontend_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 | | `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 |
| `ui-nyla/src/hooks/useUsers.ts` | Z.35, 39, 74, 88, 92, 218, 222 | Beide Flags mitgeben | | `frontend_nyla/src/hooks/useUsers.ts` | Z.35, 39, 74, 88, 92, 218, 222 | Beide Flags mitgeben |
## Entscheidungen ## Entscheidungen
@ -379,13 +379,13 @@ after:
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
| --- | ---- | ------------------------ | ------------- | ------------------------------------------------------------------ | ------- | | --- | ---- | ------------------------ | ------------- | ------------------------------------------------------------------ | ------- |
| T1 | 1 | api-integration | ja | `platform-core/tests/integration/rbac/test_platform_admin_flag.py` | done | | T1 | 1 | api-integration | ja | `gateway/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T2 | 2 | api-integration | ja | dito | done | | T2 | 2 | api-integration | ja | dito | done |
| T3 | 3 | api-integration | ja | dito | done | | T3 | 3 | api-integration | ja | dito | done |
| T4 | 4,10 | migration-unit | ja | `platform-core/tests/unit/rbac/test_sysadmin_migration.py` | done | | T4 | 4,10 | migration-unit | ja | `gateway/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 | | T5 | 5,6 | api-integration | ja | `gateway/tests/integration/rbac/test_platform_admin_flag.py` | done |
| T6 | 7 | frontend (Playwright) | optional | `ui-nyla/e2e/admin-users-flags.spec.ts` (neu) | open | | T6 | 7 | frontend (Playwright) | optional | `frontend_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 | | T7 | 8 | api-unit | ja | `gateway/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 | | 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 | | T9 | 11,12| manuelle UI-Regression | manuell | Siehe Security-Regression-Manual | open |
@ -412,7 +412,7 @@ after:
## Links ## Links
- RBAC-Referenz: `wiki/b-reference/platform/rbac.md` - RBAC-Referenz: `wiki/b-reference/platform/rbac.md`
- Auth-Modul: `platform-core/modules/auth/authentication.py` - Auth-Modul: `gateway/modules/auth/authentication.py`
- Ausgangspunkt Testing PORTA 2026-04-17 (Issue 4: Security-Bug) - Ausgangspunkt Testing PORTA 2026-04-17 (Issue 4: Security-Bug)
## Abschluss ## Abschluss
@ -420,7 +420,7 @@ after:
- [x] `wiki/b-reference/platform/rbac.md`: Abschnitt „Platform-Governance-Autoritaet" ergaenzt - [x] `wiki/b-reference/platform/rbac.md`: Abschnitt „Platform-Governance-Autoritaet" ergaenzt
- [ ] `wiki/TOPICS.md`: Topic „Authority-Modell: System/Platform/Mandate" anlegen - [ ] `wiki/TOPICS.md`: Topic „Authority-Modell: System/Platform/Mandate" anlegen
- [x] Dieses Dokument nach Abschluss → `wiki/c-work/4-done/` verschoben - [x] Dieses Dokument nach Abschluss → `wiki/c-work/4-done/` verschoben
- [x] CI-Gate `platform-core/scripts/check_no_sysadmin_role.py` (Acceptance T8 / AC#9) - [x] CI-Gate `gateway/scripts/check_no_sysadmin_role.py` (Acceptance T8 / AC#9)
### Umsetzungs-Status ### Umsetzungs-Status

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
<!-- status: done --> <!-- status: done -->
<!-- planned: 2026-04-21 --> <!-- planned: 2026-04-21 -->
<!-- done: 2026-04-21 --> <!-- done: 2026-04-21 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# Trustee: Aufraeumen `Positionen` / `Dokumente` Top-Level-Seiten # 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: Top-Level-Routen / Mappings fuer diese beiden Seiten wurden in der Vorgaenger-Iteration entfernt:
- `ui-nyla/src/pages/FeatureView.tsx`: kein direktes `'positions' / 'documents'`-Mapping mehr (`VIEW_COMPONENTS.trustee`). - `frontend_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. - `frontend_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`. - `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`.
Was noch lebt: die beiden Standalone-Komponenten als Datei + Index-Export. Sie werden ausschliesslich vom `TrusteeDataTablesView` als Tab-Body referenziert. 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. - 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. - 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). - `position-documents` (Zuordnungen) bleibt als eigene Top-Level-View unangetastet (anderer Use-Case: Position-Document-Zuordnung).
- `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. - `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.
## Ziel und Nicht-Ziele ## Ziel und Nicht-Ziele
@ -39,17 +39,17 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
## Betroffene Module ## Betroffene Module
- **Frontend**: - **Frontend**:
- `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`: Header-Kommentar / Renaming. - `frontend_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). - `frontend_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. - `frontend_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`. - `frontend_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. - `frontend_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. - `frontend_nyla/src/components/Navigation/*`: Pruefen, ob noch Icons / Default-Routes auf `positions` / `documents` zeigen.
- **Gateway**: - **Gateway**:
- `platform-core/modules/features/trustee/mainTrustee.py`: Sweep `UI_OBJECTS`, `TEMPLATE_ROLES`, `QUICK_ACTIONS` -- keine `ui.feature.trustee.positions` / `.documents` mehr. - `gateway/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). - `gateway/modules/features/trustee/routeFeatureTrustee.py`: kein Code-Change geplant (REST-Endpunkte fuer Position/Document bleiben).
- **Wiki**: - **Wiki**:
- `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. - `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.
- **DB-Migration**: nein. - **DB-Migration**: nein.
## Entscheidungen ## 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] `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] `TrusteeDocumentsView.tsx` analog ergaenzt.
- [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] `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] `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 "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] `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] `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 `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. - [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.
### Verifikation ### 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 `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] 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] `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 `platform-core/tests/test_routeFeatureTrustee_*` -- nicht beruehrt (kein Backend-Change in dieser Iteration). - [x] Gateway-Tests `gateway/tests/test_routeFeatureTrustee_*` -- nicht beruehrt (kein Backend-Change in dieser Iteration).
## Akzeptanzkriterien ## Akzeptanzkriterien
@ -92,23 +92,23 @@ Diese Iteration raeumt die noch existierenden, aber nicht mehr als eigenstaendig
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | manual UI | nein | -- | done (smoke ok) | | T1 | 1 | manual UI | nein | -- | done (smoke ok) |
| T2 | 2 | grep | manuell | platform-core/, ui-nyla/ | done (keine Live-Treffer) | | T2 | 2 | grep | manuell | gateway/, frontend_nyla/ | done (keine Live-Treffer) |
| T3 | 3 | grep + manual | manuell | mainTrustee.py, mail-templates | done (nur API-URLs verbleiben) | | T3 | 3 | grep + manual | manuell | mainTrustee.py, mail-templates | done (nur API-URLs verbleiben) |
| T4 | 4 | build | ja | ui-nyla `npm run build` | done (keine neuen Fehler) | | T4 | 4 | build | ja | frontend_nyla `npm run build` | done (keine neuen Fehler) |
## Links ## Links
- Vorgaenger-Plan: `wiki/c-work/4-done/2026-04-trustee-data-tables-page.md` - Vorgaenger-Plan: `wiki/c-work/4-done/2026-04-trustee-data-tables-page.md`
- Konsolidierte Seite: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` - Konsolidierte Seite: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`
- Eingebettete Tab-Bodies: `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx` - Eingebettete Tab-Bodies: `frontend_nyla/src/pages/views/trustee/TrusteePositionsView.tsx`, `TrusteeDocumentsView.tsx`
## Abschluss ## Abschluss
- [x] Dieses Dokument -> `c-work/4-done/` (Cleanup war eine reine Aufraeum-Iteration ohne Backend-Migration; keine separate Build-/Validate-Phase noetig). - [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: - [x] Code-Aenderungen:
- `ui-nyla/src/pages/views/trustee/TrusteePositionsView.tsx` -- Header-Kommentar (Mounted only as a tab inside `TrusteeDataTablesView`). - `frontend_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. - `frontend_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`. - `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`.
- [x] Audit ohne Code-Aenderung: - [x] Audit ohne Code-Aenderung:
- Backend (`mainTrustee.py`): keine UI-Object-Keys `ui.feature.trustee.positions/.documents` mehr; `QUICK_ACTIONS` zielen auf REST-API. - 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. - 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 --> <!-- status: done -->
<!-- started: 2026-04-20 --> <!-- started: 2026-04-20 -->
<!-- finished: 2026-04-21 --> <!-- finished: 2026-04-21 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# Trustee: Konsolidierte Daten-Tabellen-Seite # 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 ## Fokus und kritische Details
- **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(...)`. - **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(...)`.
- **`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. - **`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. - **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. - **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 ## Betroffene Module
- **Gateway**: - **Gateway**:
- `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`. - `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`.
- `platform-core/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern. - `gateway/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern.
- **Frontend**: - **Frontend**:
- **Neu**: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` (Container mit Tab-Bar + URL-Sync). - **Neu**: `frontend_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). - **Neu**: `frontend_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**: `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**: `ui-nyla/src/api/trusteeApi.ts` um `fetchTrusteeData*`-Funktionen. - **Erweitern**: `frontend_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**: `frontend_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**: `frontend_nyla/src/pages/views/trustee/index.ts` (Export).
- **Anpassen**: `ui-nyla/src/App.tsx` (Route `data-tables` registrieren). - **Anpassen**: `frontend_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. - **Optional**: `frontend_nyla/src/types/mandate.ts` (`FEATURE_REGISTRY.trustee.views`) um `data-tables` ergänzen, falls noch genutzt.
- **DB-Migration**: nein. - **DB-Migration**: nein.
- **Andere Komponenten**: keine. - **Andere Komponenten**: keine.
@ -92,18 +92,18 @@ Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (ums
### Frontend ### Frontend
- [x] `ui-nyla/src/api/trusteeApi.ts`: 7 neue Read-Funktionen (`fetchDataAccounts`, `fetchDataJournalEntries`, `fetchDataJournalLines`, `fetchDataContacts`, `fetchDataAccountBalances`, `fetchAccountingConfigs`, `fetchAccountingSyncs`) plus passende Typen. - [x] `frontend_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] `frontend_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** `frontend_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`: - [x] **Neu** `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`:
- 13 Tab-Defs, jede mit eigenem Wrapper-Component, das den passenden Hook aufruft. - 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). - 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. - 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). - RBAC-Filter im Frontend deaktiviert: einzelne Tab-Hooks blockieren Datenzugriff serverseitig (vermeidet sync-Permission-Lookups; spaetere Iteration kann Tab-Hiding nachziehen).
- [x] `ui-nyla/src/pages/views/trustee/index.ts`: Export ergaenzt. - [x] `frontend_nyla/src/pages/views/trustee/index.ts`: Export ergaenzt.
- [x] `ui-nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import. - [x] `frontend_nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import.
- [x] `ui-nyla/src/App.tsx`: Route `<Route path="data-tables" .../>` ergaenzt. - [x] `frontend_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. - [x] `frontend_nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` um `'data-tables'` ergaenzt.
### Cross-Cutting ### 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | manual UI | nein | | pending | | T1 | 1 | manual UI | nein | | pending |
| T2 | 2,5 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending | | T2 | 2,5 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T3 | 3,4 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending | | T3 | 3,4 | api | ja | gateway/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 | | T4 | 6 | api | ja | gateway/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 | | T5 | 7 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (RBAC-Gate) | pending |
| T6 | 8 | manual UI | nein | | pending | | T6 | 8 | manual UI | nein | | pending |
| T7 | 9 | manual + e2e | teils | bestehende Position/Document Tests laufen weiter | pending | | T7 | 9 | manual + e2e | teils | bestehende Position/Document Tests laufen weiter | pending |
| T8 | 10,11 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending | | T8 | 10,11 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending |
## Links ## Links
- PR: - PR:
- Issue: - Issue:
- Vorlage: `wiki/b-reference/ui-nyla/formgenerator.md` - Vorlage: `wiki/b-reference/frontend-nyla/formgenerator.md`
- Vorbild-Seite: `ui-nyla/src/pages/basedata/PromptsPage.tsx` - Vorbild-Seite: `frontend_nyla/src/pages/basedata/PromptsPage.tsx`
- Vorbild-Tabs: `ui-nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx` - Vorbild-Tabs: `frontend_nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx`
## Abschluss ## Abschluss
- [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/gateway/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/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/ui-nyla/formgenerator.md`: bereits referenziert (`TrusteeDataTablesView` als Beispiel im "Page Layout Chain"-Pattern). - [x] `b-reference/frontend-nyla/formgenerator.md`: bereits referenziert (`TrusteeDataTablesView` als Beispiel im "Page Layout Chain"-Pattern).
- [x] `TOPICS.md`: keine Änderung nötig (kein neues Thema). - [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] 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/`. - [x] Dieses Dokument → `c-work/4-done/`.

View file

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

View file

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

View file

@ -1,7 +1,7 @@
<!-- status: done --> <!-- status: done -->
<!-- started: 2026-04-24 --> <!-- started: 2026-04-24 -->
<!-- completed: 2026-04-24 --> <!-- completed: 2026-04-24 -->
<!-- component: gateway, ui-nyla, wiki --> <!-- component: gateway, frontend-nyla, wiki -->
<!-- depends-on: c-work/4-done/2026-04-typed-action-architecture.md --> <!-- depends-on: c-work/4-done/2026-04-typed-action-architecture.md -->
# Typed Action Architecture — Folge-Plan (Validate → Done) # Typed Action Architecture — Folge-Plan (Validate → Done)
@ -74,7 +74,7 @@ mindmap
D2 workflow.md<br/>(Action-Signaturen + Adapter) D2 workflow.md<br/>(Action-Signaturen + Adapter)
D3 ai-agent.md<br/>(Tool-Generierung aus Katalog) D3 ai-agent.md<br/>(Tool-Generierung aus Katalog)
D4 features/trustee.md<br/>(typisierte Inputs/Outputs) D4 features/trustee.md<br/>(typisierte Inputs/Outputs)
D5 ui-nyla/architecture.md<br/>(RequiredAttributePicker,<br/>Object-Drill-Down,<br/>Loop-Vorschlag) D5 frontend-nyla/architecture.md<br/>(RequiredAttributePicker,<br/>Object-Drill-Down,<br/>Loop-Vorschlag)
D6 TOPICS.md<br/>(neuer Eintrag<br/>"Typed Action Architecture") D6 TOPICS.md<br/>(neuer Eintrag<br/>"Typed Action Architecture")
E) Doc-Lifecycle E) Doc-Lifecycle
E1 Architektur-Plan ->4-done<br/>nach Abschluss D E1 Architektur-Plan ->4-done<br/>nach Abschluss D
@ -144,11 +144,11 @@ mindmap
- `components/FlowEditor/editor/__tests__/RunButton.test.tsx` (neu) — A1 - `components/FlowEditor/editor/__tests__/RunButton.test.tsx` (neu) — A1
- `e2e/workflows/save-with-errors.spec.ts` (neu, falls Playwright) — A3 - `e2e/workflows/save-with-errors.spec.ts` (neu, falls Playwright) — A3
- **Wiki:** - **Wiki:**
- `b-reference/platform-core/architecture.md` — D1 - `b-reference/gateway/architecture.md` — D1
- `b-reference/platform-core/workflow.md` — D2 - `b-reference/gateway/workflow.md` — D2
- `b-reference/platform-core/ai-agent.md` — D3 - `b-reference/gateway/ai-agent.md` — D3
- `b-reference/platform-core/features/trustee.md` — D4 - `b-reference/gateway/features/trustee.md` — D4
- `b-reference/ui-nyla/architecture.md` — D5 - `b-reference/frontend-nyla/architecture.md` — D5
- `TOPICS.md` — D6 - `TOPICS.md` — D6
- `c-work/3-validate/2026-04-typed-action-architecture.md` - `c-work/3-validate/2026-04-typed-action-architecture.md`
bei Abschluss → `4-done/` (E1) → `z-archive/` (E2) bei Abschluss → `4-done/` (E1) → `z-archive/` (E2)
@ -211,10 +211,10 @@ mindmap
### C) Operatives ### C) Operatives
- [x] C1: DB-CLI-Migrationsskript - [x] C1: DB-CLI-Migrationsskript
`platform-core/scripts/script_migrate_feature_instance_refs.py` — `gateway/scripts/script_migrate_feature_instance_refs.py` —
walkt `Automation2Workflow` + `AutoVersion`, ruft walkt `Automation2Workflow` + `AutoVersion`, ruft
`materializeFeatureInstanceRefs`, persistiert mit `--dry-run`-Flag, `materializeFeatureInstanceRefs`, persistiert mit `--dry-run`-Flag,
Tests in `platform-core/tests/unit/scripts/test_migrate_feature_instance_refs.py` Tests in `gateway/tests/unit/scripts/test_migrate_feature_instance_refs.py`
(9/9 gruen, idempotent) (9/9 gruen, idempotent)
- [x] C2: HTML-Prototype `local/temp/uxPrototype.html` aktualisiert — - [x] C2: HTML-Prototype `local/temp/uxPrototype.html` aktualisiert —
FeatureInstanceRef-Envelope sichtbar, Strict-Mode-Toggle, `*`-Wildcard- FeatureInstanceRef-Envelope sichtbar, Strict-Mode-Toggle, `*`-Wildcard-
@ -222,15 +222,15 @@ mindmap
### D) Wissens-Sync (b-reference) ### D) Wissens-Sync (b-reference)
- [x] D1: `b-reference/platform-core/architecture.md` — Abschnitt - [x] D1: `b-reference/gateway/architecture.md` — Abschnitt
"Typed Action Architecture (4-Schichten)" ergaenzt, `lastReviewed` 2026-04-24 "Typed Action Architecture (4-Schichten)" ergaenzt, `lastReviewed` 2026-04-24
- [x] D2: `b-reference/platform-core/workflow.md` — Abschnitt "Typed Action Architecture - [x] D2: `b-reference/gateway/workflow.md` — Abschnitt "Typed Action Architecture
(Phasen 1-5)": Catalog, Adapter, Pick-not-Push, `*`-Wildcard, Save-with-errors (Phasen 1-5)": Catalog, Adapter, Pick-not-Push, `*`-Wildcard, Save-with-errors
- [x] D3: `b-reference/platform-core/ai-agent.md` — `ActionToolAdapter`-Notiz mit - [x] D3: `b-reference/gateway/ai-agent.md` — `ActionToolAdapter`-Notiz mit
Tool-Generierung aus Catalog statt Heuristik Tool-Generierung aus Catalog statt Heuristik
- [x] D4: `b-reference/platform-core/features/trustee.md` — neue kanonische Seite - [x] D4: `b-reference/gateway/features/trustee.md` — neue kanonische Seite
mit Actions, Datenmodell, FeatureInstanceRef, AccountingBridge, Tests mit Actions, Datenmodell, FeatureInstanceRef, AccountingBridge, Tests
- [x] D5: `b-reference/ui-nyla/architecture.md` — Abschnitt - [x] D5: `b-reference/frontend-nyla/architecture.md` — Abschnitt
"FlowEditor -- Typed Action Architecture" mit Picker-Komponenten, "FlowEditor -- Typed Action Architecture" mit Picker-Komponenten,
Save/Run-Gating und Vitest+RTL-Tests Save/Run-Gating und Vitest+RTL-Tests
- [x] D6: `wiki/TOPICS.md` — Eintrag "Typed Action Architecture" mit Verweisen - [x] D6: `wiki/TOPICS.md` — Eintrag "Typed Action Architecture" mit Verweisen
@ -267,12 +267,12 @@ mindmap
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| F1 | 1 | smoke | ja | `ui-nyla/vitest.config.ts` + `vitest.setup.ts` | done | | F1 | 1 | smoke | ja | `frontend_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) | | 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 | `platform-core/tests/integration/trustee/test_spesenbelege_workflow_e2e.py` | done (3/3) | | F3 | 3 | integration | ja | `gateway/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 | | 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 | `platform-core/scripts/script_migrate_feature_instance_refs.py` + `platform-core/tests/unit/scripts/test_migrate_feature_instance_refs.py` | done (9/9) | | 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/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 | | 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 |
| F7 | 9 | manual | nein | `wiki/c-work/4-done/2026-04-typed-action-architecture.md` | 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 --> <!-- status: done -->
<!-- started: 2026-04-23 --> <!-- started: 2026-04-23 -->
<!-- completed: 2026-04-23 --> <!-- completed: 2026-04-23 -->
<!-- component: gateway, ui-nyla --> <!-- component: gateway, frontend-nyla -->
# Typed Generic Handover für den Graphical Editor — PicknotPush, StaticOnly Schemas, Hard Validation # 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) ### Was schon da ist (verifiziert im Code, 20260423)
- `platform-core/modules/features/graphicalEditor/portTypes.py` — `PortField`, `PortSchema`, `PORT_TYPE_CATALOG`, `SYSTEM_VARIABLES`, `_normalizeToSchema`, `INPUT_EXTRACTORS`. - `gateway/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). - `gateway/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. - `frontend_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. - `frontend_nyla/src/components/FlowEditor/nodes/frontendTypeRenderers/index.tsx` — `FRONTEND_TYPE_RENDERERS` Registry.
- `ui-nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx` — generischer ConfigRenderer. - `frontend_nyla/src/components/FlowEditor/editor/NodeConfigPanel.tsx` — generischer ConfigRenderer.
### Was fragil / kritisch wird ### Was fragil / kritisch wird
@ -74,7 +74,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
## Betroffene Module ## Betroffene Module
**Gateway (`platform-core/modules/`):** **Gateway (`gateway/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/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/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`. - `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). - `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. - MigrationsSkript `scripts/migration/2026-04-pick-not-push-migration.py` (neu) — scannt `AutoWorkflow.graph`, ergänzt explizite DataRefs anstelle implizitem WireHandover.
- TestPakete: - TestPakete:
- `platform-core/tests/unit/graphicalEditor/test_port_schema_recursive.py` - `gateway/tests/unit/graphicalEditor/test_port_schema_recursive.py`
- `platform-core/tests/unit/graphicalEditor/test_validate_typed_hard.py` - `gateway/tests/unit/graphicalEditor/test_validate_typed_hard.py`
- `platform-core/tests/integration/graphicalEditor/test_upstream_paths_api.py` - `gateway/tests/integration/graphicalEditor/test_upstream_paths_api.py`
- `platform-core/tests/integration/graphicalEditor/test_pwg_pilot_typed.py` - `gateway/tests/integration/graphicalEditor/test_pwg_pilot_typed.py`
- `platform-core/tests/unit/migration/test_pick_not_push_migration.py` - `gateway/tests/unit/migration/test_pick_not_push_migration.py`
- pro Adapter (sharepoint/outlook/clickup/trustee/file): SchemaComplianceTest - pro Adapter (sharepoint/outlook/clickup/trustee/file): SchemaComplianceTest
**Frontend (`ui-nyla/src/`):** **Frontend (`frontend_nyla/src/`):**
- `api/workflowApi.ts` — Interfaces: `PortSchema` rekursiv (`fields`, `itemSchema`); `DataRef.expectedType`; `NodeType.outputPorts.schema` darf `string | {kind:"fromGraph", parameter:string}` sein. - `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/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. - `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. **DBMigration:** Nein im SchemaSinn (kein `AutoWorkflow`TableChange). **DatenMigration ja:** `AutoWorkflow.graph`JSON wird einmalig durch MigrationsSkript transformiert.
**Andere Komponenten:** **Andere Komponenten:**
- 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. - 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.
## Entscheidungen ## Entscheidungen
@ -143,7 +143,7 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
- [ ] `methods/clickup/` analog. - [ ] `methods/clickup/` analog.
- [ ] `methods/trustee/` (`extractFromFiles`, `processDocuments`): UDMOutput sauber rekursiv typisieren. - [ ] `methods/trustee/` (`extractFromFiles`, `processDocuments`): UDMOutput sauber rekursiv typisieren.
- [ ] `methods/file/create`: OutputSchema auf `Document` mappen. - [ ] `methods/file/create`: OutputSchema auf `Document` mappen.
- [ ] Pro Adapter ein ComplianceTest (`platform-core/tests/integration/methods/test_<method>_schema_compliance.py`): mock + reale MiniOutputs gegen SollSchema validiert. - [ ] Pro Adapter ein ComplianceTest (`gateway/tests/integration/methods/test_<method>_schema_compliance.py`): mock + reale MiniOutputs gegen SollSchema validiert.
### Phase 3 — LoopScoping & DataPicker (Frontend) ### 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. - [ ] `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). - [ ] `data.transform` Nodes in alten Workflows: MigrationsSkript gibt Warnung pro Vorkommen aus (manuell zu refactoren — kein AutoCleanup, weil semantisch).
### Phase 10 — Dokumentation & Abschluss ### Phase 10 — Dokumentation & Abschluss
- [ ] `wiki/b-reference/platform-core/automation.md`: Abschnitt „PicknotPush Handover" + Removed `INPUT_EXTRACTORS`. - [ ] `wiki/b-reference/gateway/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/gateway/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/b-reference/frontend-nyla/architecture.md`: Abschnitt FlowEditor mit TypeCompat, AutoSuggest, HybridConnectionPicker.
- [ ] `wiki/TOPICS.md`: Eintrag „Typed Generic Handover (build/done)" verlinken. - [ ] `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. - [ ] 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 | | ID | AC | Art | Automatisiert | RepoPfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | integration | ja | `platform-core/tests/integration/graphicalEditor/test_pwg_pilot_typed.py` | pending | | T1 | 1 | integration | ja | `gateway/tests/integration/graphicalEditor/test_pwg_pilot_typed.py` | pending |
| T2 | 2 | unit | ja | `platform-core/tests/unit/graphicalEditor/test_validate_typed_hard.py` | pending | | T2 | 2 | unit | ja | `gateway/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 | | T3 | 3 | frontend unit | ja | `frontend_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 | | 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 | `platform-core/tests/integration/graphicalEditor/test_upstream_paths_api.py` | pending | | T5 | 5 | api | ja | `gateway/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 | | T6 | 6 | migration | ja | `gateway/tests/unit/migration/test_pick_not_push_migration.py` | pending |
| T7 | 7 | frontend unit | ja | `ui-nyla/.../__tests__/dataPicker.typeCompat.test.ts` | pending | | T7 | 7 | frontend unit | ja | `frontend_nyla/.../__tests__/dataPicker.typeCompat.test.ts` | pending |
| T8 | 8 | frontend e2e | ja (Playwright opt) | `ui-nyla/tests/e2e/wireAutoSuggest.spec.ts` | pending | | T8 | 8 | frontend e2e | ja (Playwright opt) | `frontend_nyla/tests/e2e/wireAutoSuggest.spec.ts` | pending |
| T9 | 9 | frontend unit | ja | `ui-nyla/.../__tests__/connectionPicker.modes.test.ts` | pending | | T9 | 9 | frontend unit | ja | `frontend_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 | | T10 | 10 | api/integration | ja | `gateway/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 | | T11 | 11 | unit | ja | `gateway/tests/unit/migration/test_data_transform_warning.py` | pending |
## Links ## Links
@ -247,9 +247,9 @@ Im PWGPilot (`pwg-pilot-jahresmietzinsbestätigung.workflow.json`) zeigt dies
## Abschluss ## Abschluss
- [ ] `wiki/b-reference/platform-core/automation.md` aktualisiert (PicknotPush, Removed Heuristik) - [ ] `wiki/b-reference/gateway/automation.md` aktualisiert (PicknotPush, Removed Heuristik)
- [ ] `wiki/b-reference/platform-core/workflow.md` aktualisiert (SchemaTiefe, LoopScoping) - [ ] `wiki/b-reference/gateway/workflow.md` aktualisiert (SchemaTiefe, LoopScoping)
- [ ] `wiki/b-reference/ui-nyla/architecture.md` aktualisiert (FlowEditorErweiterungen) - [ ] `wiki/b-reference/frontend-nyla/architecture.md` aktualisiert (FlowEditorErweiterungen)
- [ ] `wiki/TOPICS.md` aktualisiert (neuer Eintrag „Typed Generic Handover") - [ ] `wiki/TOPICS.md` aktualisiert (neuer Eintrag „Typed Generic Handover")
- [ ] Dieses Dokument → `wiki/z-archive/` verschoben - [ ] 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) ## 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 `platform-core/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 `gateway/modules/features/graphicalEditor/portTypes.py:59170`.
### Neue / erweiterte ItemSchemas im Katalog ### Neue / erweiterte ItemSchemas im Katalog

View file

@ -2,7 +2,7 @@
<!-- started: 2026-04-19 --> <!-- started: 2026-04-19 -->
<!-- built: 2026-04-21 --> <!-- built: 2026-04-21 -->
<!-- done: 2026-04-21 --> <!-- done: 2026-04-21 -->
<!-- component: ui-nyla --> <!-- component: frontend-nyla -->
<!-- relatedTo: c-work/3-validate/2026-04-pwg-pilot-mietzinsbestaetigung-workflow.md (Phase 2 deferred item — jetzt erfüllt) --> <!-- 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. --> <!-- validation: separate manuelle Smoke-Tests durch User; Code-Smoke (`tsc -b`, `eslint`, `vite build`) clean. -->
@ -10,7 +10,7 @@
## Beschreibung und Kontext ## 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` (`ui-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` (`frontend_nyla/src/components/FolderTree/FolderTree.tsx`). Sie wird heute in mehreren Kontexten verwendet:
| Kontext | Datei | Zweck | | 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 ### Phase 1 — Action-Modell + Registry-Hook
- [x] ✅ DONE — Neue Datei `ui-nyla/src/components/FolderTree/actions/types.ts`: - [x] ✅ DONE — Neue Datei `frontend_nyla/src/components/FolderTree/actions/types.ts`:
```ts ```ts
export type FileActionScope = 'file' | 'folder' | 'multi'; 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 `ui-nyla/src/components/FolderTree/actions/registry.ts` mit: - [x] ✅ DONE — Neue Datei `frontend_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). - 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. - `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. - `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 ### Phase 5 — Tests + Dokumentation
- [ ] 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 — 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 — Storybook-Story: keine Storybook-Setup im Repo (`.storybook/` fehlt) → analog Test-Setup eigener Plan nötig. - [ ] 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". - [ ] 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. - [ ] 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|---|---|---| |----|----|-----|---|---|---|
| T1 | 1, 5, 8 | unit | ja | `ui-nyla/tests/components/FolderTree/actions.test.tsx` | deferred (kein Test-Stack im Repo) | | 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 | `ui-nyla/tests/components/FolderTree/workflowAction.test.tsx` | deferred (s. T1) | | T2 | 2, 3 | integration | ja | `frontend_nyla/tests/components/FolderTree/workflowAction.test.tsx` | deferred (s. T1) |
| T3 | 4 | manual | nein | mobile-emulation in Chrome DevTools | manual (User-Smoke separat) | | T3 | 4 | manual | nein | mobile-emulation in Chrome DevTools | manual (User-Smoke separat) |
| T4 | 6 | integration | ja | `ui-nyla/tests/components/FolderTree/dragDrop.test.tsx` | deferred (s. T1) | | T4 | 6 | integration | ja | `frontend_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) | | T5 | 7 | unit | ja | `frontend_nyla/tests/components/FolderTree/shortcuts.test.tsx` | deferred (s. T1) |
## Inspirations / State-of-the-Art ## Inspirations / State-of-the-Art
@ -206,12 +206,12 @@ Die **Unified Data Bar (UDB)** ist die zentrale Datenleiste der PORTA-UI: sie ze
## Links ## Links
- Heutiger `FolderTree`: `ui-nyla/src/components/FolderTree/FolderTree.tsx` - Heutiger `FolderTree`: `frontend_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`) - Action-System: `frontend_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` - Konsumenten: `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`, `frontend_nyla/src/pages/basedata/FilesPage.tsx`
- Drop-Target: `ui-nyla/src/components/FlowEditor/editor/FlowCanvas.tsx` (`onExternalDrop`-Prop) + `Automation2FlowEditor.tsx` (Wiring) - Drop-Target: `frontend_nyla/src/components/FlowEditor/editor/FlowCanvas.tsx` (`onExternalDrop`-Prop) + `Automation2FlowEditor.tsx` (Wiring)
- Datei-Context: `ui-nyla/src/contexts/FileContext.tsx` - Datei-Context: `frontend_nyla/src/contexts/FileContext.tsx`
- Workflow-API: `ui-nyla/src/api/workflowApi.ts` (`importWorkflowFromFile`, `isWorkflowFileContent`) - Workflow-API: `frontend_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) - Verwandter Plan: `wiki/c-work/1-plan/2026-04-pwg-pilot-mietzinsbestaetigung-workflow.md` (Phase 2 deferred → jetzt erfüllt)
## Offene Punkte / Follow-ups ## Offene Punkte / Follow-ups

View file

@ -1,7 +1,7 @@
<!-- status: done --> <!-- status: done -->
<!-- started: 2026-04-08 --> <!-- started: 2026-04-08 -->
<!-- completed: 2026-04-08 --> <!-- completed: 2026-04-08 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# UI-Mehrsprachigkeit: Dynamische Sprachsets (DB-backed i18n) # 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: Bei **Update**, **Update All** und dem dedizierten Endpunkt `PUT /api/i18n/sets/sync-de` wird automatisch:
1. Alle `.ts`/`.tsx`-Dateien unter `ui-nyla/src/` nach `t('...')`-Aufrufen gescannt 1. Alle `.ts`/`.tsx`-Dateien unter `frontend_nyla/src/` nach `t('...')`-Aufrufen gescannt
2. Neue Keys (in Codebase, nicht in DB) → zum `de`-Set hinzugefügt (Key = Value = deutscher Klartext) 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 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) 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 ## Links
- LanguageContext: `ui-nyla/src/providers/language/LanguageContext.tsx` - LanguageContext: `frontend_nyla/src/providers/language/LanguageContext.tsx`
- API-Route: `platform-core/modules/routes/routeI18n.py` - API-Route: `gateway/modules/routes/routeI18n.py`
- Admin-Seite: `ui-nyla/src/pages/admin/AdminLanguagesPage.tsx` - Admin-Seite: `frontend_nyla/src/pages/admin/AdminLanguagesPage.tsx`
- Seed-Daten: `platform-core/modules/migration/seedData/ui_language_seed.json` - Seed-Daten: `gateway/modules/migration/seedData/ui_language_seed.json`

View file

@ -2,7 +2,7 @@
<!-- started: 2026-04-21 --> <!-- started: 2026-04-21 -->
<!-- code-complete: 2026-04-21 --> <!-- code-complete: 2026-04-21 -->
<!-- closed: 2026-04-21 --> <!-- closed: 2026-04-21 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# Bundle: UI-Polish-Sprint Q2 (Format-Hints, UDB-Container, Store, Modal-Audit, Node-Mapping) # 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: Fragile Stellen:
- `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. - `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.
- `ui-nyla/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx::formatCellValue` wird auch im PDF-Export benutzt (prüfen). Format-Funktion muss reine Funktion sein. - `frontend_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 ## 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/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/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.) - `modules/serviceCenter/services/serviceAgent/coreTools/_dataSourceTools.py` oder neues `_emailTools.py` (Thema 6: Tool-Implementierung `replyToMail` etc.)
- `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` (Thema 7: Border-Left auf Z.1414 erzeugt 3px-Versatz; aktive Wildcard-Row braucht kompensierenden negativen `marginLeft`) - `frontend_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`) - `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`)
- **Frontend**: - **Frontend**:
- `src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx` (Thema 1: `formatCellValue` ruft neuen `applyFrontendFormat`) - `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) - `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` - [ ] `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>]` - [ ] `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 - [ ] `getModelLabels()` ergänzen, sodass übersetzte Format-Labels auf Frontend ausgeliefert werden
- [ ] **NEU** `ui-nyla/src/utils/applyFrontendFormat.ts` mit `applyFrontendFormat(value, format, formatLabels, type, locale)` pure function - [ ] **NEU** `frontend_nyla/src/utils/applyFrontendFormat.ts` mit `applyFrontendFormat(value, format, formatLabels, type, locale)` pure function
- [ ] `FormGeneratorTable::formatCellValue` integrieren (für `cellAlign` ebenfalls nutzen) - [ ] `FormGeneratorTable::formatCellValue` integrieren (für `cellAlign` ebenfalls nutzen)
- [ ] `FormGeneratorForm` integrieren für read-only Anzeige - [ ] `FormGeneratorForm` integrieren für read-only Anzeige
- [ ] Unit-Tests für Format-Parser - [ ] 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 - [ ] `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 `*`) - [ ] Container-`objectKey`-Format definieren: `data.feature.<code>.group:<groupKey>.*` (Glob mit `*`)
- [ ] Backend-Resolver `workspaceContext` (in `platform-core/modules/aiAgent/`): Globs auflösen, Records-Set zurückliefern - [ ] Backend-Resolver `workspaceContext` (in `gateway/modules/aiAgent/`): Globs auflösen, Records-Set zurückliefern
- [ ] Anzeige im Chat-Context: "Container Mandant Müller AG (12 Records)" statt `null` - [ ] Anzeige im Chat-Context: "Container Mandant Müller AG (12 Records)" statt `null`
- [ ] Audit Token-Limits — Container kann gross sein, Warning-UX - [ ] Audit Token-Limits — Container kann gross sein, Warning-UX
### Thema 3 — Store: automation ### Thema 3 — Store: automation
- [ ] In Feature-Registry (`platform-core/modules/datamodels/datamodelFeatures.py` o.ä. Bootstrap): `automation` mit `meta.category = "store"`, `enabled = True` - [ ] In Feature-Registry (`gateway/modules/datamodels/datamodelFeatures.py` o.ä. Bootstrap): `automation` mit `meta.category = "store"`, `enabled = True`
- [ ] Optional: Icon/Beschreibung für Store-Card prüfen - [ ] Optional: Icon/Beschreibung für Store-Card prüfen
- [ ] Smoke-Test: Aktivierung in fresh-Mandant funktioniert - [ ] Smoke-Test: Aktivierung in fresh-Mandant funktioniert
### Thema 4 — Modal-Forms (Outside-Click-Fix) ### Thema 4 — Modal-Forms (Outside-Click-Fix)
- [ ] `usePrompt.tsx`: Backdrop-`onClick={_handleCancel}` **entfernen** (oder optional via Prop `dismissOnBackdrop?: boolean = false`) - [ ] `usePrompt.tsx`: Backdrop-`onClick={_handleCancel}` **entfernen** (oder optional via Prop `dismissOnBackdrop?: boolean = false`)
- [ ] Audit: grep nach `onClick.*Close|onClick.*Cancel` auf Overlay-DIVs in `ui-nyla/src/` - [ ] Audit: grep nach `onClick.*Close|onClick.*Cancel` auf Overlay-DIVs in `frontend_nyla/src/`
- [ ] Liste der gefundenen Stellen prüfen, jede einzeln korrigieren oder bewusst lassen (z.B. Image-Lightbox: Backdrop schliesst soll bleiben) - [ ] 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`) - [ ] `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) ### 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 - [ ] **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 `platform-core/modules/features/*/main*.py` nach Pattern `"label":\s*"[^"]+"` (bare string statt `t(...)`) - [ ] **Audit-Script**: Grep über `gateway/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 `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 `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 - [ ] **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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1,2,3 | unit | ja | `ui-nyla/src/utils/applyFrontendFormat.test.ts` | pending | | T1 | 1,2,3 | unit | ja | `frontend_nyla/src/utils/applyFrontendFormat.test.ts` | pending |
| T2 | 1,2,3 | api | ja | `platform-core/tests/test_attributeUtils_format.py` | pending | | T2 | 1,2,3 | api | ja | `gateway/tests/test_attributeUtils_format.py` | pending |
| T3 | 3 | api | ja | `platform-core/tests/test_i18nModel_formatLabels.py` | pending | | T3 | 3 | api | ja | `gateway/tests/test_i18nModel_formatLabels.py` | pending |
| T4 | 4,5 | e2e | nein (manuell) | UDB → Chat Flow | pending | | T4 | 4,5 | e2e | nein (manuell) | UDB → Chat Flow | pending |
| T5 | 6 | api | ja | `platform-core/tests/test_routeStore_automation.py` | pending | | T5 | 6 | api | ja | `gateway/tests/test_routeStore_automation.py` | pending |
| T6 | 7 | unit | ja | `ui-nyla/src/hooks/usePrompt.test.tsx` | pending | | T6 | 7 | unit | ja | `frontend_nyla/src/hooks/usePrompt.test.tsx` | pending |
| T7 | 8 | doc | nein | `wiki/b-reference/modal-audit.md` | pending | | T7 | 8 | doc | nein | `wiki/b-reference/modal-audit.md` | pending |
| T8 | 9,10 | manuell | nein | Graph-Editor Smoke | pending | | T8 | 9,10 | manuell | nein | Graph-Editor Smoke | pending |
| T9 | 11,12 | api | ja | `platform-core/tests/test_outlookAdapter_reply.py` (Mock Graph) | pending | | T9 | 11,12 | api | ja | `gateway/tests/test_outlookAdapter_reply.py` (Mock Graph) | pending |
| T10 | 13 | api | ja | `platform-core/tests/test_browseDataSource_mailLimit.py` | pending | | T10 | 13 | api | ja | `gateway/tests/test_browseDataSource_mailLimit.py` | pending |
| T11 | 11,12,14 | manuell | nein | Real-Outlook Agent-Chat E2E | 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 | | T12 | 15,16 | manuell | nein | UDB Visual-Diff Screenshot vor/nach | pending |
| T13 | 17,18,19 | api | ja | `platform-core/tests/test_outlookAdapter_moveDelete.py` (Mock Graph) | pending | | T13 | 17,18,19 | api | ja | `gateway/tests/test_outlookAdapter_moveDelete.py` (Mock Graph) | pending |
| T14 | 20,21 | api | ja | `platform-core/tests/test_outlookAdapter_folderResolve.py` | pending | | T14 | 20,21 | api | ja | `gateway/tests/test_outlookAdapter_folderResolve.py` | pending |
| T15 | 22 | api | ja | `platform-core/tests/test_outlookAdapter_readState.py` | pending | | T15 | 22 | api | ja | `gateway/tests/test_outlookAdapter_readState.py` | pending |
| T16 | 17,18,19,20 | manuell | nein | Real-Outlook E2E Move/Archive/Delete | 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 | | T17 | 23 | manuell | nein | Sprachwechsel UDB-Test (DE → EN/FR) | pending |
| T18 | 24 | script | ja | `platform-core/tests/test_featureCatalogLabels_i18n.py` (Grep über alle main*.py) | pending | | T18 | 24 | script | ja | `gateway/tests/test_featureCatalogLabels_i18n.py` (Grep über alle main*.py) | pending |
## Phasen-Planung (Vorschlag) ## 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: 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: `ui-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: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`.

View file

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

View file

@ -27,7 +27,7 @@ Heins Forschung (*Boosting Querying Accuracy with Ontology-Guided LLMs*, ENTER 2
## Fokus und kritische Details ## Fokus und kritische Details
- **Eine zentrale Stelle:** `featureDataAgent._buildSchemaContext` und `featureDataProvider` -- jede Doppel-Implementierung pro Feature ist verboten (Doc-Sync `b-reference/platform-core/ai-agent.md`). - **Eine zentrale Stelle:** `featureDataAgent._buildSchemaContext` und `featureDataProvider` -- jede Doppel-Implementierung pro Feature ist verboten (Doc-Sync `b-reference/gateway/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. - **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. - **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. - **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 ## Betroffene Module
- **Gateway:** - **Gateway:**
- `platform-core/modules/serviceCenter/services/serviceAgent/datamodelAgent.py` (`ToolResult.errorDetails`, `ToolCallLog.validationFailureCode`, `AgentTrace`-Counter) - `gateway/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) - `gateway/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) - `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)
- `platform-core/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` (unverändert; Validator läuft davor) - `gateway/modules/serviceCenter/services/serviceAgent/featureDataProvider.py` (unverändert; Validator läuft davor)
- `platform-core/modules/serviceCenter/services/serviceAgent/queryValidator.py` **(neu)** (zentrale Validator-Engine) - `gateway/modules/serviceCenter/services/serviceAgent/queryValidator.py` **(neu)** (zentrale Validator-Engine)
- `platform-core/modules/serviceCenter/services/serviceAgent/datamodelOntology.py` **(neu)** (`OntologyDescriptor`, `Constraint`, `Entity`, `Relation`, `QueryValidationError`) - `gateway/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) - `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)
- `platform-core/modules/features/trustee/trusteeOntology.py` **(neu)** (Trustee-Buchhaltungs-Ontologie als Code) - `gateway/modules/features/trustee/trusteeOntology.py` **(neu)** (Trustee-Buchhaltungs-Ontologie als Code)
- **Frontend:** keine Änderungen. - **Frontend:** keine Änderungen.
- **DB-Migration:** nein. Eval-Goldstandard liegt im Test-Repo, nicht in der Mandanten-DB. - **DB-Migration:** nein. Eval-Goldstandard liegt im Test-Repo, nicht in der Mandanten-DB.
- **Andere Komponenten:** - **Andere Komponenten:**
- `platform-core/tests/integration/featureDataAgent/` **(neu)** -- Goldstandard-Eval-Harness, läuft optional in CI als langer Job. - `gateway/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. - `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.
## Entscheidungen ## Entscheidungen
@ -222,7 +222,7 @@ class OntologyDescriptor(BaseModel):
### Eval-Harness (querschneidend, Phase 1 + 2) ### Eval-Harness (querschneidend, Phase 1 + 2)
**Goldstandard-Format** (`platform-core/tests/fixtures/trusteeBenchmark/questions.yaml`): **Goldstandard-Format** (`gateway/tests/fixtures/trusteeBenchmark/questions.yaml`):
```yaml ```yaml
- id: q01 - id: q01
@ -239,7 +239,7 @@ class OntologyDescriptor(BaseModel):
"1021.closingBalance": 28100.00 "1021.closingBalance": 28100.00
``` ```
**Harness** (`platform-core/tests/integration/featureDataAgent/test_trusteeBenchmark.py`): **Harness** (`gateway/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). - 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. - Iteriert über 19 Fragen.
- Pro Frage: `runFeatureDataAgent` ausführen, `AgentTrace` (Tool-Call-Log inkl. `validationFailureCode`) + finale Antwort capturen. - 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) ### Phase 1.5 -- Eval-Harness (Woche 2, ca. 3-4 PT, parallel zu Phase 2 startbar)
- [ ] `platform-core/tests/fixtures/trusteeBenchmark/loadTrusteeBenchmarkFixture.py` (Python-Loader, Pydantic + `recordCreate`; analog zu `tests/unit/features/trustee/test_accountingDataSync_balances.py`) - [ ] `gateway/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 - [ ] `gateway/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) - [ ] `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) - [ ] Eval-Bericht-Generator (Markdown-Output)
- [ ] **Baseline-Run** (vor Phase 2) -- Resultate in `local/notes/eval-results-baseline.md` - [ ] **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 ### 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] Ontology-Datenmodell vervollständigt (`Entity`, `Relation`, `Invariant`, `CanonicalQueryPattern`, `SemanticType`-Enum -- bereits in Phase 1 vorbereitet, jetzt aktiv genutzt)
- [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] `gateway/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] `getAgentOntology()`-Hook in `mainTrustee.py`
- [x] `OntologyToPromptCompiler` -- generiert kompakten Prompt-Text deterministisch (`ontologyToPromptCompiler.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 - [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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | platform-core/tests/unit/services/test_queryValidator.py | DONE (24 tests) | | T1 | 1 | unit | ja | gateway/tests/unit/services/test_queryValidator.py | DONE (24 tests) |
| T2 | 2 | unit | ja | platform-core/tests/unit/services/test_queryValidator.py | DONE | | T2 | 2 | unit | ja | gateway/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%) | | 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 | platform-core/tests/unit/services/test_featureDataAgent_schema.py, test_trusteeOntology.py | DONE | | T4 | 4 | unit | ja | gateway/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) | | T5 | 5 | unit | ja | gateway/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) | | 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 | platform-core/tests/unit/services/test_featureDataAgent_schema.py | DONE -- Features ohne Ontologie laufen unverändert | | T7 | 7 | unit + smoke | ja | gateway/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 | | 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 | platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py:284-310 | DONE -- Tool-Description erklärt errorDetails-Format inline | | 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 | platform-core/tests/unit/serviceAgent/test_agentTrace_repairCounters.py | DONE (8 tests) | | T10 | 10 | unit | ja | gateway/tests/unit/serviceAgent/test_agentTrace_repairCounters.py | DONE (8 tests) |
## Links ## Links
- Forschungs-Input: `pamocreate/projects/poweron/admin-compliance-security/20-outputs/20260515-andreas-hein-learnings-fuer-porta.md` (Punkte 3.1, 3.3) - 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) - Hein-Paper: *Boosting Querying Accuracy with Ontology-Guided LLMs* (ENTER 2025, Springer)
- Bestehender Code: `platform-core/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`, `mainTrustee.py:676-754` (`_AGENT_DOMAIN_HINTS`) - Bestehender Code: `gateway/modules/serviceCenter/services/serviceAgent/featureDataAgent.py`, `mainTrustee.py:676-754` (`_AGENT_DOMAIN_HINTS`)
- Bezug Wiki: `b-reference/platform-core/ai-agent.md` (Abschnitt FeatureSubAgent) - Bezug Wiki: `b-reference/gateway/ai-agent.md` (Abschnitt FeatureSubAgent)
## Abschluss ## Abschluss
- [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/gateway/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] `b-reference/gateway/features/trustee.md` neuer Abschnitt "Agent-Ontologie"
- [x] `wiki/d-guides/coding-conventions.md` Migrations-Pattern für `getAgentOntology()` - [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] 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) - [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 --> <!-- status: done -->
<!-- started: 2026-05-01 --> <!-- started: 2026-05-01 -->
<!-- completed: 2026-05-03 --> <!-- completed: 2026-05-03 -->
<!-- component: ui-nyla, gateway --> <!-- component: frontend-nyla, gateway -->
# FormGeneratorTree (NEU) + Recovery der persistenten Folder/File-Funktionen # 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, In den Commits `c8e9304` (2026-04-29), `e7a79a3` und `7c05cb0` (beide 2026-04-30,
zusammen -1263 / +897) wurde `FolderTree` aus zusammen -1263 / +897) wurde `FolderTree` aus
- `ui-nyla/src/pages/basedata/FilesPage.tsx` - `frontend_nyla/src/pages/basedata/FilesPage.tsx`
- `ui-nyla/src/components/UnifiedDataBar/FilesTab.tsx` - `frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx`
entfernt und durch `FormGeneratorTable` mit `groupingConfig` ersetzt. Begleitend entfernt und durch `FormGeneratorTable` mit `groupingConfig` ersetzt. Begleitend
wurden die Folder-Operationen aus `FileContext.tsx` und `useFiles.ts` reduziert, wurden die Folder-Operationen aus `FileContext.tsx` und `useFiles.ts` reduziert,
`FileInfo.folderId` aus `fileApi.ts` und das Pydantic-Feld `FileItem.folderId` `FileInfo.folderId` aus `fileApi.ts` und das Pydantic-Feld `FileItem.folderId`
aus `platform-core/modules/datamodels/datamodelFiles.py` entfernt. Im Repo liegt das aus `gateway/modules/datamodels/datamodelFiles.py` entfernt. Im Repo liegt das
Archiviertes Skript `platform-core/modules/migrations/_archive/migrate_folders_to_groups.py`, das die Archiviertes Skript `gateway/modules/migrations/_archive/migrate_folders_to_groups.py`, das die
`FileFolder`-Tabelle + `FileItem.folderId`-Spalte in einen JSON-Tree `FileFolder`-Tabelle + `FileItem.folderId`-Spalte in einen JSON-Tree
(`TableGrouping.rootGroups`, Context `files/list`) ueberfuehren *kann* -- per (`TableGrouping.rootGroups`, Context `files/list`) ueberfuehren *kann* -- per
Default `--dry-run`, ohne begleitende Alembic-Migration zum DROP-COLUMN / Default `--dry-run`, ohne begleitende Alembic-Migration zum DROP-COLUMN /
@ -235,7 +235,7 @@ bekommen 1:1 dieselbe Mechanik:
## Ziel und Nicht-Ziele ## Ziel und Nicht-Ziele
- **Ziel 1.** `FormGeneratorTree` als Komponente in - **Ziel 1.** `FormGeneratorTree` als Komponente in
`ui-nyla/src/components/FormGenerator/FormGeneratorTree/` mit `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/` mit
Provider-Interface, Built-in-Features (Multiselect, Cascade, DnD, Provider-Interface, Built-in-Features (Multiselect, Cascade, DnD,
Inline-Edit, Scope-/Neutralize-Indikatoren) und Backend-Attribut-Resolution. Inline-Edit, Scope-/Neutralize-Indikatoren) und Backend-Attribut-Resolution.
- **Ziel 2.** `FolderFileProvider` als erste Implementierung; recovered die - **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 - [ ] Optional: `SELECT COUNT(*) FROM "FileFolder"` und Stichprobe pro Mandant
auf Datenkonsistenz auf Datenkonsistenz
**Hinweis (dev):** `python -m scripts.stage0_filefolder_schema_check` im Ordner `platform-core`. **Hinweis (dev):** `python -m scripts.stage0_filefolder_schema_check` im Ordner `gateway`.
> Falls eine Umgebung abweicht: Plan zurueckziehen, Restore-/Migration- > Falls eine Umgebung abweicht: Plan zurueckziehen, Restore-/Migration-
> Subtask einplanen, **bevor** Stage 1 startet. > Subtask einplanen, **bevor** Stage 1 startet.
@ -656,10 +656,10 @@ Kann bei Bedarf spaeter als eigenes Projekt aufgegriffen werden.
**Checkliste** **Checkliste**
- [x] `wiki/b-reference/ui-nyla/architecture.md`: Komponenten-Tabelle - [x] `wiki/b-reference/frontend-nyla/architecture.md`: Komponenten-Tabelle
um `FormGeneratorTree` ergaenzt, `FolderTree`-Eintrag ersetzt, um `FormGeneratorTree` ergaenzt, `FolderTree`-Eintrag ersetzt,
`components/`-Ordner-Beschreibung aktualisiert `components/`-Ordner-Beschreibung aktualisiert
- [x] `wiki/b-reference/ui-nyla/formgenerator.md`: Abschnitt - [x] `wiki/b-reference/frontend-nyla/formgenerator.md`: Abschnitt
`FormGeneratorTree` (Provider-Interface, Built-in Features, `FormGeneratorTree` (Provider-Interface, Built-in Features,
Vergleichstabelle Tree vs. Table-with-grouping, Props, Verwendung) Vergleichstabelle Tree vs. Table-with-grouping, Props, Verwendung)
- [x] `wiki/TOPICS.md`: Neuer Eintrag FormGenerator (Table, Form, Tree, Report) - [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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1, 2 | api | ja | `platform-core/tests/unit/routes/test_folder_crud.py` | pending | | T1 | 1, 2 | api | ja | `gateway/tests/unit/routes/test_folder_crud.py` | pending |
| T2 | 3 | api | ja | `platform-core/tests/unit/routes/test_folder_cascade_delete.py` | pending | | T2 | 3 | api | ja | `gateway/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 | | 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 | `platform-core/tests/unit/interfaces/test_folderRbac.py` (zwei User; alle Mutationsrouten 403; Render-Regel inkl. `contextOrphan`) | 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 | `ui-nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/FormGeneratorTree.test.tsx` | pending | | T5 | 1-6 | ui | ja | `frontend_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 | | T6 | 6, 11 | ui | ja | `frontend_nyla/src/components/FormGenerator/FormGeneratorTree/__tests__/dnd.test.tsx` | pending |
| T7 | 1-7, 10 | manuell | nein | -- | pending | | T7 | 1-7, 10 | manuell | nein | -- | pending |
| T8 | 9 | manuell | nein | -- | pending | | T8 | 9 | manuell | nein | -- | pending |
| T9 | 7 | 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 - PR: tba (Stage 0+1+2 -- bereit), Stage 3 deferred, Stage 4+5 abgeschlossen
- Issue: -- - Issue: --
- Vorgaenger-Commits: `c8e9304`, `e7a79a3`, `7c05cb0` - Vorgaenger-Commits: `c8e9304`, `e7a79a3`, `7c05cb0`
- Migrations-Skript (archiviert): `platform-core/modules/migrations/_archive/migrate_folders_to_groups.py` - Migrations-Skript (archiviert): `gateway/modules/migrations/_archive/migrate_folders_to_groups.py`
- Heutige `FolderTree`-Komponente (vollstaendig, nicht mehr eingebunden): - Heutige `FolderTree`-Komponente (vollstaendig, nicht mehr eingebunden):
`ui-nyla/src/components/FolderTree/FolderTree.tsx` `frontend_nyla/src/components/FolderTree/FolderTree.tsx`
--- ---
## Abschluss ## Abschluss
- [x] `b-reference/ui-nyla/architecture.md` aktualisiert - [x] `b-reference/frontend-nyla/architecture.md` aktualisiert
(Komponenten-Tabelle, UDB-Beschreibung) (Komponenten-Tabelle, UDB-Beschreibung)
- [x] `b-reference/ui-nyla/formgenerator.md` aktualisiert - [x] `b-reference/frontend-nyla/formgenerator.md` aktualisiert
(Abschnitt FormGeneratorTree) (Abschnitt FormGeneratorTree)
- [x] `TOPICS.md` aktualisiert - [x] `TOPICS.md` aktualisiert
- [x] Dokument verschoben nach `4-done/` - [x] Dokument verschoben nach `4-done/`

View file

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

View file

@ -6,7 +6,7 @@
## Beschreibung und Kontext ## Beschreibung und Kontext
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). 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).
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. 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 ## Betroffene Module
- **Gateway:** - **Gateway:**
- `platform-core/modules/connectors/connectorDbPostgre.py` — Refactor (Pool-Helper, alle 40 `self.connection.*` Stellen) - `gateway/modules/connectors/connectorDbPostgre.py` — Refactor (Pool-Helper, alle 40 `self.connection.*` Stellen)
- `platform-core/app.py` — Pool-Shutdown-Hook bei FastAPI-Shutdown - `gateway/app.py` — Pool-Shutdown-Hook bei FastAPI-Shutdown
- `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py` — neue Concurrency-Tests - `gateway/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 - **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 - **Frontend:** keine
- **DB-Migration:** nein (keine Schema-Änderung) - **DB-Migration:** nein (keine Schema-Änderung)
- **Andere Komponenten:** keine (service-llm-private, teams-bot, frontend nicht betroffen) - **Andere Komponenten:** keine (private-llm, teams-bot, frontend nicht betroffen)
## Entscheidungen ## 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] `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] 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] 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 `platform-core/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 `gateway/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] 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] 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)** - [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:** **Abschluss:**
- Notiz unter `local/notes/2026-05-pool-smoke-1h.md` mit: - Notiz unter `local/notes/2026-05-pool-smoke-1h.md` mit:
- Start/Endzeit - Start/Endzeit
- Auffälligkeiten in den Logs (sollten keine sein) — `grep -E "another command|pool exhausted|connection pool" platform-core/local/logs/log_app_<datum>.log` - Auffälligkeiten in den Logs (sollten keine sein) — `grep -E "another command|pool exhausted|connection pool" gateway/local/logs/log_app_<datum>.log`
- `pg_stat_activity` Snapshots zu Beginn / Mitte / Ende - `pg_stat_activity` Snapshots zu Beginn / Mitte / Ende
- RAM-Verlauf 3 Werte - RAM-Verlauf 3 Werte
- Bei Erfolg: Diese Plan-Doc nach `c-work/3-validate/` verschieben, dann S8 (Doku-Sync) anstossen. - 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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|---------------|-----------|--------| |----|----|-----|---------------|-----------|--------|
| T1 | 2 | unit (concurrency) | ja | `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_concurrent_getRecordset_50threads` | pending | | T1 | 2 | unit (concurrency) | ja | `gateway/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 | | 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 | `platform-core/tests/unit/connectors/test_connectorDbPostgre_failLoud.py::test_statement_timeout_returns_conn_to_pool` | 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 | `platform-core/tests/integration/test_pool_shutdown.py` + `pg_stat_activity` check | pending | | T4 | 5 | manual+integration | teilweise | `gateway/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 | | T5 | 6 | regression | ja | `gateway/tests/unit/connectors/`, `gateway/tests/integration/` (alle bestehenden) | pending |
| T6 | 1 | smoke (manuell) | nein | `local/notes/2026-05-pool-smoke-1h.md` mit Polling-Log + Memory-Verlauf | 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 ## Schritt-für-Schritt-Umsetzung mit LLM-Empfehlung
@ -184,7 +184,7 @@ Neue Datei oder Modul-Section in `connectorDbPostgre.py`:
**LLM:** `composer-2-fast` **LLM:** `composer-2-fast`
- In `platform-core/app.py` FastAPI `lifespan`-Handler (oder `on_event("shutdown")` falls Codebase noch das alte Pattern nutzt) → `closeAll()` aufrufen - In `gateway/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) - Bei `lifespan` zusätzlich Startup-Hook für initialen Pool-Warmup (optional)
### S5 — Concurrency-Tests ### S5 — Concurrency-Tests
@ -200,7 +200,7 @@ Neue Datei oder Modul-Section in `connectorDbPostgre.py`:
**LLM:** `composer-2-fast` (nur Run + Fix-Loop) **LLM:** `composer-2-fast` (nur Run + Fix-Loop)
- `pytest platform-core/tests/unit/connectors/ platform-core/tests/integration/` → grün - `pytest gateway/tests/unit/connectors/ gateway/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`) - 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 ### S7 — Smoke-Test 1 h

View file

@ -24,7 +24,7 @@ Jede Phase referenziert sie.
| # | Befund | Datei / Stelle | Konsequenz für Plan | | # | Befund | Datei / Stelle | Konsequenz für Plan |
|---|--------|----------------|---------------------| |---|--------|----------------|---------------------|
| 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`. | | 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`. |
| 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. | | 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. | | 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. | | 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 ### A.1 `DataSource`-Modell umbenennen
- **Datei:** `platform-core/modules/datamodels/datamodelDataSource.py` - **Datei:** `gateway/modules/datamodels/datamodelDataSource.py`
- **Änderung:** - **Änderung:**
- `autoSync: bool = Field(default=False, ...)`**umbenennen** zu - `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"})` `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 ### A.2 DB-Migration
- **Datei:** `platform-core/modules/migrations/migrationXXX_renameDataSourceFields.py` (neu — Nummer aus aktueller Migrations-Folge ableiten) - **Datei:** `gateway/modules/migrations/migrationXXX_renameDataSourceFields.py` (neu — Nummer aus aktueller Migrations-Folge ableiten)
- **SQL:** - **SQL:**
```sql ```sql
ALTER TABLE poweron_app."DataSource" RENAME COLUMN "autoSync" TO "ragIndexEnabled"; 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 ### A.3 `UserConnection.knowledgePreferences` Schema-Doku reduzieren
- **Datei:** `platform-core/modules/datamodels/datamodelUam.py` - **Datei:** `gateway/modules/datamodels/datamodelUam.py`
- **Änderung:** Field-Description von `knowledgePreferences` aktualisieren — entferne Erwähnung von: - **Änderung:** Field-Description von `knowledgePreferences` aktualisieren — entferne Erwähnung von:
- `neutralizeBeforeEmbed` (kommt nach `DataSource.neutralize`) - `neutralizeBeforeEmbed` (kommt nach `DataSource.neutralize`)
- `surfaceToggles` (obsolet — pro DataSource via `ragIndexEnabled`) - `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 ### A.4 Pref-Loader bereinigen
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py` - **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py`
- **Änderung:** Felder `neutralizeBeforeEmbed`, `mimeAllowlist`, `surfaceToggles` aus `loadConnectionPrefs`-Output entfernen (DTO + Defaults). - **Ä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. - **Wirkung:** Walker dürfen `prefs.neutralizeBeforeEmbed` nicht mehr lesen — wird in Phase B durch DataSource-Lookup ersetzt.
### A.5 Cancel-API in Background-Jobs ### A.5 Cancel-API in Background-Jobs
- **Datei:** `platform-core/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py` - **Datei:** `gateway/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Neue Funktion** (nach `_markError`, vor `_makeProgressCallback`): - **Neue Funktion** (nach `_markError`, vor `_makeProgressCallback`):
```python ```python
def cancelJob(jobId: str, *, reason: str = "user_requested") -> bool: 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 ### A.6 Stop-Job-Helfer für Connection
- **Datei:** `platform-core/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py` - **Datei:** `gateway/modules/serviceCenter/services/serviceBackgroundJobs/mainBackgroundJobService.py`
- **Neue Funktion:** - **Neue Funktion:**
```python ```python
def cancelJobsByConnection(connectionId: str, *, jobType: str = "connection.bootstrap") -> int: 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 ### A.7 Knowledge-Interface Purge-Methoden ergänzen
- **Datei:** `platform-core/modules/interfaces/interfaceDbKnowledge.py` - **Datei:** `gateway/modules/interfaces/interfaceDbKnowledge.py`
- **Bestehend:** `deleteFileContentIndexByConnectionId(connectionId)` (Z. 96). - **Bestehend:** `deleteFileContentIndexByConnectionId(connectionId)` (Z. 96).
- **Neu:** - **Neu:**
- `deleteFileContentIndexByDataSource(dataSourceId: str) -> Dict[str, int]` — purgt Chunks deren `provenance.dataSourceId == dataSourceId`. - `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 ### B.1 Bootstrap-Dispatcher umstellen
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py` - **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py`
- **Änderung in `_bootstrapJobHandler`** (Z. 125238): - **Änderung in `_bootstrapJobHandler`** (Z. 125238):
1. **Vor jedem Authority-Branch:** DataSources der Connection laden: 1. **Vor jedem Authority-Branch:** DataSources der Connection laden:
```python ```python
@ -259,7 +259,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### B.4 Effektive Policy aus DataSource (mit Tree-Vererbung) ### B.4 Effektive Policy aus DataSource (mit Tree-Vererbung)
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/subPolicyResolver.py` **(neu)** - **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/subPolicyResolver.py` **(neu)**
- **Funktion:** - **Funktion:**
```python ```python
def resolveEffectivePolicy( def resolveEffectivePolicy(
@ -304,7 +304,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.1 `routeDataConnections` GET-Response erweitern ### C.1 `routeDataConnections` GET-Response erweitern
- **Datei:** `platform-core/modules/routes/routeDataConnections.py` - **Datei:** `gateway/modules/routes/routeDataConnections.py`
- **Refactor:** `_buildEnhancedItems` (Z. 183202) zu Helper-Funktion erheben: - **Refactor:** `_buildEnhancedItems` (Z. 183202) zu Helper-Funktion erheben:
```python ```python
def _buildConnectionDict(connection, tokenStatus, tokenExpiresAt) -> Dict[str, Any]: 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` ### C.2 Neue PATCH-Endpoints `routeDataConnections`
- **Datei:** `platform-core/modules/routes/routeDataConnections.py` - **Datei:** `gateway/modules/routes/routeDataConnections.py`
- **Endpoints:** - **Endpoints:**
```python ```python
@ -382,7 +382,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.3 Neuer PATCH `routeDataSources/rag-index` ### C.3 Neuer PATCH `routeDataSources/rag-index`
- **Datei:** `platform-core/modules/routes/routeDataSources.py` - **Datei:** `gateway/modules/routes/routeDataSources.py`
- **Neuer Endpoint nach Z. 127:** - **Neuer Endpoint nach Z. 127:**
```python ```python
@router.patch("/{sourceId}/rag-index") @router.patch("/{sourceId}/rag-index")
@ -405,7 +405,7 @@ Pro Walker-Datei (`subConnectorSyncSharepoint.py`, `subConnectorSyncOutlook.py`,
### C.4 Neuer Route-Block `routeRagInventory` ### C.4 Neuer Route-Block `routeRagInventory`
- **Datei:** `platform-core/modules/routes/routeRagInventory.py` **(neu)** - **Datei:** `gateway/modules/routes/routeRagInventory.py` **(neu)**
- **Endpoints:** - **Endpoints:**
``` ```
GET /api/rag/inventory/me → eigene Daten (Connections + DataSources + Chunks-Counts) 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 ### C.5 WorkspaceRagInsights-Backend-Route entfernen
- **Datei:** `platform-core/modules/features/workspace/routeFeatureWorkspace.py` - **Datei:** `gateway/modules/features/workspace/routeFeatureWorkspace.py`
- **Löschen:** Ab Z. 2219 (`@router.get("/{instanceId}/rag-statistics")`) bis Funktionsende. - **Löschen:** Ab Z. 2219 (`@router.get("/{instanceId}/rag-statistics")`) bis Funktionsende.
- **Datei:** `platform-core/modules/features/workspace/mainWorkspace.py` - **Datei:** `gateway/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.) - **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:** `platform-core/modules/interfaces/interfaceDbKnowledge.py` - **Datei:** `gateway/modules/interfaces/interfaceDbKnowledge.py`
- **Löschen oder behalten?** `getRagStatisticsForInstance` (Z. 421) — falls keine anderen Aufrufer (Audit per Suche), löschen. Sonst behalten. - **Löschen oder behalten?** `getRagStatisticsForInstance` (Z. 421) — falls keine anderen Aufrufer (Audit per Suche), löschen. Sonst behalten.
### C.6 Acceptance-Gate Phase C ### 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 ### D.1 `connectionApi.ts` reduzieren
- **Datei:** `ui-nyla/src/api/connectionApi.ts` - **Datei:** `frontend_nyla/src/api/connectionApi.ts`
- **Änderung:** - **Änderung:**
- `KnowledgePreferences`-Type: `neutralizeBeforeEmbed`, `surfaceToggles`, `mimeAllowlist` entfernen. - `KnowledgePreferences`-Type: `neutralizeBeforeEmbed`, `surfaceToggles`, `mimeAllowlist` entfernen.
- **Neue API-Methoden:** - **Neue API-Methoden:**
@ -485,7 +485,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.2 `useConnections` Hook erweitern ### D.2 `useConnections` Hook erweitern
- **Datei:** `ui-nyla/src/hooks/useConnections.ts` - **Datei:** `frontend_nyla/src/hooks/useConnections.ts`
- **Neu exportieren:** - **Neu exportieren:**
- `setKnowledgeConsent(connectionId, enabled)` — wrapt `patchKnowledgeConsent` + `refetch()`. - `setKnowledgeConsent(connectionId, enabled)` — wrapt `patchKnowledgeConsent` + `refetch()`.
- `setKnowledgePreferences(connectionId, prefs, opts)` — wrapt `patchKnowledgePreferences` + `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 ### D.3 `AddConnectionWizard.tsx` Komplett-Refactor
- **Datei:** `ui-nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx` - **Datei:** `frontend_nyla/src/components/AddConnectionWizard/AddConnectionWizard.tsx`
- **Entfernen:** - **Entfernen:**
- `computeCostEstimate` (Z. 71151). - `computeCostEstimate` (Z. 71151).
- Step 2 (Preferences): Z. 302397. - 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 ### D.4 `ConnectionsPage.tsx` aufräumen
- **Datei:** `ui-nyla/src/pages/basedata/ConnectionsPage.tsx` - **Datei:** `frontend_nyla/src/pages/basedata/ConnectionsPage.tsx`
- **Entfernen:** - **Entfernen:**
- `adminConsentPending` State + Handler (Z. 57, alle Verwendungen). - `adminConsentPending` State + Handler (Z. 57, alle Verwendungen).
- `infomaniakModal` State + `handleCreateInfomaniak`, `handleInfomaniakCancel`, `handleInfomaniakSubmit` (Z. 78...). - `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` ### D.5 Neue Komponente `KnowledgePreferencesDrawer`
- **Datei:** `ui-nyla/src/components/KnowledgePreferencesDrawer/KnowledgePreferencesDrawer.tsx` **(neu)** - **Datei:** `frontend_nyla/src/components/KnowledgePreferencesDrawer/KnowledgePreferencesDrawer.tsx` **(neu)**
- **Inhalt:** Felder analog zu altem Wizard-Step 2, aber **ohne** `neutralizeBeforeEmbed`: - **Inhalt:** Felder analog zu altem Wizard-Step 2, aber **ohne** `neutralizeBeforeEmbed`:
- `mailContentDepth` (Select: metadata / snippet / full) - `mailContentDepth` (Select: metadata / snippet / full)
- `mailIndexAttachments` (Checkbox) - `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` ### D.6 `SourcesTab.tsx` — 4. Action-Button für `ragIndexEnabled`
- **Datei:** `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` - **Datei:** `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- **Erweiterungen:** - **Erweiterungen:**
1. Type `UdbDataSource` (Z. 3645): `ragIndexEnabled: boolean` ergänzen. 1. Type `UdbDataSource` (Z. 3645): `ragIndexEnabled: boolean` ergänzen.
2. **Konstante neu:** 2. **Konstante neu:**
@ -584,7 +584,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### D.7 Neue Seite `RagInventoryPage.tsx` ### D.7 Neue Seite `RagInventoryPage.tsx`
- **Datei:** `ui-nyla/src/pages/system/RagInventoryPage.tsx` **(neu)** - **Datei:** `frontend_nyla/src/pages/system/RagInventoryPage.tsx` **(neu)**
- **3 Tabs (`PageTabsLayout`-Komponente):** - **3 Tabs (`PageTabsLayout`-Komponente):**
| Tab | Endpoint | Sichtbarkeit | Inhalt | | 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` ### D.8 Navigation: `Start > Nutzung > RAG-Inventar`
- **Datei:** `platform-core/modules/system/mainSystem.py` - **Datei:** `gateway/modules/system/mainSystem.py`
- **Neuer Eintrag** unter Gruppe „Nutzung" (vermutlich `usage` / `nutzung`): - **Neuer Eintrag** unter Gruppe „Nutzung" (vermutlich `usage` / `nutzung`):
```python ```python
{ {
@ -608,7 +608,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
"order": NN, "order": NN,
} }
``` ```
- **Datei:** `ui-nyla/src/config/pageRegistry.tsx` - **Datei:** `frontend_nyla/src/config/pageRegistry.tsx`
- **Mapping:** - **Mapping:**
```tsx ```tsx
'page.system.ragInventory': { component: lazy(() => import('../pages/system/RagInventoryPage')), icon: FaDatabase }, '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` ### D.9 Header-Badge `RagRunningBadge`
- **Datei:** `ui-nyla/src/components/Header/RagRunningBadge.tsx` **(neu)** - **Datei:** `frontend_nyla/src/components/Header/RagRunningBadge.tsx` **(neu)**
- **Logik:** - **Logik:**
- `useEffect`: alle 5s `getRagJobsActive()`; State `count: number`. - `useEffect`: alle 5s `getRagJobsActive()`; State `count: number`.
- Render: nur wenn `count > 0` — kleines Icon (`FaSync` rotierend) mit Badge `count`; Click → Navigate `/system/rag-inventory`. - 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 ### D.10 Workspace-Insights-Seite löschen
- **Löschen:** - **Löschen:**
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx` - `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx`
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.module.css` - `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.module.css`
- **Datei:** `ui-nyla/src/pages/FeatureView.tsx` - **Datei:** `frontend_nyla/src/pages/FeatureView.tsx`
- **Entfernen:** Import Z. 38, Mapping `'rag-insights': WorkspaceRagInsightsPage` Z. 158. - **Entfernen:** Import Z. 38, Mapping `'rag-insights': WorkspaceRagInsightsPage` Z. 158.
- **Datei:** `ui-nyla/src/pages/views/workspace/WorkspacePage.tsx` - **Datei:** `frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx`
- **Prüfen:** Ob Verweise auf die Insights-Seite (Buttons, Links) drin sind — entfernen. - **Prüfen:** Ob Verweise auf die Insights-Seite (Buttons, Links) drin sind — entfernen.
- **Datei:** `ui-nyla/src/api/mandate.ts` (oder vergleichbare Mapping-Stelle) - **Datei:** `frontend_nyla/src/api/mandate.ts` (oder vergleichbare Mapping-Stelle)
- **Prüfen:** Ob Workspace-Sub-View `'rag-insights'` enumeriert ist — entfernen. - **Prüfen:** Ob Workspace-Sub-View `'rag-insights'` enumeriert ist — entfernen.
### D.11 Acceptance-Gate Phase D ### 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 ### E.1 Backend-Integrationstests
- **Datei:** `platform-core/modules/serviceCenter/services/serviceKnowledge/tests/test_bootstrapDispatcher.py` (neu/erweitern) - **Datei:** `gateway/modules/serviceCenter/services/serviceKnowledge/tests/test_bootstrapDispatcher.py` (neu/erweitern)
- **Tests:** - **Tests:**
- `test_bootstrap_skipsIfNoRagEnabledDataSources` - `test_bootstrap_skipsIfNoRagEnabledDataSources`
- `test_bootstrap_iteratesOnlyRagEnabledDataSources` - `test_bootstrap_iteratesOnlyRagEnabledDataSources`
@ -667,7 +667,7 @@ neue `RagInventoryPage` ist erreichbar; Header-Badge zeigt laufende Jobs; alte W
### E.3 Frontend-Integrationstests ### E.3 Frontend-Integrationstests
- **Datei:** `ui-nyla/cypress/integration/ragConsentControl.spec.ts` (neu, falls Cypress vorhanden) - **Datei:** `frontend_nyla/cypress/integration/ragConsentControl.spec.ts` (neu, falls Cypress vorhanden)
- **Tests:** - **Tests:**
- Wizard MSFT-Flow inkl. Admin-Consent-Step - Wizard MSFT-Flow inkl. Admin-Consent-Step
- Wizard Infomaniak-Flow inkl. PAT-Cancel - Wizard Infomaniak-Flow inkl. PAT-Cancel

View file

@ -1,7 +1,7 @@
<!-- status: done --> <!-- status: done -->
<!-- started: 2026-05-12 --> <!-- started: 2026-05-12 -->
<!-- lastReviewed: 2026-05-15 --> <!-- lastReviewed: 2026-05-15 -->
<!-- component: gateway | ui-nyla | platform --> <!-- component: gateway | frontend-nyla | platform -->
# Unified RAG Consent, Neutralization and Visibility — Single Source of Truth # 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 ### Kritische Stellen im Code
- `platform-core/modules/serviceCenter/services/serviceKnowledge/subConnectorIngestConsumer.py` — Bootstrap-Dispatcher: muss Walker auf DataSource-Iteration umstellen + Cancel-Flag prüfen. - `gateway/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`. - `gateway/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. - `gateway/modules/serviceCenter/services/serviceKnowledge/subConnectorPrefs.py` — `neutralizeBeforeEmbed`, `mimeAllowlist`, `surfaceToggles` raus.
- `platform-core/modules/datamodels/datamodelUam.py` — `knowledgePreferences` Schema-Doku anpassen. - `gateway/modules/datamodels/datamodelUam.py` — `knowledgePreferences` Schema-Doku anpassen.
- `platform-core/modules/datamodels/datamodelDataSource.py` — `autoSync``ragIndexEnabled` (oder umdokumentieren); ggf. `lastIndexed`-Feld hinzufügen. - `gateway/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. - `gateway/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. - `gateway/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. - `gateway/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)`. - `gateway/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. - `gateway/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`. - **NEU** `gateway/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`. - `gateway/modules/system/mainSystem.py` — Navigation `Nutzung > RAG-Inventar`.
- `ui-nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx` + `.module.css`**löschen**. - `frontend_nyla/src/pages/views/workspace/WorkspaceRagInsightsPage.tsx` + `.module.css`**löschen**.
- `ui-nyla/src/types/mandate.ts` — `rag-insights` raus. - `frontend_nyla/src/types/mandate.ts` — `rag-insights` raus.
- `ui-nyla/src/pages/FeatureView.tsx`, `App.tsx` — Route + Mapping raus. - `frontend_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. - `frontend_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). - `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).
- `ui-nyla/src/api/connectionApi.ts` — `KnowledgePreferences` reduzieren; neue API-Methoden. - `frontend_nyla/src/api/connectionApi.ts` — `KnowledgePreferences` reduzieren; neue API-Methoden.
- **NEU** `ui-nyla/src/pages/system/RagInventoryPage.tsx` — Drei-Tab-Seite (Meine / Mandant / Plattform). - **NEU** `frontend_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. - `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** `ui-nyla/src/components/Header/RagRunningBadge.tsx` — globales Header-Badge mit Anzahl laufender Bootstrap-Jobs + Click-through zur RAG-Inventar. - **NEU** `frontend_nyla/src/components/Header/RagRunningBadge.tsx` — globales Header-Badge mit Anzahl laufender Bootstrap-Jobs + Click-through zur RAG-Inventar.
### Bekannte Fallstricke ### 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] **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] **Backend-Integrationstests:** manuell verifiziert (Smoke-Tests, 2026-05-15).
- [x] **Frontend-Tests:** manuell verifiziert (2026-05-15). - [x] **Frontend-Tests:** manuell verifiziert (2026-05-15).
- [x] **Wiki-Updates:** `b-reference/platform-core/ai-agent.md` aktualisiert; `TOPICS.md` enthält RAG-Inventar-Eintrag. - [x] **Wiki-Updates:** `b-reference/gateway/ai-agent.md` aktualisiert; `TOPICS.md` enthält RAG-Inventar-Eintrag.
## Akzeptanzkriterien ## Akzeptanzkriterien
@ -350,14 +350,14 @@ Diese Frage muss **drei** UI-Plätze ohne Lücke abdecken:
## Links ## Links
- Vorgänger-Plan: `wiki/c-work/4-done/2026-04-id-unified-knowledge-indexing-rag-concept.md` - 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/platform-core/ai-agent.md`, `wiki/b-reference/ui-nyla/architecture.md` - Architektonisch betroffen: `wiki/b-reference/platform/neutralization.md`, `wiki/b-reference/gateway/ai-agent.md`, `wiki/b-reference/frontend-nyla/architecture.md`
- Code-Touchpoints: siehe Abschnitt „Kritische Stellen im Code" - Code-Touchpoints: siehe Abschnitt „Kritische Stellen im Code"
## Abschluss ## Abschluss
- [x] `b-reference/platform-core/ai-agent.md` aktualisiert (Knowledge Lifecycle, DataSource-getriebener Walker, Cancel-Mechanismus) - [x] `b-reference/gateway/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/platform/neutralization.md` aktualisiert (DataSource = SSoT, kein neutralizeBeforeEmbed mehr, Tree-Vererbung via subPolicyResolver) — 2026-05-15
- [x] `b-reference/ui-nyla/architecture.md` aktualisiert (RagInventoryPage, UDB 4. Action-Button, RagRunningBadge, AddConnectionWizard) — 2026-05-15 - [x] `b-reference/frontend-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] `TOPICS.md` aktualisiert (RAG-Inventar als neuer Kanon-Eintrag)
- [x] Dieses Dokument in `c-work/4-done/` (Status → `done`, 2026-05-15) - [x] Dieses Dokument in `c-work/4-done/` (Status → `done`, 2026-05-15)
- [x] Eintrag im `c-work/_CHANGELOG.md` - [x] Eintrag im `c-work/_CHANGELOG.md`

View file

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

View file

@ -1,7 +1,7 @@
<!-- status: build --> <!-- status: build -->
<!-- started: 2026-05-17 --> <!-- started: 2026-05-17 -->
<!-- completed: 2026-05-17 --> <!-- completed: 2026-05-17 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
# UDB DataSource Settings (⚙️) + konfigurierbare RAG-Limits # UDB DataSource Settings (⚙️) + konfigurierbare RAG-Limits
@ -14,14 +14,6 @@
> Das Modal zeigt fehlende Werte als Placeholder aus dem Cost-Estimate-Endpoint > 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 > 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. > 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 ## Beschreibung und Kontext
@ -61,7 +53,7 @@ Wichtiger Architektur-Constraint:
- **Nicht-Ziel:** - **Nicht-Ziel:**
- Mandate-weite Defaults / Override-Schichten / Resolver-Layer. - Mandate-weite Defaults / Override-Schichten / Resolver-Layer.
- Hard-Caps (User/Admin trägt Verantwortung). - Hard-Caps (User/Admin trägt Verantwortung).
- ~~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. - Settings-Vererbung im Tree (Parent-Folder → Children) aktuell wirkt eine Änderung nur auf die konkrete DataSource.
- 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. - 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 ## Architektur-Skizze
@ -108,7 +100,7 @@ MAX_ITEMS_DEFAULT = 10_000
``` ```
Wird zu: Wird zu:
```python ```python
# platform-core/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py # gateway/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py
RAG_LIMITS_DEFAULT = { RAG_LIMITS_DEFAULT = {
"maxBytes": 200 * 1024 * 1024, "maxBytes": 200 * 1024 * 1024,
"maxFileSize": 25 * 1024 * 1024, "maxFileSize": 25 * 1024 * 1024,
@ -175,15 +167,15 @@ Auf der `RagInventoryPage`-Partial-Banner-Komponente:
## Schritte ## Schritte
- [ ] 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`. - [ ] 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: `platform-core/modules/serviceCenter/services/serviceKnowledge/_ragLimits.py` neu mit `RAG_LIMITS_DEFAULT`, `getRagLimits()`, `lazyFillRagLimits()`. - [ ] S2 — Zentralisierte Defaults: `gateway/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. - [ ] 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. - [ ] 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. - [ ] 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. - [ ] 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). - [ ] 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. - [ ] S8 — Audit-Logging in den neuen Settings-Endpunkten.
- [ ] S9 — Cost-Estimate-Engine: `platform-core/modules/serviceCenter/services/serviceKnowledge/_costEstimate.py` mit Heuristik (Items × Tokens × Embedding-Preis) und Basis-Annahmen-Output. - [ ] S9 — Cost-Estimate-Engine: `gateway/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). - [ ] 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. - [ ] 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 --> <!-- status: done -->
<!-- started: 2026-05-18 --> <!-- started: 2026-05-18 -->
<!-- completed: 2026-05-18 --> <!-- completed: 2026-05-18 -->
<!-- component: gateway | ui-nyla --> <!-- component: gateway | frontend-nyla -->
<!-- lastReviewed: 2026-05-18 --> <!-- lastReviewed: 2026-05-18 -->
<!-- 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 --> <!-- 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 -->
# UDB Generic Tree Refactor (Backend authoritativ, FE pure Renderer) # UDB Generic Tree Refactor (Backend authoritativ, FE pure Renderer)
@ -62,7 +62,7 @@ Stable, parsebar, kollisionsfrei. Pipe-Separator:
### Builder ### Builder
`platform-core/modules/serviceCenter/services/serviceKnowledge/_buildTree.py` orchestriert pro Request: `gateway/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. - Vor-Laden aller DataSource-Records des Users (`recordFilter={"userId": userId}`) und aller FeatureDataSource-Records des Workspaces (`recordFilter={"workspaceInstanceId": instanceId}`) einmal.
- Dispatch pro Parent-Kind: - Dispatch pro Parent-Kind:
- `null` -> aktive Connections + zugaengliche Mandanten-Gruppen - `null` -> aktive Connections + zugaengliche Mandanten-Gruppen
@ -143,7 +143,7 @@ Erhalten (haben weitere Konsumenten ausserhalb UDB):
## Tests ## Tests
Neu: Neu:
- `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). - `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).
- 5 neue Tests in `test_inheritFlags.py::TestResolveEffectiveForFds`: RAG inherits when only neutralize overridden; RAG aggregate-mixed; `_INHERITABLE_FDS_FLAGS` contains all 3 keys. - 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`. - `TestCascadeResetFdsRag::test_cascade_resets_rag_on_descendants`.
@ -153,9 +153,9 @@ Frontend: `npx tsc --noEmit --skipLibCheck` clean.
## Verifizierte Datei-Pfade ## Verifizierte Datei-Pfade
- 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` - 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: `ui-nyla/src/components/UnifiedDataBar/SourcesTab.tsx` - Frontend: `frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx`
- Tests: `platform-core/tests/unit/services/test_buildTree.py`, `test_inheritFlags.py` - Tests: `gateway/tests/unit/services/test_buildTree.py`, `test_inheritFlags.py`
## Nachtrag 2026-05-26: Spec Recovery ## Nachtrag 2026-05-26: Spec Recovery

View file

@ -8,38 +8,12 @@ Eine Zeile pro Change, NEUESTE EINTRAEGE ZUOBERST. Begruendungen gehoeren ins zu
`c-work/<phase>/<feature>.md` oder die PR-Beschreibung. `c-work/<phase>/<feature>.md` oder die PR-Beschreibung.
Format: `- YYYY-MM-DD | <type> | <scope> | <Kurzbeschreibung> [(c-work: <relPfad>)] [(PR: #123)]` Format: `- YYYY-MM-DD | <type> | <scope> | <Kurzbeschreibung> [(c-work: <relPfad>)] [(PR: #123)]`
type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `platform-core` `ui-nyla` `service-llm-private` `service-preprocessing` `teams-bot` `wiki` `infra` `*` type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `gateway` `frontend-nyla` `private-llm` `teams-bot` `wiki` `infra` `*`
Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler. 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
- 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-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 ## 2026-05-27

View file

@ -1,6 +1,6 @@
<!-- status: plan | build | validate | done --> <!-- status: plan | build | validate | done -->
<!-- started: YYYY-MM-DD --> <!-- started: YYYY-MM-DD -->
<!-- component: gateway | ui-nyla | service-llm-private | teams-bot | platform --> <!-- component: gateway | frontend-nyla | private-llm | teams-bot | platform -->
# <Feature/Refactor Titel> # <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 | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | api | ja | platform-core/tests/... | pending | | T1 | 1 | api | ja | gateway/tests/... | pending |
## Links ## 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 **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 `ui-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 `frontend_nyla/src/api.ts`) und die `_requestContextMiddleware` (`app.py`) in eine `ContextVar` schreibt — analog zum `_setLanguage`-Pattern.
```python ```python
from modules.shared.timeUtils import getUtcTimestamp, getRequestNow 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. **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 `ui-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 `frontend_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 ### 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 ## Projektstruktur Gateway
``` ```
platform-core/ gateway/
app.py # FastAPI-App, Middleware, Startup app.py # FastAPI-App, Middleware, Startup
config.ini # Statische Konfiguration config.ini # Statische Konfiguration
modules/ modules/
@ -392,7 +392,7 @@ def getAgentOntology() -> OntologyDescriptor:
return _ONTOLOGY 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/platform-core/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie" und `b-reference/platform-core/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/gateway/ai-agent.md` Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie" und `b-reference/gateway/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. **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 ## Gateway starten
```bash ```bash
cd platform-core/ cd gateway/
# Python-Umgebung aktivieren (Conda oder venv) # Python-Umgebung aktivieren (Conda oder venv)
conda activate <env> conda activate <env>
# oder: python -m venv .venv && .\.venv\Scripts\Activate.ps1 # oder: python -m venv .venv && .\.venv\Scripts\Activate.ps1
@ -21,7 +21,7 @@ conda activate <env>
pip install -r requirements.txt pip install -r requirements.txt
# Config vorbereiten: # Config vorbereiten:
# 1. config.ini muss im platform-core/ Verzeichnis liegen (statische Settings) # 1. config.ini muss im gateway/ Verzeichnis liegen (statische Settings)
# 2. .env Datei aus env_dev.env kopieren/symlinken: # 2. .env Datei aus env_dev.env kopieren/symlinken:
# copy env_dev.env .env # copy env_dev.env .env
# 3. APP_KEY_SYSVAR in config.ini zeigt auf Master-Key (OS-Variable oder Dateipfad) # 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 | | Datei | Zweck |
|-------|-------| |-------|-------|
| `platform-core/config.ini` | Statische Settings (Auth-Defaults, Upload-Limits, Operator-Text) | | `gateway/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 | | `gateway/.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) | | `gateway/env_dev.env` | Dev-Umgebung Template (verschluesselte Secrets mit `DEV_ENC:` Prefix) |
| `platform-core/env_int.env` | Integration-Umgebung | | `gateway/env_int.env` | Integration-Umgebung |
| `platform-core/env_prod.env` | Produktion | | `gateway/env_prod.env` | Produktion |
### Wichtige Env-Variablen (Auszug) ### Wichtige Env-Variablen (Auszug)
@ -53,7 +53,7 @@ uvicorn app:app --host 0.0.0.0 --port 8000
## Frontend Nyla starten ## Frontend Nyla starten
```bash ```bash
cd ui-nyla/ cd frontend_nyla/
npm install npm install
npm run dev npm run dev
# oder: npx vite --port 5176 --mode 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 | | Datei | Zweck |
|-------|-------| |-------|-------|
| `ui-nyla/config/.env.dev` | Dev-Mode Env (VITE_API_BASE_URL etc.) | | `frontend_nyla/config/.env.dev` | Dev-Mode Env (VITE_API_BASE_URL etc.) |
| `ui-nyla/config/.env.int` | Integration | | `frontend_nyla/config/.env.int` | Integration |
| `ui-nyla/config/.env.prod` | Produktion | | `frontend_nyla/config/.env.prod` | Produktion |
## Secrets-Verwaltung ## 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 ### 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 `platform-core` 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 `gateway` 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. `platform-core`), 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. `gateway`), 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.: - **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` - Windows PowerShell im Repo-Root: `python -m venv .venv && .\.venv\Scripts\Activate.ps1`
- `pip install -r requirements.txt` - `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`). - 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). - **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 `platform-core` 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 `gateway` automatisch zu `sys.path` hinzu.
--- ---
@ -27,9 +27,9 @@ Hinweis: Das Tool importiert `encryptValue` aus `modules/shared/configuration.py
``` ```
cryptography>=41.0.0 cryptography>=41.0.0
``` ```
Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `platform-core/requirements.txt`. Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `gateway/requirements.txt`.
2. Notwendige Gateway-Komponenten (sofern außerhalb von `platform-core` verwendet): 2. Notwendige Gateway-Komponenten (sofern außerhalb von `gateway` verwendet):
- `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_getMasterKey`, `encryptValue`, `decryptValue`) - `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_getMasterKey`, `encryptValue`, `decryptValue`)
- Optional, aber unterstützt: `modules/shared/auditLogger.py` (Audit-Events; Ausfall ist toleriert) - Optional, aber unterstützt: `modules/shared/auditLogger.py` (Audit-Events; Ausfall ist toleriert)
- `config.ini` im gleichen Baum wie `modules`, mit mindestens: - `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>` - `APP_KEY_SYSVAR = <OS_ENV_NAME|Pfad_zur_Keydatei>`
3. Struktur/Importpfade sicherstellen: 3. Struktur/Importpfade sicherstellen:
- Entweder das Tool im Ordner ausführen, der die `modules`-Struktur enthält (z. B. `platform-core`). - Entweder das Tool im Ordner ausführen, der die `modules`-Struktur enthält (z. B. `gateway`).
- Oder `PYTHONPATH` so setzen, dass `modules` auflösbar ist, z. B. PowerShell: - Oder `PYTHONPATH` so setzen, dass `modules` auflösbar ist, z. B. PowerShell:
```powershell ```powershell
$env:PYTHONPATH = (Resolve-Path .) $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 ### 3) Anwendung und Verhalten
Tool: `platform-core/tool_security_encrypt_all_env_files.py` Tool: `gateway/tool_security_encrypt_all_env_files.py`
- Standardlauf (alle drei Dateien, mit Backup): - Standardlauf (alle drei Dateien, mit Backup):
```bash ```bash
@ -125,7 +125,7 @@ Fehlerbilder und Checks:
### Referenz ### Referenz
- Schlüsselauflösung und Verschlüsselung: `platform-core/modules/shared/configuration.py` (`_get_master_key`, `_derive_encryption_key`, `encrypt_value`). - Schlüsselauflösung und Verschlüsselung: `gateway/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`). - Batch-Tool: `gateway/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: 3. If prompted, configure the OAuth consent screen first:
- Choose "External" user type - Choose "External" user type
- Fill in the required fields (App name, User support email, Developer contact information) - Fill in the required fields (App name, User support email, Developer contact information)
- Add scopes (see `platform-core/modules/auth/oauthProviderConfig.py` -- `googleAuthScopes` and `googleDataScopes` are the source of truth): - Add scopes (see `gateway/modules/auth/oauthProviderConfig.py` -- `googleAuthScopes` and `googleDataScopes` are the source of truth):
- **Auth app** (login only): - **Auth app** (login only):
- `openid` - `openid`
- `https://www.googleapis.com/auth/userinfo.profile` - `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 ## Step 4: Configure Porta Application
1. Open your environment file (`platform-core/env_dev.env` for development) 1. Open your environment file (`gateway/env_dev.env` for development)
2. Replace the placeholder values with your actual Google OAuth credentials: 2. Replace the placeholder values with your actual Google OAuth credentials:
```env ```env

View file

@ -21,7 +21,7 @@
| GCP-Projekt-ID | (siehe `env_prod.env`, `Service_GOOGLE_DATA_CLIENT_ID`) | | GCP-Projekt-ID | (siehe `env_prod.env`, `Service_GOOGLE_DATA_CLIENT_ID`) |
| Verwendete Google-Scopes | `openid`, `userinfo.email`, `userinfo.profile`, `gmail.readonly`, `drive.readonly` | | Verwendete Google-Scopes | `openid`, `userinfo.email`, `userinfo.profile`, `gmail.readonly`, `drive.readonly` |
> Bei jeder Änderung an Scopes (`platform-core/modules/auth/oauthProviderConfig.py::googleDataScopes`) > Bei jeder Änderung an Scopes (`gateway/modules/auth/oauthProviderConfig.py::googleDataScopes`)
> diese Tabelle, die OAuth-Consent-Screen-Konfiguration in der GCP-Console > diese Tabelle, die OAuth-Consent-Screen-Konfiguration in der GCP-Console
> **und** die Privacy-Policy synchron halten — Google bouncet sonst die > **und** die Privacy-Policy synchron halten — Google bouncet sonst die
> Verification. > 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 privacy policy link: `https://porta.poweron.swiss/poweron-privacy.html`.
* Application terms of service link: `https://porta.poweron.swiss/poweron-terms.html`. * Application terms of service link: `https://porta.poweron.swiss/poweron-terms.html`.
* [ ] Scope-Liste im Consent-Screen identisch zu `googleDataScopes` in * [ ] Scope-Liste im Consent-Screen identisch zu `googleDataScopes` in
`platform-core/modules/auth/oauthProviderConfig.py`. `gateway/modules/auth/oauthProviderConfig.py`.
* [ ] Jeder Scope hat eine Justification (Kapitel 2 dieses Dokuments). * [ ] Jeder Scope hat eine Justification (Kapitel 2 dieses Dokuments).
* [ ] Demo-Video (Kapitel 3) auf YouTube unlisted, Link im Antrag. * [ ] Demo-Video (Kapitel 3) auf YouTube unlisted, Link im Antrag.
* [ ] Developer-E-Mail `p.motsch@poweron.swiss` empfangsbereit; Eingangs-Mail * [ ] 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. - App-Name, Support-Mail, Developer Contact wie von Google gefordert.
- **Scopes** müssen zur Code-Basis passen (Single Source of Truth): - **Scopes** müssen zur Code-Basis passen (Single Source of Truth):
`platform-core/modules/auth/oauthProviderConfig.py` → `googleAuthScopes`, `googleDataScopes` `gateway/modules/auth/oauthProviderConfig.py` → `googleAuthScopes`, `googleDataScopes`
Kurzreferenz: Kurzreferenz:
@ -61,15 +61,15 @@ Das Gateway unterstützt **getrennte Auth- und Data-Clients** (unterschiedliche
- PROD: `https://gateway-prod.poweron.swiss` - 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. - Forgejo/ALT-Prod (falls genutzt): `https://api.poweron.swiss` — in `env-gateway-prod-forgejo.env` Google `*_REDIRECT_URI` ggf. noch setzen.
Backend-Routing: `platform-core/modules/routes/routeSecurityGoogle.py`. Backend-Routing: `gateway/modules/routes/routeSecurityGoogle.py`.
--- ---
## 4) Speech / Voice (ohne User-OAuth) ## 4) Speech / Voice (ohne User-OAuth)
**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). **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).
Doku STT/TTS: [`b-reference/platform-core/voice-google.md`](../b-reference/platform-core/voice-google.md). Doku STT/TTS: [`b-reference/gateway/voice-google.md`](../b-reference/gateway/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 | | `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) | | `Connector_GoogleSpeech_API_KEY_SECRET` | Speech/TTS API-Key oder SA-JSON (verschlüsselt) |
**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`. **Dateien (Stand Repo):** `gateway/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `gateway/.env`.
Zusätzlich — wenn neues **Frontend** oder neuer **API-Host**: 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 | | Datei | Wann anfassen |
|-------|----------------| |-------|----------------|
| `platform-core/modules/auth/oauthProviderConfig.py` | Neue/entfernte Google-Scopes für Login oder Datenverbindung | | `gateway/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) | | `gateway/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 | | `gateway/modules/auth/tokenManager.py` | Nutzt `Service_GOOGLE_DATA_*` für Refresh — keine manuelle Anpassung bei reiner Registrierung |
Token-Refresh und Microsoft/Google Data: `platform-core/modules/auth/tokenManager.py`. Token-Refresh und Microsoft/Google Data: `gateway/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). Implizite Flow / SPA: für dieses Gateway-Backend-Redirect-Muster **nicht** nötig (Confidential Client mit Secret).
Backend-Routing: `platform-core/modules/routes/routeSecurityMsft.py` (Prefix `/api/msft`). Backend-Routing: `gateway/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**. **API permissions** → **Add a permission****Microsoft Graph****Delegated permissions**.
Single Source of Truth für die Scope-Liste: `platform-core/modules/auth/oauthProviderConfig.py` → `msftAuthScopes`, `msftDataScopes` Single Source of Truth für die Scope-Liste: `gateway/modules/auth/oauthProviderConfig.py` → `msftAuthScopes`, `msftDataScopes`
| Zweck | Graph permissions (delegated) | | 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_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 | | `Service_MSFT_TENANT_ID` | `common` (Multi-Tenant-Anmeldung) **oder** Verzeichnis-ID (GUID) des Tenants **poweron.swiss** für Single-Tenant-Authority |
**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`. **Dateien (Stand Repo):** `gateway/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `gateway/.env`.
Wenn neues **Frontend** oder neuer **API-Host**: Wenn neues **Frontend** oder neuer **API-Host**:
@ -101,10 +101,10 @@ Wenn neues **Frontend** oder neuer **API-Host**:
| Datei | Inhalt | | Datei | Inhalt |
|-------|--------| |-------|--------|
| `platform-core/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` | | `gateway/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` |
| `platform-core/modules/routes/routeSecurityMsft.py` | Login, Connect, Admin-Consent; liest alle `Service_MSFT_*` | | `gateway/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`) | | `gateway/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) | | `gateway/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. 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 | | Bereich | Datei | Was passiert |
|---------|-------|--------------| |---------|-------|--------------|
| 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. | | 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. |
| 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. | | 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.`. | | 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. | | 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) / Unit \ <- pytest (Models, Utils, Logic)
``` ```
## Gateway: `platform-core/tests/` ## Gateway: `gateway/tests/`
### Test-Kategorien ### Test-Kategorien
@ -49,7 +49,7 @@ tests/
### Tests ausfuehren ### Tests ausfuehren
```bash ```bash
cd platform-core/ cd gateway/
# Standard (ohne expensive-Marker): # Standard (ohne expensive-Marker):
pytest pytest
@ -71,7 +71,7 @@ pytest --cov=modules tests/unit/
### Konfiguration ### Konfiguration
`pytest.ini` im `platform-core/`-Root: `pytest.ini` im `gateway/`-Root:
- `testpaths = tests`, `pythonpath = .` - `testpaths = tests`, `pythonpath = .`
- Log-Output: `logs/test_logs.log` - Log-Output: `logs/test_logs.log`
- Default: `-v --tb=short -m 'not expensive'` - Default: `-v --tb=short -m 'not expensive'`
@ -98,8 +98,8 @@ Then <erwartetes Ergebnis>
| ID | AC | Art | Automatisiert | Repo-Pfad | Status | | ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------| |----|----|-----|--------------|-----------|--------|
| T1 | 1 | unit | ja | platform-core/tests/unit/... | pending | | T1 | 1 | unit | ja | gateway/tests/unit/... | pending |
| T2 | 2 | integration | ja | platform-core/tests/integration/... | pending | | T2 | 2 | integration | ja | gateway/tests/integration/... | pending |
| T3 | 3 | api | nein | -- | pending | | T3 | 3 | api | nein | -- | pending |
Referenz: -> `c-work/_TEMPLATE.md` (Testplan-Section) Referenz: -> `c-work/_TEMPLATE.md` (Testplan-Section)