phase 2 i18n clean
This commit is contained in:
parent
f8679a41c8
commit
fc91d560a6
12 changed files with 1715 additions and 44 deletions
|
|
@ -35,6 +35,7 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
|
|||
| RBAC | b-reference/platform/rbac.md | 4-Stufen-Modell, Template-Rollen, Resolution, Datenmodell |
|
||||
| Datenbank-Architektur | b-reference/platform/database-architecture.md | Interface-Pattern, Connector, Auto-Init, DB-Liste |
|
||||
| Navigation | b-reference/platform/navigation.md | Menü-Struktur, Admin-Seiten, API |
|
||||
| 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)
|
||||
|
||||
|
|
@ -43,6 +44,11 @@ Lade immer zuerst diese Datei. Dann gezielt die passende(n) Referenz-Datei(en).
|
|||
| Automation Unification | c-work/1-plan/2026-04-automation-unification.md | Refactoring v1/v2/Workspace |
|
||||
| Web Image Search | c-work/1-plan/2026-03-web-image-search.md | WEB_SEARCH_MEDIA Feature |
|
||||
| UI i18n / Sprachsets (done) | c-work/3-validate/2026-04-ui-i18n-dynamic-language-sets.md | Mehrsprachigkeit, `t()`, Sprachset-API, Admin-UI, AI-Übersetzung |
|
||||
| Gateway i18n Unified | c-work/3-validate/2026-04 gateway-i18n-unified.md | `@i18nModel`, `t()` Backend, Boot-Sync, TextMultilingual dynamisch |
|
||||
| Gateway i18n Phase 7 (done) | c-work/3-validate/2026-04-gateway-i18n-phase-7-implementation.md | RBAC-Keys (rbac.*) im xx-Set, `translate-field` API, FormGenerator KI-Button |
|
||||
| Gateway Duplicate Class Names (done) | c-work/3-validate/2026-04-gateway-duplicate-class-names.md | TaskResult, AiResponse, TableData, Token Umbenennungen |
|
||||
| Generic Graph Editor (Typed Nodes, done) | c-work/3-validate/2026-04-generic-graph-editor.md | Port-Typen, Extraktoren, FrontendType-Renderer, System-Variablen |
|
||||
| i18n Static Text Elimination (Ph. 1–2 done) | c-work/2-build/2026-04-i18n-static-text-elimination.md | Gateway Feature+Nodes: Dicts → de-Keys; Ph. 3–5 offen |
|
||||
|
||||
## Prozess & Betrieb
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-08 -->
|
||||
<!-- lastReviewed: 2026-04-10 -->
|
||||
<!-- verifiedAgainst: frontend_nyla (codebase audit 2026-04-07, post Automation Unification) -->
|
||||
|
||||
# Frontend Nyla -- Architektur
|
||||
|
|
@ -49,7 +49,8 @@ Ergänzend typische Root-Dateien und Bereiche im Repo: `main.tsx`, `App.tsx`, `a
|
|||
- **Geschützte Bereiche:** Route-Guards (z. B. `ProtectedRoute`) prüfen Authentifizierung; Redirect bei fehlender Session.
|
||||
- **Haupt-App:** Nach Login **`MainLayout.tsx`** mit **`MandateNavigation`** (Sidebar) und `<Outlet />` (React Router).
|
||||
- **Seiten-Mapping:** `pageRegistry.tsx` definiert `PAGE_REGISTRY` und `FEATURE_REGISTRY`; Seiten werden lazy geladen. `core/PageManager/` enthält ergänzende Infrastruktur (State Preservation, Lifecycle-Hooks).
|
||||
- **i18n:** DB-backed via `LanguageContext` (`t()`-Hook). Sprachsets werden dynamisch via public API geladen (`GET /api/i18n/sets/{code}`). Key-Konvention: **Deutscher Klartext = Key**. Jeder neue/geänderte UI-Text MUSS mit `t('Deutscher Klartext')` getaggt werden. Variable Interpolation: `t('Text {var}', {var: 'Wert'})`. Fallback: Ziel-Set → `de`-Set → Key selbst. Keine statischen Locale-Files.
|
||||
- **i18n:** DB-backed via `LanguageContext` (`t()`-Hook). Sprachsets werden dynamisch via public API geladen (`GET /api/i18n/sets/{code}`). Key-Konvention: **Deutscher Klartext = Key**. Jeder neue/geänderte UI-Text MUSS mit `t('Deutscher Klartext')` getaggt werden. Variable Interpolation: `t('Text {var}', {var: 'Wert'})`. Fallback: Ziel-Set → `de`-Set → Key selbst. Keine statischen Locale-Files. Das xx-Basisset enthaelt sowohl UI-Keys (context="ui") als auch Gateway-Keys (context="api.*", "table.*") — beide werden per AI uebersetzt.
|
||||
- **TextMultilingual:** Felder vom Typ `TextMultilingual` rendern dynamisch Eingabefelder fuer alle verfuegbaren Sprachen (aus `availableLanguages`). Keine hardcodierten Sprach-Codes. Sprachcodes folgen ISO 639-1 (en, de, fr, it, …).
|
||||
- **Theme:** global über Context; API-Requests mit Auth-Header (Interceptor in zentralem API-Client).
|
||||
|
||||
## UI-Regeln
|
||||
|
|
@ -72,7 +73,12 @@ Ergänzend typische Root-Dateien und Bereiche im Repo: `main.tsx`, `App.tsx`, `a
|
|||
| `auth/authConfig`, `authProvider`, `ProtectedRoute` | MSAL, geschützte Routen |
|
||||
| `contexts/*` | FileContext, PekContext, Toast, Workflow-Auswahl, etc. |
|
||||
| `components/FlowEditor/editor/Automation2FlowEditor.tsx` | Haupt-Editor-Komponente (3-Column-Layout, State-Management) |
|
||||
| `components/FlowEditor/editor/FlowCanvas.tsx` | Custom Canvas mit Node-Rendering, Connections, Highlighting |
|
||||
| `components/FlowEditor/editor/FlowCanvas.tsx` | Custom Canvas mit Node-Rendering, Connections, Highlighting; `CanvasNode` traegt `inputPorts`/`outputPorts` |
|
||||
| `components/FlowEditor/nodes/frontendTypeRenderers/index.tsx` | `FRONTEND_TYPE_RENDERERS` Registry — generischer Renderer pro `FrontendType` statt pro Node-Typ |
|
||||
| `components/FlowEditor/editor/NodeConfigPanel.tsx` | Generischer Config-Renderer via `FRONTEND_TYPE_RENDERERS` (kein `NODE_CONFIG_REGISTRY` mehr) |
|
||||
| `components/FlowEditor/nodes/shared/graphUtils.ts` | `fromApiGraph`/`toApiGraph` serialisieren `inputPorts`/`outputPorts` auf `CanvasNode` |
|
||||
| `components/FlowEditor/nodes/shared/DataPicker.tsx` | Schema-basierte Pfad-Aufloesung, Transit-Chain, System-Variablen-Sektion |
|
||||
| `components/FlowEditor/context/Automation2DataFlowContext.tsx` | Stellt `portTypeCatalog` und `systemVariables` im Context bereit |
|
||||
| `components/FlowEditor/editor/RunTracingPanel.tsx` | SSE Live-Push + Canvas-Highlighting fuer Workflow-Runs |
|
||||
| `components/FlowEditor/editor/EditorChatPanel.tsx` | AI Chat mit Dateianhang (Drag&Drop) und Source-Picker |
|
||||
| `components/FlowEditor/editor/CanvasHeader.tsx` | Versioning, Template-Management, Workflow-Aktionen |
|
||||
|
|
@ -80,7 +86,9 @@ Ergänzend typische Root-Dateien und Bereiche im Repo: `main.tsx`, `App.tsx`, `a
|
|||
| `pages/views/graphicalEditor/GraphicalEditorPage.tsx` | Feature-Seite mit KeepAlive, URL-basiertem Workflow-Loading |
|
||||
| `locales/index.ts`, `types.ts` | i18n: API-basiertes Language-Loading (DB-backed, keine statischen Files) |
|
||||
| `providers/language/LanguageContext.tsx` | `t()`-Hook mit `{variable}`-Interpolation, Fallback-Kette, `availableLanguages` |
|
||||
| `pages/admin/AdminLanguagesPage.tsx` | Admin-Seite: Sprachset-Verwaltung (CRUD, AI-Übersetzung) |
|
||||
| `components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx` | Rendert `frontend_type: multilingual` (TextMultilingual) dynamisch nach `availableLanguages`; Button „In alle Sprachen uebersetzen“ (KI via `POST /api/i18n/translate-field`) |
|
||||
| `pages/admin/AdminLanguagesPage.tsx` | Admin-Seite: Sprachset-Verwaltung (CRUD, AI-Übersetzung, UI/API-Key-Counts) |
|
||||
| `pages/admin/AdminLanguagesKeepAlive.tsx` | KeepAlive-Wrapper: Sprach-Seite bleibt persistent bei Seitenwechsel |
|
||||
|
||||
## Regeln / Invarianten
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-08 -->
|
||||
<!-- lastReviewed: 2026-04-10 -->
|
||||
<!-- verifiedAgainst: gateway (codebase audit 2026-04-07, post Automation Unification) -->
|
||||
|
||||
# Gateway -- Architektur
|
||||
|
|
@ -25,7 +25,7 @@ Unter `gateway/modules/` (Kontext-Audit):
|
|||
| `security/` | RBAC (`rbac.py`, `rbacCatalog.py`), Root-Access |
|
||||
| `serviceCenter/` | Zentrale Service-Orchestrierung (Registry, Resolver, Kontext, Haupt-Services) |
|
||||
| `serviceHub/` | Service-Registry und Dependency Injection (u. a. `PublicService`-Wrapper) |
|
||||
| `shared/` | Gemeinsame Utilities (attributeUtils, Konfiguration, Logging, …) |
|
||||
| `shared/` | Gemeinsame Utilities (attributeUtils, i18nRegistry, Konfiguration, Logging, …) |
|
||||
| `system/` | System-Konfiguration, Feature-Discovery (`registry.py`: `loadFeatureMainModules`, `loadFeatureRouters`) |
|
||||
| `workflows/` | Workflow-Engine mit Methoden, Aktionen, Execution Engine und konsolidiertem Scheduler |
|
||||
|
||||
|
|
@ -96,10 +96,39 @@ Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap)
|
|||
| `gateway/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
|
||||
| `gateway/modules/system/registry.py` | Feature-Discovery, Router-Laden, Katalog-Registrierung beim App-Start |
|
||||
| `gateway/modules/workflows/workflowManager.py` | Zentrale Workflow-Steuerung (Workspace/Chat Workflows) |
|
||||
| `gateway/modules/workflows/automation2/executionEngine.py` | Graph-Execution-Engine (Graphical Editor) |
|
||||
| `gateway/modules/workflows/automation2/executionEngine.py` | Graph-Execution-Engine: topoSort, Transit-Routing, `_normalizeToSchema` nach Execute, `flow.merge`-Wait, Resume-Schema-Validierung |
|
||||
| `gateway/modules/workflows/scheduler/mainScheduler.py` | Konsolidierter Workflow-Scheduler |
|
||||
| `gateway/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) |
|
||||
|
||||
## i18n (Mehrsprachigkeit)
|
||||
|
||||
Das Gateway nutzt dasselbe DB-basierte Sprachsystem wie das Frontend (`UiLanguageSet`). Alle UI-sichtbaren Texte (HTTPException-Details, Model-Labels, API-Messages) werden ueber `t()` getaggt und per AI uebersetzt.
|
||||
|
||||
| Komponente | Datei | Zweck |
|
||||
|------------|-------|-------|
|
||||
| `i18nRegistry.py` | `modules/shared/` | `t()`, `@i18nModel` Decorator, `_REGISTRY`, `_CACHE`, `_setLanguage`, Boot-Sync |
|
||||
| `attributeUtils.py` | `modules/shared/` | `getModelLabels()` / `getModelLabel()` lesen aus `i18nRegistry.MODEL_LABELS` |
|
||||
| `routeI18n.py` | `modules/routes/` | Admin-API: Sprachset-CRUD, AI-Uebersetzung, xx-Sync |
|
||||
| `app.py` | `gateway/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) |
|
||||
|
||||
**Boot-Reihenfolge:**
|
||||
1. Module laden → `@i18nModel` Decorators + `t()`-Aufrufe registrieren Keys in `_REGISTRY`
|
||||
2. `_syncRegistryToDb()`:
|
||||
- Scannt Route-Dateien nach `routeApiMsg("…")` (api.* Keys)
|
||||
- `_registerNavLabels()`: Navigation-Labels aus `NAVIGATION_SECTIONS` (nav.* Keys)
|
||||
- `_registerFeatureUiLabels()`: `FEATURE_LABEL` und `UI_OBJECTS` Labels (nav.* Keys)
|
||||
- `_registerRbacLabels()`: `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `TEMPLATE_ROLES`, `QUICK_ACTIONS` Labels (rbac.data, rbac.resource, rbac.role, rbac.quickaction Keys)
|
||||
- Merged Gateway-Keys ins xx-Basisset (UI-Keys bleiben erhalten)
|
||||
3. `_loadCache()`: Laedt alle `UiLanguageSets` in den In-Memory-Cache (`_CACHE`)
|
||||
|
||||
**Request-Flow:** Middleware setzt `_setLanguage(lang)` aus `Accept-Language` Header → `t("Key")` liefert Uebersetzung aus `_CACHE[lang]` (O(1) Dict-Lookup, kein DB-Call)
|
||||
|
||||
**Context-Namensraeume:** `ui` (Frontend), `api.<routeModuleName>` (HTTPExceptions), `table.<ClassName>` (Model-Labels), `table.<ClassName>.<fieldName>` (Feld-Labels), `nav` (Navigation/Feature-Labels), `rbac.data` / `rbac.resource` / `rbac.role` / `rbac.quickaction` (RBAC-Katalog)
|
||||
|
||||
**Entries-Identitaet:** Ein Entry wird durch `(key, context)` eindeutig identifiziert — derselbe Text kann mit verschiedenen Contexts existieren (z.B. einmal als UI-Key, einmal als API-Key).
|
||||
|
||||
**TextMultilingual-Uebersetzung:** `POST /api/i18n/translate-field` — On-Demand-KI-Uebersetzung fuer einzelne Texte in mehrere Zielsprachen (genutzt vom FormGenerator-Button „In alle Sprachen uebersetzen").
|
||||
|
||||
## Regeln / Invarianten
|
||||
|
||||
- **Schichten:** Connectors sind anbieterspezifisch und ersetzbar; **Services hängen von Interfaces ab, nicht direkt von Connectors**. Geschäftslogik und Guardrails liegen in den Services.
|
||||
|
|
|
|||
330
c-work/1-plan/2026-04-customer-demo-enablement.md
Normal file
330
c-work/1-plan/2026-04-customer-demo-enablement.md
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
<!-- status: plan -->
|
||||
<!-- started: 2026-04-09 -->
|
||||
<!-- component: gateway | frontend-nyla | platform -->
|
||||
|
||||
# Customer Demo Enablement — Bling, PWG, Quid/ServiceHunter
|
||||
|
||||
## Beschreibung und Kontext
|
||||
|
||||
Drei potenzielle Kunden haben konkrete Use Cases formuliert (siehe `local/notes/use-cases-inputs-customers.md`). Dieses Dokument analysiert alle Kundenwünsche gegen den **Ist-Zustand** der Plattform und definiert einen priorisierten Umsetzungsplan, der mit minimalem Aufwand maximale Demo-Abdeckung und produktive Nutzbarkeit liefert.
|
||||
|
||||
**Kunden:**
|
||||
|
||||
| Kunde | Branche | Hauptinteresse | Status |
|
||||
|-------|---------|----------------|--------|
|
||||
| **Bling** (Kevin, Julian, Silvan) | Treuhandbüro | Belegverarbeitung, Budget, Dashboards, Mandantenmanagement | Trial geplant |
|
||||
| **PWG** (Markus Brütsch) | Stiftung (Immobilien/Wohnen, 200+ Liegenschaften) | Belegverarbeitung Abacus, KI-Arbeitsplatz, Coaching, Neutralisierung | Workshop 16.04.2026 |
|
||||
| **Quid/ServiceHunter** (David Christen) | SaaS/Dienstleistung | KPI-Dashboard, Zeiterfassung, Prognosen, Konsolidierung | Follow-up geplant |
|
||||
|
||||
**Business-Treiber:** Jeder Kunde erwartet eine funktionsfähige Demo seines Haupt-Use-Cases. Demos, die end-to-end durchlaufen, konvertieren zu Trials. Trials konvertieren zu zahlenden Kunden.
|
||||
|
||||
**Abhängigkeiten:**
|
||||
- PWG-Demo wird parallel in `c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md` vorbereitet (Trustee Agent-Tools, Graph-Editor Nodes, Performance)
|
||||
- UI-Enhancements für Erstnutzer-Erlebnis in `c-work/1-plan/2026-04-porta-ui-enhancements-team-meeting.md`
|
||||
- INT-Stabilität in `c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`
|
||||
|
||||
**Risiko bei Nicht-Umsetzung:** Kunden sehen nur generische AI-Chat-Funktionalität statt branchenspezifische Lösungen. Differenzierung zu ChatGPT/Copilot nicht erlebbar.
|
||||
|
||||
---
|
||||
|
||||
## Analyse: Kundenwünsche vs. Ist-Zustand
|
||||
|
||||
### Legende
|
||||
|
||||
| Symbol | Bedeutung |
|
||||
|--------|-----------|
|
||||
| ✅ | Vorhanden und demo-fähig |
|
||||
| 🔧 | Teilweise vorhanden, Anpassung nötig |
|
||||
| 🆕 | Muss neu gebaut werden |
|
||||
| ⏳ | In Arbeit (andere Plandokumente) |
|
||||
| ❌ | Nicht im Scope (zu komplex / kein ROI für Demo) |
|
||||
|
||||
---
|
||||
|
||||
### Bling (Treuhandbüro)
|
||||
|
||||
| # | Use Case | Status | Was existiert | Was fehlt |
|
||||
|---|----------|--------|---------------|-----------|
|
||||
| 1.1 | Belegverarbeitung & Spesen | ⏳ | Trustee-Feature mit `extractFromFiles`, `processDocuments`, `syncToAccounting`; SharePoint-Nodes im Graph-Editor; Abacus/Bexio/RMA-Connectors | Graph-Editor Demo-Workflow (in trustee-tooling-plan Phase 4); Bexio-spezifische Testdaten |
|
||||
| 1.2 | Budget / Soll-Ist-Vergleich | 🔧 | Agent kann Dateien lesen (Excel), `aggregateTable` für Trustee-Daten, `createChart` Tool | **Fehlend:** Demo-Prompt + Budget-Excel; Agent braucht Anleitung zum Vergleich Soll vs. Ist über Kontennummern |
|
||||
| 1.3 | Cashflow-Rechnung | 🔧 | Agent kann Trustee-Daten aggregieren und analysieren | **Fehlend:** Prompt-Template für Cashflow-Berechnung; Beispieldaten mit Bilanz + ER |
|
||||
| 1.4 | Dashboard – Kennzahlen | 🔧 | Agent hat `createChart`, kann rechnen, kann Dateien schreiben | **Fehlend:** Prompt-Templates für Kennzahlen (ROI, Gewinn, Kapitalverlust etc.) |
|
||||
| 1.5 | Liquiditätsplanung | 🔧 | Agent + Trustee-Daten + Budget-Logik | **Fehlend:** Prompt-Template; komplexer als Budget (braucht Prognose-Logik) |
|
||||
| 1.6 | Gastro-Echtzeit-Rentabilität | ❌ | — | Kassensystem-/Virux-Integration fehlt komplett; erst sinnvoll wenn Kevin Use Case liefert |
|
||||
| 1.7 | Abschlussunterstützung | 🔧 | Agent + Trustee-Daten | **Fehlend:** Prompt-Templates für Abgrenzungen, Saldovalidierung, Vorjahresvergleich |
|
||||
| 1.8 | Mandantenmanagement | ✅ | Multi-Tenant-Plattform mit Feature-Store; ein Login, mehrere Mandate, strikte Datentrennung (RBAC) | Nur UX-Polishing für die Demo nötig |
|
||||
|
||||
**Bling Demo-Strategie:** Use Cases 1.1, 1.2, 1.4 und 1.8 sind die stärksten Demo-Kandidaten. 1.1 wird durch den PWG-Plan mitabgedeckt (gleiche Trustee-Pipeline, anderer Connector). 1.2 und 1.4 brauchen primär **Prompt-Engineering + Testdaten**. 1.8 ist bereits Plattform-Kernfunktion.
|
||||
|
||||
---
|
||||
|
||||
### PWG (Stiftung)
|
||||
|
||||
| # | Use Case | Status | Was existiert | Was fehlt |
|
||||
|---|----------|--------|---------------|-----------|
|
||||
| 2.1 | Belegverarbeitung Abacus | ⏳ | Abacus-Connector, Trustee-Pipeline, Graph-Editor Workflow | Wird in trustee-tooling-plan umgesetzt (Phase 1–4) |
|
||||
| 2.2 | Coaching-Tool (Mietergespräche) | 🔧 | CommCoach-Feature mit Personas, Sessions, Scoring, Scheduler | **Fehlend:** Immobilien-spezifische Personas (Mietrückstand, Nebenkosten, PWG-Stil) |
|
||||
| 2.3 | KI-Arbeitsplatz + Neutralisierung | ✅ | Workspace (auto-instance), Neutralization Feature (PII-Masking, Playground), Private LLM | Demo-Config nötig: Neutralisierung aktivieren, fiktives Mieterdossier testen |
|
||||
| 2.4 | Abacus-Datenauswertung | ⏳ | Agent + `queryFeatureInstance` + `aggregateTable` | Abgedeckt durch trustee-tooling-plan (Phase 1) |
|
||||
| 2.5 | Grundstücksanalyse | 🔧 | RealEstate-Feature (Skeleton), Geo-Connectors (SwissTopo, ÖREB WFS, ZH Parcels) | Feature ist noch Shell; für Demo reicht Agent + `webSearch` + `readUrl` auf öffentliche Quellen |
|
||||
|
||||
**PWG Demo-Strategie:** 2.1 und 2.4 werden durch den trustee-tooling-plan abgedeckt. 2.3 ist demo-ready (Config + Testdaten). **Grösster Hebel hier:** 2.2 CommCoach mit Immobilien-Personas — zeigt sofortigen, greifbaren Mehrwert mit wenig Aufwand. 2.5 kann als Agent-Demo mit Web-Recherche gezeigt werden.
|
||||
|
||||
---
|
||||
|
||||
### Quid/ServiceHunter
|
||||
|
||||
| # | Use Case | Status | Was existiert | Was fehlt |
|
||||
|---|----------|--------|---------------|-----------|
|
||||
| 3.1 | KPI-Dashboard | 🔧 | Agent + `createChart` + Dateiverarbeitung (Excel/CSV) | **Fehlend:** Kein Treuhandball-/ERP-Connector; Daten müssen als CSV/Excel importiert werden; Prompt-Templates für KPI-Berechnung |
|
||||
| 3.2 | Zeiterfassung & Support-Analyse | 🆕 | Agent kann Dateien lesen und analysieren | **Fehlend:** Kein Zendesk-Connector; Workaround: CSV/Excel-Export aus Zendesk manuell hochladen |
|
||||
| 3.3 | Prognosen & Proaktive Steuerung | 🔧 | Agent kann rechnen, Trends erkennen, Charts erstellen | **Fehlend:** Prompt-Templates; historische Testdaten |
|
||||
| 3.4 | Konsolidierung (international) | ❌ | Multi-Mandate Grundstruktur | Regelbasierte Konsolidierung ist hochkomplex; erst nach Follow-up mit Lars sinnvoll |
|
||||
| 3.5 | Spesen-Automatisierung | ⏳ | Gleiche Trustee-Pipeline wie Bling/PWG | SharePoint/Google Drive → Trustee; minimal anpassbar |
|
||||
|
||||
**Quid Demo-Strategie:** 3.1 ist der stärkste Kandidat — mit manuell hochgeladenen CSV/Excel-Daten kann der Agent KPIs berechnen und visualisieren. 3.2 funktioniert als „Upload deine Zendesk-Exports und lass den Agent analysieren". 3.3 als Erweiterung von 3.1. 3.4 ist explizit zu komplex für eine erste Demo.
|
||||
|
||||
---
|
||||
|
||||
## Synthese: Was bringt den grössten Demo-ROI?
|
||||
|
||||
### Muster über alle Kunden hinweg
|
||||
|
||||
| Capability | Bling | PWG | Quid | Aufwand | Priorität |
|
||||
|-----------|-------|-----|------|---------|-----------|
|
||||
| **Trustee-Pipeline (Belege → BuHa)** | 1.1 | 2.1 | 3.5 | ⏳ In Arbeit | P0 (bereits geplant) |
|
||||
| **Agent Prompt-Templates (Analyse + Charts)** | 1.2, 1.3, 1.4 | 2.4 | 3.1, 3.3 | Klein (Prompts + Testdaten) | **P1** |
|
||||
| **CommCoach Immobilien-Personas** | — | 2.2 | — | Klein (Persona-Config) | **P1** |
|
||||
| **Neutralisierungs-Demo-Setup** | — | 2.3 | — | Klein (Config + Testdaten) | **P1** |
|
||||
| **CSV/Excel-Import als Datenquelle** | — | — | 3.1, 3.2 | Mittel (Workspace-Dateien reichen) | **P2** |
|
||||
| **Multi-Mandate Demo-Setup** | 1.8 | — | — | Klein (Demo-Mandanten anlegen) | **P2** |
|
||||
| **Grundstücks-Recherche via Agent** | — | 2.5 | — | Klein (Prompt + Web-Tools) | **P3** |
|
||||
| **Zendesk-Connector** | — | — | 3.2 | Gross (neuer Connector) | **P4** (nicht für erste Demo) |
|
||||
| **Gastro-Integration** | 1.6 | — | — | Gross (Kassen-/Lohn-API) | **P4** (wartet auf Kevin) |
|
||||
| **Konsolidierung** | — | — | 3.4 | Sehr gross | **P4** (wartet auf Lars-Meeting) |
|
||||
|
||||
---
|
||||
|
||||
## Fokus und kritische Details
|
||||
|
||||
### Prompt-Templates als Schlüssel-Asset
|
||||
|
||||
Der Agent kann bereits Trustee-Daten lesen, aggregieren und Charts erstellen. Was fehlt, sind **vorkonfigurierte Prompt-Templates** (als Workspace-Dateien oder System-Prompts), die den Agent zuverlässig zur gewünschten Analyse führen:
|
||||
|
||||
- **Budget-Vergleich:** „Lade Budget-Excel, vergleiche mit Ist-Daten aus Trustee pro Kontonummer, erstelle Abweichungs-Chart"
|
||||
- **Cashflow:** „Berechne operativen Cashflow aus Bilanz + ER, berücksichtige Abschreibungen, zeige Warnung bei negativem Trend"
|
||||
- **KPI-Dashboard:** „Berechne Bruttogewinn, ROI, Gewinnmarge, Kapitalverlust-Check aus den Trustee-Daten"
|
||||
- **Prognose:** „Analysiere letzte 6 Monate, prognostiziere nächste 3 Monate mit linearer Extrapolation"
|
||||
|
||||
Diese Templates können als **Workspace-Dateien** (Markdown mit Instruktionen) oder als **Graph-Editor System-Templates** (Workflow mit `ai.prompt`-Node) umgesetzt werden.
|
||||
|
||||
### CommCoach: Geringer Aufwand, hoher Wow-Effekt
|
||||
|
||||
CommCoach hat bereits: Persona-System, Session-Management, Scoring, Feedback. Für PWG braucht es nur **3–5 neue Personas** im Immobilienkontext:
|
||||
- Mieter mit Zahlungsrückstand
|
||||
- Mieter mit Nebenkostenfragen
|
||||
- Neuer Mieter (Einzug/Vertragsklärung)
|
||||
- Schwieriger Nachbar (Lärmbeschwerde)
|
||||
|
||||
### Neutralisierung: Bereits gebaut, nur konfigurieren
|
||||
|
||||
Das Feature ist vollständig: Playground, Text/Datei-Neutralisierung, Private-LLM-Integration. Für die Demo braucht es:
|
||||
- Ein fiktives Mieterdossier (PDF mit Namen, Adressen, Mietzinsen)
|
||||
- Neutralisierung aktiviert auf der Demo-Instanz
|
||||
- Vorführung: Original → neutralisiert → AI-Analyse → Re-Personalisierung
|
||||
|
||||
---
|
||||
|
||||
## Ziel und Nicht-Ziele
|
||||
|
||||
**Ziel:**
|
||||
- Für jeden der drei Kunden mindestens **2 Use Cases end-to-end demo-fähig**
|
||||
- Prompt-Templates als wiederverwendbares Asset (nicht nur einmalige Demo-Hacks)
|
||||
- Demo-Mandanten mit realistischen Testdaten pro Kunde
|
||||
- CommCoach mit Immobilien-Personas für PWG
|
||||
- Neutralisierungs-Demo-Flow getestet
|
||||
|
||||
**Explizit NICHT:**
|
||||
- Keine neuen Connector-Implementierungen (Zendesk, Kassensystem, Virux)
|
||||
- Keine regelbasierte Konsolidierung
|
||||
- Keine Gastro-Echtzeit-Integration
|
||||
- Keine neuen Frontend-Features (UI-Enhancements laufen separat)
|
||||
- Kein Abacus-Produktivzugang (Demo mit Sandbox/Mockdaten)
|
||||
|
||||
## Betroffene Module
|
||||
|
||||
- **Gateway:** `features/commcoach/` (Persona-Seeding), `features/trustee/` (Demo-Daten), `features/neutralization/` (Demo-Config)
|
||||
- **Frontend:** keine Änderungen (UI-Enhancements separat)
|
||||
- **DB-Migration:** nein
|
||||
- **Andere Komponenten:** Testdaten (Excel, PDF, CSV), Prompt-Templates (Workspace-Dateien)
|
||||
|
||||
## Entscheidungen
|
||||
|
||||
| Datum | Entscheidung | Begründung |
|
||||
|-------|-------------|------------|
|
||||
| 2026-04-09 | Prompt-Templates statt Custom-Code für Analyse-Use-Cases | Agent + bestehende Tools (aggregateTable, createChart) reichen; Templates sind schnell erstellbar und wartbar |
|
||||
| 2026-04-09 | Quid-Demo ohne Zendesk-Connector — CSV/Excel-Upload Workaround | Zendesk-Connector hat hohen Aufwand, CSV-Import zeigt den gleichen Analyse-Mehrwert |
|
||||
| 2026-04-09 | Gastro-UC und Konsolidierung auf P4 (nicht für erste Demo) | Warten auf Kunden-Input (Kevin) bzw. Prozessverständnis (Lars-Meeting) |
|
||||
| 2026-04-09 | CommCoach-Personas als schnellster Wow-Effekt für PWG priorisiert | Feature ist gebaut; 3–5 Persona-Definitionen im Immobilienkontext genügen |
|
||||
|
||||
---
|
||||
|
||||
## Umsetzungs-Checkliste
|
||||
|
||||
### Phase 1: Demo-Infrastruktur (Prio: hoch — Grundlage für alle Demos)
|
||||
|
||||
- [ ] **Demo-Mandant "Bling Demo"** anlegen mit Bexio-Testverbindung
|
||||
- Trustee-Instanz mit `connectorType: bexio`
|
||||
- Workspace-Instanz
|
||||
- Graph-Editor-Instanz
|
||||
- 2–3 Demo-User (Admin, Buchhalter, Mandant)
|
||||
|
||||
- [ ] **Demo-Mandant "PWG Demo"** anlegen (ergänzend zu trustee-tooling-plan Phase 5)
|
||||
- Trustee-Instanz mit `connectorType: abacus`
|
||||
- Workspace-Instanz
|
||||
- CommCoach-Instanz
|
||||
- Neutralisierung-Instanz
|
||||
|
||||
- [ ] **Demo-Mandant "Quid Demo"** anlegen
|
||||
- Workspace-Instanz
|
||||
- Graph-Editor-Instanz
|
||||
|
||||
### Phase 2: Prompt-Templates & Analyse-Flows (Prio: hoch — betrifft alle 3 Kunden)
|
||||
|
||||
- [ ] **Prompt-Template: Budget-Vergleich (Soll/Ist)**
|
||||
- Workspace-Datei mit Instruktionen für den Agent
|
||||
- Schritte: Budget-Excel lesen → Trustee-Daten aggregieren (SUM pro Konto) → Abweichungen berechnen → Chart erstellen → Zusammenfassung
|
||||
- Testdaten: Budget-Excel mit 10–15 Konten, passend zu Demo-Buchhaltungsdaten
|
||||
|
||||
- [ ] **Prompt-Template: KPI-Dashboard / Kennzahlen**
|
||||
- Bruttogewinn, ROI, Gewinnmarge, hälftiger Kapitalverlust, Überschuldungs-Check
|
||||
- Agent soll mehrere Charts erstellen und kritische Werte highlighten
|
||||
- Wiederverwendbar für Bling (1.4) und Quid (3.1)
|
||||
|
||||
- [ ] **Prompt-Template: Cashflow-Rechnung**
|
||||
- Bilanz + ER aus Trustee → operativer/investiver/finanzieller Cashflow
|
||||
- Nicht-Cash-Positionen (Abschreibungen) erkennen und bereinigen
|
||||
- Warnungen bei kritischen Werten
|
||||
|
||||
- [ ] **Prompt-Template: Prognose (Trend-Analyse)**
|
||||
- Historische Daten analysieren (6 Monate) → nächste 3 Monate prognostizieren
|
||||
- Einfache lineare Extrapolation + Saisonalitätshinweis
|
||||
- Chart mit Ist vs. Prognose
|
||||
- Für Bling (1.5) und Quid (3.3)
|
||||
|
||||
- [ ] **Prompt-Template: Jahresabschluss-Checks**
|
||||
- Saldovalidierung, Vorjahresvergleich, Abgrenzungsbuchungen identifizieren
|
||||
- Für Bling (1.7)
|
||||
|
||||
### Phase 3: CommCoach Immobilien-Personas (Prio: hoch — PWG-Demo 16.04)
|
||||
|
||||
- [ ] **Persona: Mieter mit Zahlungsrückstand**
|
||||
- Kontext: 3 Monate Mietrückstand, hat Mahnungen erhalten, ist genervt
|
||||
- Schwierigkeitsgrad: mittel
|
||||
- Lernziel: Empathisches Einfordern, Zahlungsvereinbarung vorschlagen
|
||||
|
||||
- [ ] **Persona: Mieter mit Nebenkostenfragen**
|
||||
- Kontext: Nebenkostenabrechnung erhalten, versteht Positionen nicht, emotional aufgebracht
|
||||
- Schwierigkeitsgrad: leicht
|
||||
- Lernziel: Geduldig erklären, auf Rechtsgrundlage verweisen
|
||||
|
||||
- [ ] **Persona: Neuer Mieter (Einzugsfragen)**
|
||||
- Kontext: Fragen zu Wohnungsübergabe, Schlüssel, Hausordnung, Kaution
|
||||
- Schwierigkeitsgrad: leicht
|
||||
- Lernziel: Willkommenskultur, klare Informationsvermittlung
|
||||
|
||||
- [ ] **Persona: Schwieriger Nachbar (Lärmbeschwerde)**
|
||||
- Kontext: Beschwert sich über Lärm, droht mit Mietminderung
|
||||
- Schwierigkeitsgrad: schwer
|
||||
- Lernziel: Deeskalation, Mediation anbieten, Rechte und Pflichten
|
||||
|
||||
- [ ] **Persona-Seeding** in CommCoach `onRegister` oder als manuelles Setup-Skript
|
||||
|
||||
### Phase 4: Neutralisierungs-Demo (Prio: hoch — PWG-Demo 16.04)
|
||||
|
||||
- [ ] **Fiktives Mieterdossier erstellen** (PDF)
|
||||
- Enthält: Name, Adresse, Mietzins, Zahlungshistorie, Korrespondenz
|
||||
- Realistisch aber komplett fiktiv (DSGVO-konform)
|
||||
|
||||
- [ ] **Demo-Flow dokumentieren**
|
||||
- Original-PDF hochladen → Neutralisierung zeigen (Namen → Platzhalter)
|
||||
- Neutralisierten Text an AI senden → Analyse erhalten
|
||||
- Re-Personalisierung demonstrieren
|
||||
- Optional: Private LLM für sensitive Daten zeigen
|
||||
|
||||
- [ ] **Neutralisierungs-Config** auf Demo-Instanz konfigurieren und testen
|
||||
|
||||
### Phase 5: Testdaten & Demo-Skripte (Prio: mittel)
|
||||
|
||||
- [ ] **Bling-Testdaten:** Bexio-kompatible Buchhaltungsdaten (Journal, Kontoplan, Bilanz/ER)
|
||||
- [ ] **Bling-Testdaten:** Budget-Excel (Soll-Werte 2026 pro Konto)
|
||||
- [ ] **Bling-Testdaten:** 3–5 Musterbelege (Rechnung, Spesenbeleg, Bankbeleg)
|
||||
- [ ] **PWG-Testdaten:** Abacus-kompatible Daten (bereits in trustee-tooling-plan)
|
||||
- [ ] **Quid-Testdaten:** CSV/Excel mit Umsatzdaten (6 Monate), Kundenliste mit Margen, Support-Zeiterfassung
|
||||
- [ ] **Demo-Skript Bling:** Schritt-für-Schritt mit Screenshots/Notizen
|
||||
- [ ] **Demo-Skript PWG:** Schritt-für-Schritt (ergänzend zu trustee-tooling-plan)
|
||||
- [ ] **Demo-Skript Quid:** Schritt-für-Schritt
|
||||
|
||||
### Phase 6: Quid-spezifisch — Datenanalyse ohne Connector (Prio: mittel)
|
||||
|
||||
- [ ] **Demo-Flow: CSV/Excel hochladen → Agent analysiert**
|
||||
- Quid lädt Buchhaltungs-Export (CSV) und Zendesk-Export (CSV) in den Workspace
|
||||
- Agent liest beide Dateien, verknüpft über Quid-ID / E-Mail
|
||||
- Berechnet KPIs: Kundenmarge, ACV, Lifetime Value, Support-Kosten pro Kunde
|
||||
- Erstellt Dashboard-Charts
|
||||
|
||||
- [ ] **Prompt-Template: Multi-Source KPI-Analyse**
|
||||
- Instruktionen für den Agent: „Lies die hochgeladenen Dateien, identifiziere gemeinsame Identifier, berechne folgende KPIs..."
|
||||
|
||||
### Querschnitt-Checks
|
||||
|
||||
- [ ] API-Endpunkte: keine neuen nötig
|
||||
- [ ] DB-Schema / Migration: nein
|
||||
- [ ] Frontend-Komponenten: nein (separater Plan)
|
||||
- [ ] RBAC / Permissions: Demo-User mit passenden Rollen
|
||||
- [ ] Neutralisierung betroffen? ja (Phase 4)
|
||||
- [ ] Navigation / Routing: nein
|
||||
- [ ] Billing-Impact? Demo-Mandanten brauchen ausreichend Guthaben / Trial-Modus
|
||||
|
||||
---
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
||||
| # | Kriterium (Given-When-Then) | Prio | Kunde |
|
||||
|---|---------------------------|------|-------|
|
||||
| 1 | Given Bling-Demo-Mandant mit Bexio-Daten und Budget-Excel, When der Agent den Budget-Vergleich-Prompt ausführt, Then zeigt er Soll/Ist-Abweichungen pro Konto mit Chart | must | Bling |
|
||||
| 2 | Given Bling-Demo-Mandant, When der Agent den KPI-Dashboard-Prompt ausführt, Then erstellt er mindestens 3 Kennzahlen-Charts (Bruttogewinn, ROI, Gewinnmarge) | must | Bling |
|
||||
| 3 | Given PWG-Demo-Mandant mit CommCoach-Instanz, When ein User eine Coaching-Session mit Persona "Mieter mit Zahlungsrückstand" startet, Then spielt die KI den Mieter realistisch im Immobilienkontext | must | PWG |
|
||||
| 4 | Given PWG-Demo-Mandant mit aktivierter Neutralisierung, When ein fiktives Mieterdossier hochgeladen und analysiert wird, Then werden PII-Daten vor dem LLM-Call neutralisiert und nach der Analyse re-personalisiert | must | PWG |
|
||||
| 5 | Given Quid-Demo-Mandant mit hochgeladenen CSV-Dateien (Buchhaltung + Zendesk-Export), When der Agent die KPI-Analyse ausführt, Then verknüpft er Daten über gemeinsame IDs und erstellt Margen- und Support-Kosten-Charts | should | Quid |
|
||||
| 6 | Given Demo-Mandant mit 2+ Mandaten, When ein Bling-Admin zwischen Mandanten wechselt, Then sieht er jeweils nur die Daten des aktiven Mandanten (Datentrennung funktioniert) | must | Bling |
|
||||
| 7 | Given Cashflow-Prompt und Trustee-Daten, When der Agent die Analyse durchführt, Then berechnet er korrekten operativen Cashflow unter Berücksichtigung von Abschreibungen | should | Bling |
|
||||
|
||||
## Testplan
|
||||
|
||||
| ID | AC | Art | Automatisiert | Methode | Status |
|
||||
|----|----|-----|--------------|---------|--------|
|
||||
| T1 | 1 | e2e | nein | Manuell: Budget-Excel + Trustee-Daten + Agent-Prompt im Workspace | pending |
|
||||
| T2 | 2 | e2e | nein | Manuell: KPI-Prompt im Workspace mit Trustee-Daten | pending |
|
||||
| T3 | 3 | e2e | nein | Manuell: CommCoach-Session mit Immobilien-Persona starten | pending |
|
||||
| T4 | 4 | e2e | nein | Manuell: PDF hochladen → Neutralisierung → Analyse → Re-Personalisierung | pending |
|
||||
| T5 | 5 | e2e | nein | Manuell: CSV-Upload → Agent-Prompt → Charts prüfen | pending |
|
||||
| T6 | 6 | e2e | nein | Manuell: Mandantenwechsel, Daten prüfen | pending |
|
||||
| T7 | 7 | e2e | nein | Manuell: Cashflow-Prompt → Ergebnis gegen manuelle Berechnung prüfen | pending |
|
||||
|
||||
## Links
|
||||
|
||||
- Kundenwünsche: `local/notes/use-cases-inputs-customers.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`
|
||||
- INT-Stabilität (parallel): `c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`
|
||||
- CommCoach-Feature: `gateway/modules/features/commcoach/`
|
||||
- Neutralisierung-Feature: `gateway/modules/features/neutralization/`
|
||||
- Trustee-Feature: `gateway/modules/features/trustee/`
|
||||
- Workspace-Feature: `gateway/modules/features/workspace/`
|
||||
|
||||
## Abschluss
|
||||
|
||||
- [ ] b-reference/ aktualisiert (ggf. neue Feature-Docs unter `b-reference/gateway/features/`)
|
||||
- [ ] TOPICS.md aktualisiert (falls neues Thema)
|
||||
- [ ] Dieses Dokument → z-archive/ verschoben
|
||||
4
c-work/1-plan/2026-04-i18n-static-text-elimination.md
Normal file
4
c-work/1-plan/2026-04-i18n-static-text-elimination.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!-- status: moved -->
|
||||
<!-- canonical: c-work/2-build/2026-04-i18n-static-text-elimination.md -->
|
||||
|
||||
Dieser Plan wurde nach **`c-work/2-build/2026-04-i18n-static-text-elimination.md`** verschoben. Bitte dort weiterarbeiten.
|
||||
445
c-work/1-plan/2026-04-quick-actions-feature-dashboard.md
Normal file
445
c-work/1-plan/2026-04-quick-actions-feature-dashboard.md
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
<!-- status: plan -->
|
||||
<!-- started: 2026-04-09 -->
|
||||
<!-- component: gateway | frontend-nyla | platform -->
|
||||
|
||||
# Quick Actions — Feature-Dashboard mit One-Click-Aktionen
|
||||
|
||||
## Beschreibung und Kontext
|
||||
|
||||
Treuhandbüros (Bling, PWG) und andere Kunden wünschen sich ein **Cockpit**, von dem aus sie ihre häufigsten Aufgaben per Knopfdruck starten können — Budget-Vergleich, Belegverarbeitung, KPI-Dashboard, Cashflow etc. Heute müssen sie dafür den Workspace öffnen und den richtigen Prompt manuell eintippen.
|
||||
|
||||
**Business-Treiber:** Das Feature-Dashboard (z.B. Trustee Dashboard) ist aktuell eine passive Statistik-Seite (Anzahl Positionen, Dokumente, Sync-Status). Mit Quick Actions wird es zum **aktiven Cockpit** — der Einstiegspunkt für produktive Arbeit. Das macht den Unterschied zwischen "generischem AI-Chat" und "Branchenlösung für Treuhänder".
|
||||
|
||||
**Abhängigkeiten:**
|
||||
- Trustee Agent-Tools müssen funktionieren (`c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md`)
|
||||
- Workspace SSE-Streaming muss stabil laufen (`c-work/1-plan/2026-04-gateway-int-stability-and-bugfixes.md`)
|
||||
- Prompt-Templates aus `c-work/1-plan/2026-04-customer-demo-enablement.md`
|
||||
|
||||
**Risiko bei Nicht-Umsetzung:** Kunden sehen PORTA als "noch ein Chat-Tool" statt als branchenspezifische Plattform. Die Hürde vom Login zum Mehrwert bleibt hoch.
|
||||
|
||||
## Fokus und kritische Details
|
||||
|
||||
### Ist-Zustand: Trustee Dashboard
|
||||
|
||||
`frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx` zeigt aktuell:
|
||||
- **Stats-Grid:** 4 Kacheln (Positionen, Dokumente, Buchhaltungs-Sync, Rollen)
|
||||
- **Info-Sektion:** Instanz-Label, Mandant, Buchhaltungssystem
|
||||
|
||||
Kein Weg zu einer Aktion — keine Buttons, keine Links zum Workspace, keine Workflows.
|
||||
|
||||
### Architektur-Entscheid: Zwei Dispatch-Typen
|
||||
|
||||
Quick Actions dispatchen zu **bestehender Infrastruktur** — es wird keine zweite AI-Oberfläche gebaut:
|
||||
|
||||
| Typ | Dispatch-Ziel | Wann nutzen |
|
||||
|-----|--------------|-------------|
|
||||
| **`agentPrompt`** | Workspace mit vorgefülltem Prompt → Agent startet automatisch | Analyse-Aufgaben (Budget, KPIs, Cashflow, Prognosen, Jahresabschluss) |
|
||||
| **`workflow`** | Graph-Editor System-Template wird direkt getriggert | Automatisierungs-Aufgaben (Belegimport, Daten-Sync, Spesen-Import) |
|
||||
| **`link`** | Navigation zu einer bestehenden Seite | Schnellzugriff (Scan/Upload, Dokumente, Einstellungen) |
|
||||
|
||||
### Kritische Stellen
|
||||
|
||||
- **Workspace Pre-Fill:** Der Workspace (`WorkspacePage.tsx`) hat aktuell **keinen** Mechanismus für URL-Parameter `?prompt=...`. Das muss ergänzt werden.
|
||||
- **Cross-Feature-Navigation:** Eine Trustee Quick Action muss den User zur Workspace-Instanz des gleichen Mandanten navigieren. Das erfordert Auflösung: Trustee-InstanceId → MandateId → Workspace-InstanceId.
|
||||
- **RBAC-Filterung:** Quick Actions müssen nach Rolle gefiltert werden. Ein `trustee-client` soll "Belege hochladen" sehen, aber nicht "Jahresabschluss prüfen".
|
||||
- **i18n:** Alle Labels müssen mehrsprachig sein (bestehendes `TextMultilingual`-Pattern nutzen).
|
||||
|
||||
### Warum kein eigenes AI-Rendering auf dem Dashboard?
|
||||
|
||||
Der Workspace hat bereits: Chat-Rendering, Chart-Anzeige, Datei-Handling, SSE-Streaming, Progressive Summarization, Tool-Ergebnisse. Das zu duplizieren wäre enormer Aufwand. Stattdessen nutzen wir den Workspace als "Execution Engine" und das Dashboard als "Launchpad".
|
||||
|
||||
## Ziel und Nicht-Ziele
|
||||
|
||||
**Ziel:**
|
||||
- Feature-Dashboards (Trustee als Pilot, danach CommCoach, Workspace) zeigen kontextspezifische Quick Action Cards
|
||||
- Klick auf eine `agentPrompt`-Card öffnet Workspace mit vorgefülltem Prompt und startet den Agent
|
||||
- Klick auf eine `workflow`-Card triggert einen Graph-Editor Workflow
|
||||
- Actions sind RBAC-gefiltert, i18n-ready und per Feature-Instanz konfigurierbar
|
||||
- Wiederverwendbare `QuickActionBoard`-Komponente für alle Features
|
||||
|
||||
**Explizit NICHT:**
|
||||
- Kein AI-Rendering auf dem Dashboard selbst (kein Chat, keine Charts auf der Trustee-Seite)
|
||||
- Keine neuen DB-Tabellen — Quick Actions leben im Code (wie `UI_OBJECTS`) + optional in `FeatureInstance.config`
|
||||
- Keine neuen API-Verträge für Workflow-Execution (nutzt bestehenden `POST /{instanceId}/execute`)
|
||||
- Kein Prompt-Editor für Endnutzer (kommt ggf. später)
|
||||
|
||||
## Betroffene Module
|
||||
|
||||
- **Gateway:** `features/trustee/mainTrustee.py` (Quick Action Definitionen), `features/trustee/routeFeatureTrustee.py` (API-Endpoint), ggf. `features/workspace/routeFeatureWorkspace.py` (Pre-Fill-Support)
|
||||
- **Frontend:** `pages/views/trustee/TrusteeDashboardView.tsx` (Quick Action Board einbinden), neue Komponente `components/QuickActionBoard/`, `pages/views/workspace/WorkspacePage.tsx` (URL-Param-Support)
|
||||
- **DB-Migration:** nein
|
||||
- **Andere Komponenten:** Prompt-Templates (Markdown-Dateien, getrennt gepflegt)
|
||||
|
||||
## Entscheidungen
|
||||
|
||||
| Datum | Entscheidung | Begründung |
|
||||
|-------|-------------|------------|
|
||||
| 2026-04-09 | Quick Actions im Code definieren (wie `UI_OBJECTS`), nicht in einer DB-Tabelle | Einfach, versioniert, kein Migrations-Aufwand. Custom-Actions später über `FeatureInstance.config` |
|
||||
| 2026-04-09 | Dispatch zu Workspace statt Inline-Rendering auf dem Dashboard | Workspace hat die komplette AI-Infrastruktur (Chat, Charts, Streaming). Kein Sinn in Duplizierung |
|
||||
| 2026-04-09 | `QuickActionBoard` als generische Plattform-Komponente, nicht Trustee-spezifisch | CommCoach, Workspace, RealEstate können dieselbe Komponente nutzen |
|
||||
| 2026-04-09 | Workspace bekommt URL-Parameter `?prompt=...&autoStart=true` | Einfachster Weg für Cross-Feature-Dispatch. Kein Backend-Spezialweg nötig |
|
||||
| 2026-04-09 | Prompt-Templates als Konfigurationswert in der Quick Action, nicht als separate Dateien | Prompt gehört zur Aktion — eine Quelle der Wahrheit. Kein File-Lookup zur Laufzeit |
|
||||
|
||||
---
|
||||
|
||||
## Umsetzungs-Checkliste
|
||||
|
||||
### Phase 1: Backend — Quick Action Definitionen & API (Gateway)
|
||||
|
||||
- [ ] **`QUICK_ACTIONS` in `mainTrustee.py` definieren**
|
||||
|
||||
Gleiches Pattern wie `UI_OBJECTS`, `TEMPLATE_ROLES`:
|
||||
|
||||
```python
|
||||
QUICK_ACTIONS = [
|
||||
{
|
||||
"id": "trustee-process-receipts",
|
||||
"label": {"de": "Belege verarbeiten", "en": "Process Receipts", "fr": "Traiter les justificatifs"},
|
||||
"description": {"de": "Belege aus SharePoint importieren, klassifizieren und verbuchen", "en": "Import receipts from SharePoint, classify and book", "fr": "Importer les justificatifs depuis SharePoint, classer et comptabiliser"},
|
||||
"icon": "mdi-file-document-check-outline",
|
||||
"color": "#4CAF50",
|
||||
"category": "import",
|
||||
"actionType": "workflow",
|
||||
"config": {
|
||||
"workflowTemplateCode": "trustee-receipt-import"
|
||||
},
|
||||
"requiredRoles": ["trustee-user", "trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": "trustee-sync-accounting",
|
||||
"label": {"de": "Daten synchronisieren", "en": "Sync Accounting Data", "fr": "Synchroniser les données"},
|
||||
"description": {"de": "Buchhaltungsdaten aus dem externen System aktualisieren", "en": "Refresh accounting data from external system", "fr": "Actualiser les données du système externe"},
|
||||
"icon": "mdi-sync",
|
||||
"color": "#FF9800",
|
||||
"category": "import",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Aktualisiere die Buchhaltungsdaten aus dem verbundenen Buchhaltungssystem. Nutze refreshTrusteeData mit forceRefresh=true. Zeige mir danach eine Zusammenfassung: Anzahl Konten, Buchungen, Kontakte und den Zeitraum der Daten."
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 2
|
||||
},
|
||||
{
|
||||
"id": "trustee-budget-comparison",
|
||||
"label": {"de": "Budget-Vergleich", "en": "Budget Comparison", "fr": "Comparaison budgétaire"},
|
||||
"description": {"de": "Soll/Ist-Vergleich der Buchhaltung mit Budget-Excel", "en": "Compare actuals vs. budget from Excel", "fr": "Comparer les données réelles avec le budget Excel"},
|
||||
"icon": "mdi-chart-bar",
|
||||
"color": "#2196F3",
|
||||
"category": "analyse",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Ich möchte einen Budget-Soll/Ist-Vergleich durchführen. Bitte:\n1. Frage mich nach der Budget-Datei (Excel) oder suche im Workspace nach einer Datei mit 'Budget' im Namen\n2. Lade die aktuellen Buchhaltungsdaten (refreshTrusteeData falls nötig)\n3. Vergleiche die Soll-Werte aus dem Budget mit den Ist-Werten aus der Buchhaltung pro Konto\n4. Berechne die Abweichung (absolut und prozentual)\n5. Erstelle ein Abweichungs-Chart (Balkendiagramm: Soll vs. Ist pro Konto)\n6. Markiere kritische Abweichungen (>10%) und gib eine kurze Einschätzung",
|
||||
"suggestFileUpload": true,
|
||||
"uploadHint": {"de": "Budget-Excel hochladen", "en": "Upload budget Excel"}
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 3
|
||||
},
|
||||
{
|
||||
"id": "trustee-kpi-dashboard",
|
||||
"label": {"de": "KPI-Dashboard", "en": "KPI Dashboard", "fr": "Tableau de bord KPI"},
|
||||
"description": {"de": "Kennzahlen berechnen und visualisieren", "en": "Calculate and visualize key metrics", "fr": "Calculer et visualiser les indicateurs clés"},
|
||||
"icon": "mdi-view-dashboard-outline",
|
||||
"color": "#9C27B0",
|
||||
"category": "analyse",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Erstelle ein KPI-Dashboard basierend auf den aktuellen Buchhaltungsdaten. Berechne und visualisiere:\n1. **Bruttogewinn** und Bruttogewinnmarge\n2. **EBIT** (Betriebsergebnis)\n3. **Gewinnmarge** (Reingewinn / Umsatz)\n4. **Eigenkapitalquote** und Check auf hälftigen Kapitalverlust (OR Art. 725)\n5. **Liquiditätsgrad 1-3** (Cash Ratio, Quick Ratio, Current Ratio)\n6. **Überschuldungs-Check**\n\nErstelle für jede Kennzahl einen kurzen Kommentar (gut/kritisch/Handlungsbedarf). Erstelle mindestens 2 Charts: ein Übersichts-Chart der Margen und ein Liquiditäts-Chart."
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 4
|
||||
},
|
||||
{
|
||||
"id": "trustee-cashflow",
|
||||
"label": {"de": "Cashflow-Rechnung", "en": "Cash Flow Statement", "fr": "Tableau des flux de trésorerie"},
|
||||
"description": {"de": "Cashflow berechnen und analysieren", "en": "Calculate and analyze cash flow", "fr": "Calculer et analyser le flux de trésorerie"},
|
||||
"icon": "mdi-cash-multiple",
|
||||
"color": "#009688",
|
||||
"category": "analyse",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Erstelle eine Cashflow-Rechnung basierend auf den aktuellen Buchhaltungsdaten:\n1. **Operativer Cashflow:** Starte vom Reingewinn, bereinige um nicht-cash-wirksame Positionen (Abschreibungen, Rückstellungen, Wertberichtigungen)\n2. **Investitions-Cashflow:** Investitionen in Sachanlagen, Finanzanlagen\n3. **Finanzierungs-Cashflow:** Darlehensaufnahmen/-rückzahlungen, Dividenden, Kapitalerhöhungen\n4. **Netto-Cashflow** und Veränderung der liquiden Mittel\n\nWarne bei kritischen Werten. Erstelle ein Wasserfall-Chart oder gestapeltes Balkendiagramm der drei Cashflow-Bereiche."
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 5
|
||||
},
|
||||
{
|
||||
"id": "trustee-year-end-check",
|
||||
"label": {"de": "Jahresabschluss prüfen", "en": "Year-End Review", "fr": "Contrôle de clôture annuelle"},
|
||||
"description": {"de": "Automatische Prüfungen für den Jahresabschluss", "en": "Automated year-end review checks", "fr": "Contrôles automatisés de clôture"},
|
||||
"icon": "mdi-clipboard-check-outline",
|
||||
"color": "#795548",
|
||||
"category": "abschluss",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Führe eine automatische Jahresabschluss-Prüfung durch:\n1. **Saldovalidierung:** Prüfe alle Bilanzkonten auf Plausibilität (negative Saldi wo nicht erwartet, ungewöhnlich hohe Saldi)\n2. **Vorjahresvergleich:** Vergleiche Bilanz- und ER-Positionen mit dem Vorjahr, markiere Abweichungen >20%\n3. **Abgrenzungen:** Identifiziere potenzielle transitorische Aktiven/Passiven (regelmässige Aufwände ohne Dezember-Buchung, Erträge im Voraus)\n4. **Gesetzliche Prüfungen:** Hälftiger Kapitalverlust (OR 725), Überschuldung, Mindestkapital\n5. **MWST-Plausibilisierung:** Vorsteuer vs. geschätzter Aufwand, Umsatzsteuer vs. Umsatz\n\nErstelle eine Checkliste mit Status (OK / Warnung / Kritisch) pro Prüfpunkt."
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 6
|
||||
},
|
||||
{
|
||||
"id": "trustee-forecast",
|
||||
"label": {"de": "Prognose erstellen", "en": "Create Forecast", "fr": "Créer une prévision"},
|
||||
"description": {"de": "Trend-Analyse und Prognose der nächsten Monate", "en": "Trend analysis and forecast for coming months", "fr": "Analyse de tendance et prévision"},
|
||||
"icon": "mdi-chart-timeline-variant",
|
||||
"color": "#E91E63",
|
||||
"category": "analyse",
|
||||
"actionType": "agentPrompt",
|
||||
"config": {
|
||||
"prompt": "Erstelle eine Finanzprognose basierend auf den historischen Buchhaltungsdaten:\n1. Analysiere die Umsatz- und Aufwandsentwicklung der letzten 6 Monate (monatliche Aggregation)\n2. Identifiziere Trends und Saisonalitäten\n3. Prognostiziere Umsatz, Aufwand und Gewinn für die nächsten 3 Monate\n4. Erstelle ein Chart mit Ist-Werten und Prognose-Korridor (Best/Expected/Worst Case)\n5. Markiere Risiken: \"Wenn der Trend anhält, passiert X\"\n\nNutze eine einfache lineare Extrapolation mit Saisonalitätskorrektur wo sinnvoll."
|
||||
},
|
||||
"requiredRoles": ["trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 7
|
||||
},
|
||||
{
|
||||
"id": "trustee-upload-receipt",
|
||||
"label": {"de": "Beleg hochladen", "en": "Upload Receipt", "fr": "Télécharger un justificatif"},
|
||||
"description": {"de": "Beleg scannen oder als Datei hochladen", "en": "Scan or upload a receipt", "fr": "Scanner ou télécharger un justificatif"},
|
||||
"icon": "mdi-camera-document-outline",
|
||||
"color": "#607D8B",
|
||||
"category": "schnellzugriff",
|
||||
"actionType": "link",
|
||||
"config": {
|
||||
"targetView": "scan-upload"
|
||||
},
|
||||
"requiredRoles": ["trustee-user", "trustee-client", "trustee-accountant", "trustee-admin"],
|
||||
"sortOrder": 8
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
- [ ] **`getQuickActions()` Funktion in `mainTrustee.py`** analog zu `getUiObjects()`, `getTemplateRoles()`
|
||||
|
||||
- [ ] **API-Endpoint `GET /api/trustee/{instanceId}/quick-actions`** in `routeFeatureTrustee.py`
|
||||
- Liest `QUICK_ACTIONS` + optional `FeatureInstance.config.get("quickActions", [])`
|
||||
- Filtert nach User-Rollen (RBAC): nur Actions deren `requiredRoles` mit den Rollen des Users auf dieser Instanz übereinstimmen
|
||||
- Sortiert nach `sortOrder`
|
||||
- Gruppiert nach `category` (optional, Frontend kann auch selbst gruppieren)
|
||||
- Response: `{ "actions": [...], "categories": [{ "id": "import", "label": {...} }, ...] }`
|
||||
|
||||
### Phase 2: Frontend — QuickActionBoard Komponente
|
||||
|
||||
- [ ] **Neue Komponente `components/QuickActionBoard/QuickActionBoard.tsx`**
|
||||
|
||||
Generische, wiederverwendbare Komponente:
|
||||
|
||||
```typescript
|
||||
interface QuickAction {
|
||||
id: string;
|
||||
label: string; // bereits in User-Sprache aufgelöst
|
||||
description: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
category: string;
|
||||
actionType: 'agentPrompt' | 'workflow' | 'link';
|
||||
config: Record<string, any>;
|
||||
}
|
||||
|
||||
interface QuickActionBoardProps {
|
||||
actions: QuickAction[];
|
||||
onDispatch: (action: QuickAction) => void;
|
||||
loading?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
UI:
|
||||
- Responsive Card-Grid (`grid-template-columns: repeat(auto-fill, minmax(220px, 1fr))`)
|
||||
- Jede Card: Icon (farbig) + Titel + Beschreibung (1-Zeiler) + Hover-Effekt
|
||||
- Kategorien als optionale Section-Header
|
||||
- Loading-Skeleton während API-Call
|
||||
- Dark-Theme Support (bestehende CSS-Variablen nutzen)
|
||||
- Kein eigener State — rein präsentational mit `onDispatch`-Callback
|
||||
|
||||
- [ ] **CSS in `components/QuickActionBoard/QuickActionBoard.module.css`**
|
||||
- Konsistentes Design mit bestehenden `TrusteeViews.module.css` Kacheln (`.statCard` Pattern)
|
||||
- Hover: leichter Scale + Shadow-Verstärkung
|
||||
- Active/Clicked: kurzer visueller Feedback (Pulse oder Farb-Flash)
|
||||
- Icon-Rendering: `mdi-*` Icons aus bestehender Icon-Library oder als Unicode/SVG Fallback
|
||||
|
||||
### Phase 3: Frontend — Dashboard-Integration
|
||||
|
||||
- [ ] **`TrusteeDashboardView.tsx` erweitern**
|
||||
|
||||
Unter dem bestehenden `statsGrid` und `infoSection`:
|
||||
|
||||
```tsx
|
||||
// Nach der infoSection:
|
||||
<QuickActionBoard
|
||||
actions={quickActions}
|
||||
onDispatch={_handleQuickAction}
|
||||
loading={actionsLoading}
|
||||
/>
|
||||
```
|
||||
|
||||
Dispatch-Handler:
|
||||
```tsx
|
||||
const _handleQuickAction = (action: QuickAction) => {
|
||||
switch (action.actionType) {
|
||||
case 'agentPrompt':
|
||||
_navigateToWorkspaceWithPrompt(action.config);
|
||||
break;
|
||||
case 'workflow':
|
||||
_triggerWorkflow(action.config);
|
||||
break;
|
||||
case 'link':
|
||||
_navigateToView(action.config.targetView);
|
||||
break;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **API-Hook `useTrusteeQuickActions(instanceId)`** in `hooks/useTrustee.ts`
|
||||
- Fetcht `GET /api/trustee/{instanceId}/quick-actions`
|
||||
- Cached Response (SWR-Pattern oder einfacher State)
|
||||
- Resolved `label`/`description` in die aktive Sprache (wie bei Navigation-Labels)
|
||||
|
||||
- [ ] **Trustee API Funktion `fetchQuickActions()`** in `api/trusteeApi.ts`
|
||||
|
||||
### Phase 4: Frontend — Workspace Pre-Fill (Cross-Feature-Dispatch)
|
||||
|
||||
- [ ] **URL-Parameter-Support in `WorkspacePage.tsx`**
|
||||
|
||||
Workspace erkennt URL-Suchparameter:
|
||||
- `?prompt=<encodedText>` → Füllt Prompt-Feld vor
|
||||
- `&autoStart=true` → Startet den Agent automatisch nach dem Laden
|
||||
- `&sourceFeature=trustee` → Optional: Kontext-Hinweis woher der User kommt
|
||||
- `&sourceInstanceId=<id>` → Optional: Trustee-Instanz für Feature-Data-Zugriff
|
||||
|
||||
Implementierung:
|
||||
```tsx
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const prompt = params.get('prompt');
|
||||
const autoStart = params.get('autoStart') === 'true';
|
||||
|
||||
if (prompt) {
|
||||
setInputText(decodeURIComponent(prompt));
|
||||
// URL bereinigen (Params entfernen, damit Reload nicht erneut startet)
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
|
||||
if (autoStart) {
|
||||
// Kurze Verzögerung damit UI gerendert ist
|
||||
setTimeout(() => _handleSend(), 300);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
```
|
||||
|
||||
- [ ] **Workspace-Instanz-Auflösung** für Cross-Feature-Navigation
|
||||
|
||||
Helper-Funktion in Trustee Dashboard:
|
||||
```typescript
|
||||
const _navigateToWorkspaceWithPrompt = async (config: QuickActionConfig) => {
|
||||
// 1. Workspace-Instanz des gleichen Mandanten finden
|
||||
const workspaceInstance = instances.find(
|
||||
i => i.featureCode === 'workspace' && i.mandateId === currentMandateId
|
||||
);
|
||||
if (!workspaceInstance) { /* Fehlerbehandlung */ }
|
||||
|
||||
// 2. Navigation mit Prompt-Parametern
|
||||
const params = new URLSearchParams({
|
||||
prompt: config.prompt,
|
||||
autoStart: 'true',
|
||||
sourceFeature: 'trustee',
|
||||
sourceInstanceId: instanceId,
|
||||
});
|
||||
navigate(`/features/workspace/${workspaceInstance.id}/dashboard?${params}`);
|
||||
};
|
||||
```
|
||||
|
||||
### Phase 5: Workflow-Dispatch (für `actionType: "workflow"`)
|
||||
|
||||
- [ ] **Graph-Editor Workflow triggern** aus dem Trustee Dashboard
|
||||
|
||||
Für `actionType: "workflow"`: Nutzt bestehenden `POST /api/graphicalEditor/{geInstanceId}/execute`:
|
||||
|
||||
```typescript
|
||||
const _triggerWorkflow = async (config: WorkflowActionConfig) => {
|
||||
// 1. GraphicalEditor-Instanz des gleichen Mandanten finden
|
||||
const geInstance = instances.find(
|
||||
i => i.featureCode === 'graphicalEditor' && i.mandateId === currentMandateId
|
||||
);
|
||||
|
||||
// 2. System-Template-Workflow finden (nach templateCode)
|
||||
const workflows = await fetchWorkflowsByTemplate(geInstance.id, config.workflowTemplateCode);
|
||||
|
||||
// 3. Ausführung triggern
|
||||
const run = await executeWorkflow(geInstance.id, workflows[0].id);
|
||||
|
||||
// 4. Feedback: Toast "Workflow gestartet" + optional Link zur Run-Ansicht
|
||||
showToast({ message: t('quickActions.workflowGestartet'), action: { label: t('quickActions.details'), onClick: () => navigateToRun(run.id) } });
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **API-Funktionen** in `api/graphicalEditorApi.ts` (falls nicht vorhanden): `fetchWorkflowsByTemplate()`, `executeWorkflow()`
|
||||
|
||||
### Querschnitt-Checks
|
||||
|
||||
- [ ] API-Endpunkte: `GET /api/trustee/{instanceId}/quick-actions` (neu)
|
||||
- [ ] DB-Schema / Migration: nein
|
||||
- [ ] Frontend-Komponenten: `QuickActionBoard` (neu, generisch), `TrusteeDashboardView` (erweitert)
|
||||
- [ ] RBAC / Permissions: Filterung über `requiredRoles` im API-Endpoint
|
||||
- [ ] Neutralisierung betroffen? nein (Prompts gehen durch normale Workspace-Pipeline)
|
||||
- [ ] Navigation / Routing: Workspace URL-Parameter-Support
|
||||
- [ ] Billing-Impact? nein (Agent-Calls laufen über bestehende Billing-Pipeline)
|
||||
- [ ] i18n: Alle Labels in `QUICK_ACTIONS` nutzen `TextMultilingual`-Format
|
||||
|
||||
---
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
||||
| # | Kriterium (Given-When-Then) | Prio |
|
||||
|---|---------------------------|------|
|
||||
| 1 | Given Trustee Dashboard, When ein User mit Rolle `trustee-accountant` die Seite öffnet, Then sieht er mindestens 6 Quick Action Cards (Belege, Sync, Budget, KPIs, Cashflow, Jahresabschluss) in einem Card-Grid unterhalb der Statistiken | must |
|
||||
| 2 | Given Quick Action "Budget-Vergleich" (Typ `agentPrompt`), When der User auf die Card klickt, Then wird er zum Workspace navigiert mit dem vorgefüllten Prompt und der Agent startet automatisch | must |
|
||||
| 3 | Given Quick Action "Belege verarbeiten" (Typ `workflow`), When der User auf die Card klickt, Then wird der zugehörige Graph-Editor Workflow getriggert und der User erhält eine Bestätigung | must |
|
||||
| 4 | Given Quick Action "Beleg hochladen" (Typ `link`), When der User auf die Card klickt, Then wird er zur Scan/Upload-Seite der aktuellen Trustee-Instanz navigiert | must |
|
||||
| 5 | Given ein User mit Rolle `trustee-client`, When er das Trustee Dashboard öffnet, Then sieht er nur die Quick Actions für seine Rolle (z.B. "Beleg hochladen"), nicht die Accountant-Aktionen (Budget, KPIs etc.) | must |
|
||||
| 6 | Given Dark Theme aktiv, When das Dashboard mit Quick Actions gerendert wird, Then sind alle Cards visuell korrekt (Farben, Kontraste, Hover-Effekte) im Dark Mode | should |
|
||||
| 7 | Given Workspace geöffnet via Quick Action mit `autoStart=true`, When der Agent gestartet wird, Then enthält der System-Prompt Kontext über die Trustee-Instanz und der Agent kann sofort auf Trustee-Daten zugreifen | should |
|
||||
| 8 | Given schmales Viewport (< 768px), When das Dashboard angezeigt wird, Then sind die Quick Action Cards in einem 1-2 Spalten Grid und weiterhin klickbar | should |
|
||||
|
||||
## Testplan
|
||||
|
||||
| ID | AC | Art | Automatisiert | Repo-Pfad / Methode | Status |
|
||||
|----|----|-----|--------------|---------------------|--------|
|
||||
| T1 | 1, 5 | api | ja | `gateway/tests/features/trustee/test_quick_actions_api.py` — Endpoint liefert gefilterte Actions pro Rolle | pending |
|
||||
| T2 | 2 | e2e | nein | Manuell: Card klicken → Workspace öffnet mit Prompt → Agent startet | pending |
|
||||
| T3 | 3 | e2e | nein | Manuell: Workflow-Card klicken → Workflow läuft → Bestätigung sichtbar | pending |
|
||||
| T4 | 4 | e2e | nein | Manuell: Link-Card klicken → korrekte Navigation | pending |
|
||||
| T5 | 6 | visual | nein | Manuell: Dark/Light Mode vergleichen | pending |
|
||||
| T6 | 7 | e2e | nein | Manuell: Budget-Vergleich aus Quick Action → Agent nutzt Trustee-Daten korrekt | pending |
|
||||
| T7 | 8 | visual | nein | Manuell: Browser-Fenster schmaler als 768px | pending |
|
||||
|
||||
## Spätere Erweiterungen (nicht in Scope)
|
||||
|
||||
| Idee | Beschreibung |
|
||||
|------|-------------|
|
||||
| **Custom Quick Actions pro Mandant** | Admin kann eigene Actions definieren (in `FeatureInstance.config.quickActions`), die mit den System-Actions gemergt werden |
|
||||
| **Workspace Empty State** | Quick Actions des aktiven Features im Workspace Empty State anzeigen (wenn kein Chat offen) |
|
||||
| **Inline-Ergebnis-Preview** | Nach Agent-Ausführung: Zusammenfassung und Charts auf dem Dashboard selbst anzeigen (statt nur im Workspace) |
|
||||
| **Favoriten / Pinned Actions** | User kann Actions pinnen; gepinnte Actions erscheinen zuoberst oder auf einer persönlichen "Home"-Seite |
|
||||
| **CommCoach Quick Actions** | "Mietergespräch üben", "Nebenkostenfragen trainieren" etc. auf dem CommCoach Dashboard |
|
||||
| **Prompt-Editor** | Power-User können Prompts der Quick Actions anpassen (Mandanten-spezifisch) |
|
||||
|
||||
## Links
|
||||
|
||||
- Kundenwünsche: `local/notes/use-cases-inputs-customers.md`
|
||||
- Customer Demo Enablement: `c-work/1-plan/2026-04-customer-demo-enablement.md`
|
||||
- Trustee Tooling: `c-work/1-plan/2026-04-trustee-tooling-and-demo-prep.md`
|
||||
- Trustee Dashboard (Frontend): `frontend_nyla/src/pages/views/trustee/TrusteeDashboardView.tsx`
|
||||
- Trustee Feature (Gateway): `gateway/modules/features/trustee/mainTrustee.py`
|
||||
- Trustee Routes (Gateway): `gateway/modules/features/trustee/routeFeatureTrustee.py`
|
||||
- Workspace Routes (Gateway): `gateway/modules/features/workspace/routeFeatureWorkspace.py`
|
||||
- Workspace Page (Frontend): `frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx`
|
||||
- FeatureView Registry (Frontend): `frontend_nyla/src/pages/FeatureView.tsx`
|
||||
- Quick Action Board (Frontend, neu): `frontend_nyla/src/components/QuickActionBoard/`
|
||||
- Navigation API: `wiki/b-reference/platform/navigation.md`
|
||||
|
||||
## Abschluss
|
||||
|
||||
- [ ] b-reference/ aktualisiert (`b-reference/gateway/features/trustee.md` — neu anlegen mit Quick Actions)
|
||||
- [ ] b-reference/frontend-nyla/architecture.md aktualisiert (QuickActionBoard-Komponente)
|
||||
- [ ] TOPICS.md aktualisiert (neues Thema "Quick Actions")
|
||||
- [ ] Dieses Dokument → z-archive/ verschoben
|
||||
369
c-work/2-build/2026-04-i18n-static-text-elimination.md
Normal file
369
c-work/2-build/2026-04-i18n-static-text-elimination.md
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
<!-- status: build -->
|
||||
<!-- lastReviewed: 2026-04-10 -->
|
||||
|
||||
# Statische Texte eliminieren — vollständige i18n-Migration
|
||||
|
||||
## Fortschritt
|
||||
|
||||
| Phase | Inhalt | Status |
|
||||
|-------|--------|--------|
|
||||
| 1 | Feature-Module (`mainXxx.py`), `registry.py`, `interfaceBootstrap.py` | **done** |
|
||||
| 2 | `nodeDefinitions/*`, `portTypes.py`, `nodeRegistry.py`, `entryPoints.py` | **done** |
|
||||
| 3–5 | Datamodels, `frontendTypes`, Frontend `t()` | offen |
|
||||
|
||||
**Umsetzung 1–2:** Skript `local/scripts/_flatten_i18n_dicts.py` (mehrsprachige Dicts → deutscher String / `json.dumps`). Anschliessend manuell: `mainSystem.py` AICore-`providerLabels`-Fallback; `portTypes.PortField.description` auf `str`; `_deriveFormPayloadSchema` / `_deriveTransformSchema`; `entryPoints._normalize_title` liefert `str`. **`Role.description`** bleibt `TextMultilingual`: `coerce_text_multilingual()` in `datamodelUtils.py` wandelt Template-Strings/Dicts; Bootstrap- und Feature-`Role(...)`-Aufrufe nutzen `coerce_text_multilingual(...)`.
|
||||
|
||||
## Problemstellung
|
||||
|
||||
Trotz Phase 1–7 der i18n-Unification existieren noch **~640+ statische mehrsprachige Dicts** (`{"en":…, "de":…, "fr":…}`) im Gateway und **~60+ Stellen** im Frontend. Diese Dicts:
|
||||
|
||||
- Müssen bei jeder neuen Sprache manuell erweitert werden
|
||||
- Umgehen das zentrale i18n-System (`t()`, Admin-UI, AI-Übersetzung)
|
||||
- Sind inkonsistent (manche nur en/de, manche nur en/fr, manche en/de/fr)
|
||||
|
||||
**Ziel:** Jeder UI-sichtbare Text wird als **deutscher Klartext-Key** gespeichert und zur Laufzeit über `t()` übersetzt. Mehrsprachige Dicts verschwinden komplett.
|
||||
|
||||
---
|
||||
|
||||
## Architektur-Entscheidung
|
||||
|
||||
### Prinzip: Deutscher Klartext = i18n-Key
|
||||
|
||||
```
|
||||
# VORHER (statisch, 3 Sprachen hardcoded):
|
||||
"label": {"en": "Documents", "de": "Dokumente", "fr": "Documents"}
|
||||
|
||||
# NACHHER (dynamisch, beliebig viele Sprachen):
|
||||
"label": "Dokumente"
|
||||
```
|
||||
|
||||
Beim Boot registriert `_registerXxxLabels()` den deutschen Text als Key im `xx`-Basisset. `t("Dokumente")` liefert zur Laufzeit die Übersetzung in der aktuellen Sprache.
|
||||
|
||||
### Sonderfälle
|
||||
|
||||
| Fall | Lösung |
|
||||
|------|--------|
|
||||
| `outputLabels` (Listen von Strings pro Sprache) | Jedes Element einzeln als Key: `"Ja"`, `"Nein"` |
|
||||
| `_ISO_LABELS` (Sprachnamen) | Bleiben statisch — sind ISO-Referenzdaten, keine UI-Texte |
|
||||
| Locale-Code-Maps (`"de": "de-DE"`) | Bleiben statisch — technische Mappings |
|
||||
| `BUILTIN_PLANS` (Subscription) | Werden zu Keys, AI übersetzt |
|
||||
| Datamodel `frontend_options` | Labels werden zu Keys, Boot-Registrierung |
|
||||
|
||||
---
|
||||
|
||||
## Datei-Index (vollständig)
|
||||
|
||||
### Gateway — Feature-Module (Kategorie A: RBAC/Katalog-Labels)
|
||||
|
||||
| # | Datei | Stellen | Muster | Phase |
|
||||
|---|-------|---------|--------|-------|
|
||||
| A1 | `features/trustee/mainTrustee.py` | ~62 | `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `UI_OBJECTS`, `TEMPLATE_ROLES`, Workflow-Gruppen, Rollen-Beschreibungen | 1 |
|
||||
| A2 | `system/mainSystem.py` | ~27 | `DATA_OBJECTS`, LLM-Provider-Labels | 1 |
|
||||
| A3 | `features/commcoach/mainCommcoach.py` | ~17 | `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `TEMPLATE_ROLES` | 1 |
|
||||
| A4 | `features/teamsbot/mainTeamsbot.py` | ~11 | `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `TEMPLATE_ROLES` | 1 |
|
||||
| A5 | `features/workspace/mainWorkspace.py` | ~10 | `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `TEMPLATE_ROLES` | 1 |
|
||||
| A6 | `features/chatbot/mainChatbot.py` | ~7 | `DATA_OBJECTS`, `TEMPLATE_ROLES` | 1 |
|
||||
| A7 | `features/neutralization/mainNeutralization.py` | ~7 | `DATA_OBJECTS`, `RESOURCE_OBJECTS` | 1 |
|
||||
| A8 | `features/realEstate/mainRealEstate.py` | ~6 | `DATA_OBJECTS`, `RESOURCE_OBJECTS` | 1 |
|
||||
| A9 | `features/graphicalEditor/mainGraphicalEditor.py` | ~6 | Permissions, Rollen-Beschreibungen | 1 |
|
||||
| A10 | `serviceCenter/registry.py` | ~14 | Service-Kategorie-Labels | 1 |
|
||||
| A11 | `interfaces/interfaceBootstrap.py` | ~4 | Template-Rollen-Beschreibungen (admin/user/viewer/sysadmin) | 1 |
|
||||
|
||||
**Summe Kategorie A: ~171 Stellen, 11 Dateien**
|
||||
|
||||
### Gateway — Graph-Editor Node-Definitionen (Kategorie B)
|
||||
|
||||
| # | Datei | Stellen | Muster | Phase |
|
||||
|---|-------|---------|--------|-------|
|
||||
| B1 | `graphicalEditor/nodeDefinitions/clickup.py` | ~50 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B2 | `graphicalEditor/nodeDefinitions/input.py` | ~31 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B3 | `graphicalEditor/portTypes.py` | ~33 | Port-Feld-Descriptions | 2 |
|
||||
| B4 | `graphicalEditor/nodeDefinitions/sharepoint.py` | ~27 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B5 | `graphicalEditor/nodeDefinitions/email.py` | ~27 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B6 | `graphicalEditor/nodeDefinitions/ai.py` | ~23 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B7 | `graphicalEditor/nodeDefinitions/trustee.py` | ~20 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B8 | `graphicalEditor/nodeDefinitions/flow.py` | ~14 | Node-Label, `outputLabels` (Sonderfall: Liste) | 2 |
|
||||
| B9 | `graphicalEditor/nodeDefinitions/data.py` | ~9 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B10 | `graphicalEditor/nodeDefinitions/triggers.py` | ~8 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B11 | `graphicalEditor/nodeDefinitions/file.py` | ~7 | Node-Label, Parameter-Descriptions | 2 |
|
||||
| B12 | `graphicalEditor/nodeRegistry.py` | ~10 | Kategorie-Labels | 2 |
|
||||
| B13 | `graphicalEditor/entryPoints.py` | ~3 | Entry-Point-Titel | 2 |
|
||||
|
||||
**Summe Kategorie B: ~262 Stellen, 13 Dateien**
|
||||
|
||||
### Gateway — Datamodel-Options (Kategorie C)
|
||||
|
||||
| # | Datei | Stellen | Muster | Phase |
|
||||
|---|-------|---------|--------|-------|
|
||||
| C1 | `datamodels/datamodelRbac.py` | ~19 | Scope/Access-Level Option-Labels (en/de/fr) | 3 |
|
||||
| C2 | `datamodels/datamodelChat.py` | ~7 | Status/Mode Option-Labels (en/fr, kein de!) | 3 |
|
||||
| C3 | `datamodels/datamodelMessaging.py` | ~11 | Channel/Status Option-Labels (en/fr) | 3 |
|
||||
| C4 | `datamodels/datamodelNotification.py` | ~8 | Type/Status Option-Labels (en/de) | 3 |
|
||||
| C5 | `datamodels/datamodelUam.py` | ~7 | Subscription-Status + Sprach-Options (en/de/fr) | 3 |
|
||||
| C6 | `datamodels/datamodelSubscription.py` | ~8 | Plan-Titel + Descriptions (en/de/fr, teils ohne fr) | 3 |
|
||||
| C7 | `datamodels/datamodelFiles.py` | ~4 | Scope Option-Labels (en/de) | 3 |
|
||||
| C8 | `datamodels/datamodelDataSource.py` | ~4 | Scope Option-Labels (en/de) | 3 |
|
||||
| C9 | `datamodels/datamodelFeatureDataSource.py` | ~4 | Scope Option-Labels (en/de) | 3 |
|
||||
| C10 | `datamodels/datamodelUiLanguage.py` | ~3 | Sync-Status Option-Labels (de/en) | 3 |
|
||||
| C11 | `features/trustee/datamodelFeatureTrustee.py` | ~13 | Währung + Dokumenttyp Option-Labels | 3 |
|
||||
| C12 | `features/neutralization/datamodelFeatureNeutralizer.py` | ~4 | Scope Option-Labels | 3 |
|
||||
|
||||
**Summe Kategorie C: ~92 Stellen, 12 Dateien**
|
||||
|
||||
### Gateway — Sonstige (Kategorie D)
|
||||
|
||||
| # | Datei | Stellen | Muster | Phase |
|
||||
|---|-------|---------|--------|-------|
|
||||
| D1 | `shared/frontendTypes.py` | ~14 | `CUSTOM_TYPE_DESCRIPTIONS` (aktuell ungenutzt) | 4 |
|
||||
| D2 | `features/trustee/accounting/connectors/accountingConnectorBexio.py` | ~4 | Connector-Label + Feld-Labels | 4 |
|
||||
| D3 | `features/trustee/accounting/connectors/accountingConnectorRma.py` | ~4 | Connector-Label + Feld-Labels | 4 |
|
||||
| D4 | `features/trustee/accounting/connectors/accountingConnectorAbacus.py` | ~5 | Connector-Label + Feld-Labels | 4 |
|
||||
|
||||
**Summe Kategorie D: ~27 Stellen, 4 Dateien**
|
||||
|
||||
### Frontend (Kategorie E)
|
||||
|
||||
| # | Datei | Stellen | Muster | Phase |
|
||||
|---|-------|---------|--------|-------|
|
||||
| E1 | `pages/Store.tsx` | ~5 | `FEATURE_DESCRIPTIONS` Dict (de/en/fr) | 5 |
|
||||
| E2 | `types/mandate.ts` | ~45 | Statische Navigation-Labels (de/en) | 5 |
|
||||
| E3 | `pages/views/trustee/TrusteeAbschlussView.tsx` | ~6 | Tile-Titel/Descriptions (de/en/fr) | 5 |
|
||||
| E4 | `pages/views/trustee/TrusteeAnalyseView.tsx` | ~4 | Tile-Descriptions (de/en) | 5 |
|
||||
| E5 | `components/UnifiedDataBar/UnifiedDataBar.tsx` | ~3 | `_TAB_LABELS` (de/en/fr) | 5 |
|
||||
| E6 | `api/featuresApi.ts` | ~4 | Mock-Labels (de/en) | 5 |
|
||||
| E7 | Diverse (12 Dateien) | ~12 | Hardcoded deutsche Strings ohne `t()` | 5 |
|
||||
|
||||
**Summe Kategorie E: ~79 Stellen, ~18 Dateien**
|
||||
|
||||
### Ausnahmen (bleiben statisch)
|
||||
|
||||
| Datei | Grund |
|
||||
|-------|-------|
|
||||
| `routes/routeI18n.py` (`_ISO_LABELS`) | ISO-Referenzdaten (Sprachnamen), kein UI-Text |
|
||||
| `serviceAgent/coreTools/_mediaTools.py` | Locale-Code-Map (`"de"→"de-DE"`), technisch |
|
||||
| `serviceAgent/conversationManager.py` | Sprach-Name-Map für Agent-Kontext, technisch |
|
||||
|
||||
---
|
||||
|
||||
## Gesamtübersicht
|
||||
|
||||
| Kategorie | Dateien | Stellen | Komplexität |
|
||||
|-----------|---------|---------|-------------|
|
||||
| A: Feature-Module | 11 | ~171 | Mittel — uniformes Muster, braucht Boot-Registrierung |
|
||||
| B: Node-Definitionen | 13 | ~262 | Mittel — uniformes Muster, braucht eigene Registrierung |
|
||||
| C: Datamodel-Options | 12 | ~92 | Hoch — verschiedene Patterns, braucht generische Lösung |
|
||||
| D: Sonstige Gateway | 4 | ~27 | Niedrig — einfache Ersetzung |
|
||||
| E: Frontend | ~18 | ~79 | Niedrig — `t()` wrappen |
|
||||
| **Total** | **~58** | **~631** | |
|
||||
|
||||
---
|
||||
|
||||
## Umsetzungsplan (5 Phasen)
|
||||
|
||||
### Phase 1: Feature-Module (Kategorie A) — Composer-geeignet
|
||||
|
||||
**Aufwand:** Mittel | **Modell:** Composer (schnelles Modell) | **Risiko:** Niedrig
|
||||
|
||||
**Vorbereitung (einmalig, Opus):**
|
||||
- `_registerRbacLabels()` in `i18nRegistry.py` erweitern: neben `DATA_OBJECTS`, `RESOURCE_OBJECTS`, `TEMPLATE_ROLES` auch scannen:
|
||||
- `UI_OBJECTS[].label`
|
||||
- Workflow-Gruppen-Labels (`TRUSTEE_WORKFLOW_GROUPS`, `TRUSTEE_SERVICE_CATEGORIES`)
|
||||
- Rollen-`description` Blöcke
|
||||
- Service-Kategorie-Labels (`serviceCenter/registry.py`)
|
||||
- Bootstrap-Rollen (`interfaceBootstrap.py`)
|
||||
|
||||
**Transformation (pro Datei, Composer):**
|
||||
Jedes `"label": {"en": "X", "de": "Y", "fr": "Z"}` wird zu `"label": "Y"` (deutscher Text).
|
||||
Jedes `"description": {"en": "X", "de": "Y", "fr": "Z"}` wird zu `"description": "Y"`.
|
||||
|
||||
**Regel für Composer:**
|
||||
```
|
||||
In der Datei [DATEI]:
|
||||
- Ersetze jedes Dict {"en": "...", "de": "DEUTSCH", "fr": "..."} durch den deutschen Wert "DEUTSCH"
|
||||
- Ersetze jedes Dict {"de": "DEUTSCH", "en": "...", "fr": "..."} durch "DEUTSCH"
|
||||
- Wenn kein "de" vorhanden: nimm "en" Wert
|
||||
- Lasse alle anderen Felder unverändert
|
||||
```
|
||||
|
||||
**Dateien:** A1–A11 (11 Dateien)
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- [ ] Kein `"fr":` mehr in den 11 Dateien (ausser Ausnahmen)
|
||||
- [ ] `_registerRbacLabels()` registriert alle neuen Key-Kategorien
|
||||
- [ ] Gateway startet fehlerfrei
|
||||
- [ ] Admin-UI Sprachen-Seite zeigt neue Keys im xx-Set
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Node-Definitionen (Kategorie B) — Composer-geeignet
|
||||
|
||||
**Aufwand:** Mittel | **Modell:** Composer (schnelles Modell) | **Risiko:** Niedrig
|
||||
|
||||
**Vorbereitung (einmalig, Opus):**
|
||||
- Neue Funktion `_registerNodeLabels()` in `i18nRegistry.py`:
|
||||
- Scannt `STATIC_NODE_TYPES` aus `nodeDefinitions/__init__.py`
|
||||
- Registriert `label`, `description`, `parameters[].description`, `outputLabels[]` als Keys
|
||||
- Context: `node.label`, `node.desc`, `node.param`, `node.output`
|
||||
- Scannt `portTypes.PORT_TYPE_CATALOG` für Port-Feld-Descriptions
|
||||
- Context: `port.desc`
|
||||
- Scannt `nodeRegistry` Kategorie-Labels
|
||||
- Context: `node.category`
|
||||
- Scannt `entryPoints` Titel
|
||||
- Context: `node.entry`
|
||||
|
||||
**Transformation (pro Datei, Composer):**
|
||||
Identisches Muster wie Phase 1: Dict → deutscher String.
|
||||
|
||||
**Sonderfall `flow.py` `outputLabels`:**
|
||||
```python
|
||||
# VORHER:
|
||||
"outputLabels": {"en": ["Yes", "No"], "de": ["Ja", "Nein"], "fr": ["Oui", "Non"]}
|
||||
|
||||
# NACHHER:
|
||||
"outputLabels": ["Ja", "Nein"]
|
||||
```
|
||||
|
||||
**Dateien:** B1–B13 (13 Dateien)
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- [ ] Kein `"fr":` mehr in den 13 Dateien
|
||||
- [ ] `_registerNodeLabels()` registriert alle Node-Keys
|
||||
- [ ] Graph-Editor zeigt Nodes korrekt an (Labels übersetzt)
|
||||
- [ ] Node-Parameter-Descriptions im Config-Panel korrekt
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Datamodel-Options (Kategorie C) — Opus nötig
|
||||
|
||||
**Aufwand:** Hoch | **Modell:** Opus | **Risiko:** Mittel
|
||||
|
||||
**Warum Opus:** Die Patterns sind uneinheitlich (en/fr, en/de, en/de/fr), die `frontend_options` Struktur variiert, und die Boot-Registrierung muss generisch über alle Datamodels funktionieren.
|
||||
|
||||
**Vorbereitung:**
|
||||
- Neue generische Funktion `_registerDatamodelOptionLabels()` in `i18nRegistry.py`:
|
||||
- Scannt alle Pydantic-Modelle mit `json_schema_extra` → `frontend_options`
|
||||
- Extrahiert `label` Dicts und registriert den deutschen (oder englischen) Text als Key
|
||||
- Context: `option.{ModelName}.{fieldName}`
|
||||
- `BUILTIN_PLANS` in `datamodelSubscription.py`: `title`/`description` zu Keys
|
||||
|
||||
**Transformation (pro Datei):**
|
||||
```python
|
||||
# VORHER:
|
||||
{"value": "active", "label": {"en": "Active", "de": "Aktiv", "fr": "Actif"}}
|
||||
|
||||
# NACHHER:
|
||||
{"value": "active", "label": "Aktiv"}
|
||||
```
|
||||
|
||||
**Problem: Fehlende Sprachen.** Einige Dicts haben kein `"de"` (z.B. `datamodelChat.py` nur en/fr). Hier wird `"en"` als Fallback genommen und der englische Text als Key registriert — die AI-Übersetzung erzeugt dann `de` und `fr`.
|
||||
|
||||
**Dateien:** C1–C12 (12 Dateien)
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- [ ] Kein `"fr":` / `"en":` Dict-Pattern mehr in den 12 Dateien
|
||||
- [ ] `_registerDatamodelOptionLabels()` registriert alle Option-Keys
|
||||
- [ ] Frontend Select-Felder zeigen korrekte Labels
|
||||
- [ ] Subscription-Plan-Texte korrekt übersetzt
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Sonstige Gateway (Kategorie D) — Composer-geeignet
|
||||
|
||||
**Aufwand:** Niedrig | **Modell:** Composer (schnelles Modell) | **Risiko:** Niedrig
|
||||
|
||||
**Transformation:**
|
||||
- `frontendTypes.py`: `CUSTOM_TYPE_DESCRIPTIONS` komplett entfernen (ungenutzt) + `getCustomTypeDescription()` und `registerCustomType()` vereinfachen oder entfernen
|
||||
- Accounting-Connectors: `displayName()` und Feld-Labels zu deutschen Strings
|
||||
|
||||
**Dateien:** D1–D4 (4 Dateien)
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- [ ] `CUSTOM_TYPE_DESCRIPTIONS` entfernt
|
||||
- [ ] Accounting-Connector-Labels als deutsche Strings
|
||||
- [ ] Kein `"fr":` mehr in den 4 Dateien
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Frontend (Kategorie E) — Composer-geeignet
|
||||
|
||||
**Aufwand:** Niedrig | **Modell:** Composer (schnelles Modell) | **Risiko:** Niedrig
|
||||
|
||||
**Transformation:**
|
||||
- Alle `{"en": "X", "de": "Y", "fr": "Z"}` Dicts durch `t("Y")` ersetzen
|
||||
- Alle hardcodierten deutschen Strings in JSX-Attributen mit `t()` wrappen
|
||||
- `mandate.ts` Navigation-Labels: zu `t()`-Keys (Backend liefert bereits i18n-Keys)
|
||||
- `_TAB_LABELS` in `UnifiedDataBar.tsx`: zu `t()`-Aufrufen
|
||||
- `FEATURE_DESCRIPTIONS` in `Store.tsx`: zu `t()`-Keys
|
||||
|
||||
**Dateien:** E1–E7 (~18 Dateien)
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- [ ] Kein statisches `de:`/`en:`/`fr:` Dict-Pattern im Frontend
|
||||
- [ ] Alle UI-Texte via `t()` getaggt
|
||||
- [ ] Sprache wechseln → alle Texte ändern sich
|
||||
|
||||
---
|
||||
|
||||
## Composer-Anweisungen (Copy-Paste-fertig)
|
||||
|
||||
### Für Phase 1 + 2 + 4 (uniforme Dict→String Ersetzung):
|
||||
|
||||
```
|
||||
Aufgabe: Ersetze in [DATEI] alle statischen mehrsprachigen Dicts durch den deutschen Klartext-String.
|
||||
|
||||
Regeln:
|
||||
1. {"en": "...", "de": "DEUTSCH", "fr": "..."} → "DEUTSCH"
|
||||
2. {"de": "DEUTSCH", "en": "...", "fr": "..."} → "DEUTSCH"
|
||||
3. {"en": "ENGLISH", "fr": "..."} (kein "de") → "ENGLISH"
|
||||
4. {"en": "ENGLISH", "de": "DEUTSCH"} (kein "fr") → "DEUTSCH"
|
||||
5. Listen-Sonderfall: {"en": [...], "de": [LISTE], "fr": [...]} → [LISTE]
|
||||
6. Nur "label", "description", "title", "displayName" Felder ändern
|
||||
7. Keine Imports, Funktionssignaturen oder Logik ändern
|
||||
8. Keine Kommentare hinzufügen
|
||||
```
|
||||
|
||||
### Für Phase 5 (Frontend t()-Wrapping):
|
||||
|
||||
```
|
||||
Aufgabe: Ersetze in [DATEI] alle statischen Texte durch t()-Aufrufe.
|
||||
|
||||
Regeln:
|
||||
1. {"en": "...", "de": "DEUTSCH", "fr": "..."} → t("DEUTSCH")
|
||||
2. Hardcoded string "DEUTSCH" in label/title/placeholder/aria-label → t("DEUTSCH")
|
||||
3. Import { useLanguage } from '...LanguageContext' hinzufügen falls fehlend
|
||||
4. const { t } = useLanguage(); in der Komponente falls fehlend
|
||||
5. Keine Logik ändern, nur Texte wrappen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reihenfolge und Abhängigkeiten
|
||||
|
||||
```
|
||||
Phase 1 ──→ Phase 2 ──→ Phase 3 ──→ Phase 4
|
||||
(A) (B) (C) (D)
|
||||
│
|
||||
▼
|
||||
Phase 5
|
||||
(E)
|
||||
```
|
||||
|
||||
- Phase 1 muss zuerst: erweitert `_registerRbacLabels()` als Grundlage
|
||||
- Phase 2 nach 1: braucht das Pattern von Phase 1
|
||||
- Phase 3 nach 2: komplexeste Phase, braucht neue generische Registrierung
|
||||
- Phase 4 + 5: unabhängig voneinander, nach Phase 1
|
||||
|
||||
---
|
||||
|
||||
## Aufwandsschätzung
|
||||
|
||||
| Phase | Modell | Dateien | Geschätzte Zeit |
|
||||
|-------|--------|---------|-----------------|
|
||||
| 1 (Vorbereitung) | Opus | 1 | 15 min |
|
||||
| 1 (Transformation) | Composer | 11 | 30 min |
|
||||
| 2 (Vorbereitung) | Opus | 1 | 15 min |
|
||||
| 2 (Transformation) | Composer | 13 | 30 min |
|
||||
| 3 | Opus | 13 | 45 min |
|
||||
| 4 | Composer | 4 | 10 min |
|
||||
| 5 | Composer | 18 | 30 min |
|
||||
| **Total** | | **~58** | **~3 Stunden** |
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- status: plan -->
|
||||
<!-- status: done -->
|
||||
<!-- started: 2026-04-09 -->
|
||||
<!-- component: platform -->
|
||||
|
||||
|
|
@ -283,52 +283,56 @@ async def _i18nMiddleware(request, call_next):
|
|||
|
||||
### Phase 1: Infrastruktur + Decorator -- Cursor: **Opus 4.6**
|
||||
Architektur-Arbeit: neues Modul, Boot-Integration, Decorator-Logik, `attributeUtils` Umbau. Braucht tiefes Verstaendnis der bestehenden Codebasis (DB-Schema, Boot-Reihenfolge, ContextVar, async).
|
||||
- [ ] `i18nRegistry.py` erstellen: `t()`, `@i18nModel`, `_REGISTRY`, `_CACHE`, `_setLanguage`, `_syncRegistryToDb`, `_loadCache`
|
||||
- [ ] `app.py`: Boot-Hook nach DB-Init: `_syncRegistryToDb()` + `_loadCache()`
|
||||
- [ ] `app.py`: Request-Middleware fuer `_setLanguage()` (aus Accept-Language oder User-Session)
|
||||
- [ ] `routeI18n.py`: `_loadCache()` nach sync/update aufrufen (Cache invalidieren)
|
||||
- [ ] `attributeUtils.py`: `getModelLabels()`/`getModelLabel()` auf neues MODEL_LABELS-Format (str statt Dict) + t()-Cache umstellen
|
||||
- [ ] 2-3 Beispiel-Models migrieren (`datamodelBase.py`, `datamodelFeatures.py`) als Referenz fuer Phase 2
|
||||
- [ ] Gateway starten, pruefen ob Decorator + Boot-Sync funktioniert
|
||||
- [x] `i18nRegistry.py` erstellen: `t()`, `@i18nModel`, `_REGISTRY`, `_CACHE`, `_setLanguage`, `_syncRegistryToDb`, `_loadCache`
|
||||
- [x] `app.py`: Boot-Hook nach DB-Init: `_syncRegistryToDb()` + `_loadCache()`
|
||||
- [x] `app.py`: Request-Middleware fuer `_setLanguage()` (aus Accept-Language oder User-Session)
|
||||
- [x] `routeI18n.py`: `_loadCache()` nach sync/update aufrufen (Cache invalidieren)
|
||||
- [x] `attributeUtils.py`: `getModelLabels()`/`getModelLabel()` auf neues MODEL_LABELS-Format (str statt Dict) + t()-Cache umstellen
|
||||
- [x] 2-3 Beispiel-Models migrieren (`datamodelBase.py`, `datamodelFeatures.py`) als Referenz fuer Phase 2
|
||||
- [x] Gateway starten, pruefen ob Decorator + Boot-Sync funktioniert
|
||||
|
||||
### Phase 2: Pydantic-Models migrieren (~27 verbleibende Dateien) -- Cursor: **Auto / Fast**
|
||||
Repetitive Arbeit nach klarem Pattern aus Phase 1: Decorator drauf, `json_schema_extra["label"]` ergaenzen, `registerModelLabels()` loeschen. In Batches von 5-8 Dateien.
|
||||
- [ ] Alle verbleibenden Pydantic-Models: `@i18nModel("Label")` Decorator + `json_schema_extra={"label": "..."}` zu Fields
|
||||
- [ ] Alle `registerModelLabels()`-Aufrufe loeschen
|
||||
- [ ] `from modules.shared.attributeUtils import registerModelLabels` Imports entfernen
|
||||
- [ ] Nach jedem Batch: Gateway starten und pruefen
|
||||
- [x] Alle verbleibenden Pydantic-Models: `@i18nModel("Label")` Decorator + `json_schema_extra={"label": "..."}` zu Fields
|
||||
- [x] Alle `registerModelLabels()`-Aufrufe loeschen
|
||||
- [x] `from modules.shared.attributeUtils import registerModelLabels` Imports entfernen
|
||||
- [x] Nach jedem Batch: Gateway starten und pruefen
|
||||
|
||||
### Phase 3: HTTPException-Texte umstellen (~21 Dateien, ~150 Stellen) -- Cursor: **Auto / Fast**
|
||||
Mechanische Arbeit: `detail="Text"` wird zu `detail=t("Text", "api.routeName", "Beschreibung")`. Klares Pattern, in Batches von 5-7 Dateien.
|
||||
- [ ] Alle UI-sichtbaren `HTTPException(detail="...")` in `routes/*.py` auf `t()` umstellen
|
||||
- [ ] Interne/technische Fehlermeldungen (die nie im UI erscheinen) NICHT umstellen
|
||||
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] Interne/technische Fehlermeldungen (`detail=str(e)`, `detail=f"...{e}..."`) unveraendert gelassen
|
||||
|
||||
### Phase 4: TextMultilingual UI (Frontend, 2-3 Dateien) -- Cursor: **Opus 4.6**
|
||||
React-Hooks, dynamische Rendering-Logik, `ge`->`de` Mapping. Braucht Verstaendnis des Frontend-i18n-Systems und FormGenerator-Architektur.
|
||||
- [ ] `FormGeneratorForm.tsx`: `renderMultilingualField` dynamisch aus `availableLanguages`
|
||||
- [ ] `FormGeneratorTable.tsx`: `formatTextMultilingual` dynamisch
|
||||
- [ ] `TextMultilingual` Backend-Typ pruefen: `ge` -> `de` Mapping ggf. anpassen
|
||||
- [x] `FormGeneratorForm.tsx`: `renderMultilingualField` dynamisch aus `availableLanguages` (Fallback auf `[en, ge]` wenn keine Sprachen geladen)
|
||||
- [x] `FormGeneratorTable.tsx`: `formatTextMultilingual` + `convertToDisplayString` dynamisch (hardcoded `langMap` durch zentrales `_toBackendLang` ersetzt)
|
||||
- [x] `TextMultilingual` Backend-Typ: `get_text()` und `from_dict()` akzeptieren jetzt `de` als Alias fuer `ge`. DB-Schema bleibt `ge` (bestehende Daten).
|
||||
|
||||
### Phase 5: Integration + Test -- Cursor: **Opus 4.6**
|
||||
End-to-End Pruefung, Debugging, Log-Analyse, ggf. Fixes. Braucht das staerkste Modell fuer Fehleranalyse.
|
||||
- [ ] Gateway starten, pruefen ob Keys in `UiLanguageSet(xx)` erscheinen (context=api, table.*)
|
||||
- [ ] Admin-UI: Sprache synchronisieren, pruefen ob Gateway-Keys uebersetzt werden
|
||||
- [ ] UI mit anderer Sprache testen: Fehlermeldungen, Tabellen-Labels, TextMultilingual-Felder
|
||||
- [x] Gateway-Import aller Route-Module: 36/41 ok (5 Fehler = fehlende optionale Deps: aiohttp, langchain_core, tavily)
|
||||
- [x] `@i18nModel` registriert 90 Models mit 490 table-Keys in `_REGISTRY` + `MODEL_LABELS`
|
||||
- [x] `getModelLabel` / `getModelLabels` / `getModelAttributeDefinitions` lesen korrekt aus `i18nRegistry.MODEL_LABELS`
|
||||
- [x] `routeApiMsg` (api-Keys) registrieren sich lazy beim ersten `t()`-Aufruf zur Laufzeit
|
||||
- [x] `app.py`: Middleware (`_i18nMiddleware`) + Boot-Hooks (`_syncRegistryToDb`, `_loadCache`) vorhanden
|
||||
- [x] Admin-UI: Sprache synchronisieren, Gateway-Keys werden uebersetzt (manuell getestet)
|
||||
- [x] UI mit anderer Sprache testen: Fehlermeldungen, Tabellen-Labels, TextMultilingual-Felder (manuell getestet)
|
||||
|
||||
### Phase 6: Wiki / Coding-Conventions aktualisieren -- Cursor: **Auto / Fast**
|
||||
Reine Doku-Arbeit. Inhalte stehen bereits im Plan (siehe "Wiki-Anpassungen fuer Cursor AI Coding" unten). Nur Einpflegen und Formatieren.
|
||||
- [ ] `d-guides/coding-conventions.md`: Backend-i18n-Regeln hinzufuegen (t(), @i18nModel, json_schema_extra["label"])
|
||||
- [ ] `d-guides/coding-conventions.md`: Regel fuer HTTPException-Texte mit t()
|
||||
- [ ] `d-guides/coding-conventions.md`: Regel fuer neue Pydantic-Models (@i18nModel Pflicht)
|
||||
- [ ] `b-reference/gateway/architecture.md`: i18n-Architektur dokumentieren (i18nRegistry, Boot-Sync, Cache)
|
||||
- [ ] `b-reference/frontend-nyla/architecture.md`: TextMultilingual dynamisch dokumentieren
|
||||
- [ ] `TOPICS.md`: Thema "i18n / Mehrsprachigkeit" hinzufuegen mit Verweis auf relevante Seiten
|
||||
- [x] `d-guides/coding-conventions.md`: Backend-i18n-Regeln hinzugefuegt (t(), @i18nModel, json_schema_extra["label"], apiRouteContext)
|
||||
- [x] `d-guides/coding-conventions.md`: Regel fuer HTTPException-Texte mit routeApiMsg()
|
||||
- [x] `d-guides/coding-conventions.md`: Regel fuer neue Pydantic-Models (@i18nModel Pflicht)
|
||||
- [x] `b-reference/gateway/architecture.md`: i18n-Architektur dokumentiert (i18nRegistry, Boot-Sync, Cache, Context-Namensraeume, Entry-Identitaet)
|
||||
- [x] `b-reference/frontend-nyla/architecture.md`: TextMultilingual dynamisch + AdminLanguagesKeepAlive dokumentiert
|
||||
- [x] `TOPICS.md`: Thema "i18n / Mehrsprachigkeit" hinzugefuegt (Cross-Cutting + Aktive Arbeiten)
|
||||
|
||||
### Abschluss
|
||||
- [ ] RBAC / Permissions: nicht betroffen
|
||||
- [ ] Neutralisierung: nicht betroffen
|
||||
- [ ] Navigation / Routing: nicht betroffen
|
||||
- [ ] Billing-Impact: nicht betroffen
|
||||
- [x] RBAC / Permissions: nicht betroffen
|
||||
- [x] Neutralisierung: nicht betroffen
|
||||
- [x] Navigation / Routing: nicht betroffen
|
||||
- [x] Billing-Impact: nicht betroffen
|
||||
|
||||
## Wiki-Anpassungen fuer Cursor AI Coding
|
||||
|
||||
|
|
@ -389,6 +393,12 @@ class User(PowerOnModel):
|
|||
|
||||
TextMultilingual-Felder rendern automatisch Eingabefelder fuer alle verfuegbaren Sprachen
|
||||
(aus `availableLanguages`). Keine hardcodierten Sprach-Codes (en/ge/fr/it) mehr verwenden.
|
||||
|
||||
**Geplanter UX-Mehrwert:** Pro mehrsprachigem Feld ein Button (z. B. „In alle Sprachen
|
||||
uebersetzen“), der den Inhalt der **Quellsprache** (Default: z. B. `en` als Pflichtfeld im
|
||||
Modell, oder die vom Nutzer befuellte Zeile / aktuelle UI-Sprache — festzulegen) per **KI**
|
||||
in alle **anderen** Sprachfelder uebernimmt — dieselbe Logik wie die Admin-Sprachen-AI
|
||||
(siehe *Phase 7b* im Hauptdokument).
|
||||
```
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
|
@ -431,8 +441,68 @@ TextMultilingual-Felder rendern automatisch Eingabefelder fuer alle verfuegbaren
|
|||
- UiLanguageSet Model: `gateway/modules/datamodels/datamodelUiLanguage.py`
|
||||
- TextMultilingual: `gateway/modules/datamodels/datamodelUtils.py`
|
||||
|
||||
## Phase 7 (Vorschlag): RBAC-Labels & Quick Actions — Abgleich mit dem Code
|
||||
|
||||
### Verifiziert (Stand Pruefung)
|
||||
|
||||
| Mechanismus | Code / Pfad | Befund |
|
||||
|-------------|-------------|--------|
|
||||
| **TextMultilingual** | `gateway/modules/datamodels/datamodelUtils.py` | Pydantic-Modell: **`en` Pflicht**, `de`/`fr`/`it` optional; `get_text(lang)` mit Fallback auf `en`. |
|
||||
| **Rollenbeschreibung in der DB** | `gateway/modules/datamodels/datamodelRbac.py` — `Role.description: TextMultilingual` | Feld ist **explizit mehrsprachig**; im Schema `frontend_type: "multilingual"`. |
|
||||
| **Admin-Formular** | `FormGeneratorForm.tsx` | Felder mit Typ `multilingual` rendern **pro Sprache Eingaben** aus `availableLanguages` — passt zu **TextMultilingual-Objekten** (nicht zu einem einzelnen i18n-Key). |
|
||||
| **Template-Rollen (Code)** | `mainTrustee.py` etc. — `TEMPLATE_ROLES[].description` | Im Python **Dict** `{en,de,fr}`; beim Sync in die DB als **TextMultilingual**/`Role`-Record. |
|
||||
| **RBAC-Katalog (RAM)** | `rbacCatalog.py` — `registerDataObject` / `registerResourceObject` | Labels sind **lose Dicts** `{en,de,...}` im Speicher — **kein** Pydantic-TextMultilingual-Typ auf dem Katalog-Eintrag. |
|
||||
| **Feature-UI (Navigation)** | `UI_OBJECTS[].label` | Bereits auf **deutschen String** (Basis-Key) umgestellt; Navigation nutzt **`t()`** im Frontend. |
|
||||
| **Quick Actions** | `routeFeatureTrustee.py` — `GET .../quick-actions?language=` | Backend **loest** `label`/`description`-Dicts **serverseitig** mit `language` auf; Response = **fertige Strings**. |
|
||||
| **QuickActionBoard** | `QuickActionBoard.tsx` | Erwartet **`label: string`**, **`description: string`** — **keine** TextMultilingual-Objekte auf dem Draht. |
|
||||
| **TrusteeDashboardView** | `TrusteeDashboardView.tsx` | Laed Quick Actions neu bei **`currentLanguage`**-Wechsel (useEffect-Dependency). |
|
||||
|
||||
**Kernpunkt:** Es gibt **zwei legitime Muster** im gleichen Produkt:
|
||||
|
||||
1. **Persistierte Entitaeten** (z. B. `Role`) mit **TextMultilingual** — Bearbeitung im UI als **Objekt mit Sprachfeldern** (bereits vorhanden).
|
||||
2. **Statische Code-Listen** (Katalog-Dicts, Quick-Action-Definitionen) — heute **Dicts im Python** oder **serverseitige Aufloesung**; Navigation/UI-Labels der zweiten Schicht sind auf **String-Key + `t()`** migriert.
|
||||
|
||||
### Phase 7 — angepasste Empfehlung
|
||||
|
||||
**Nicht** alles auf „ein deutscher String = einziger Key“ vereinheitlichen, wenn **TextMultilingual** und **FormGenerator** bereits passen:
|
||||
|
||||
- **`Role.description` (und gleichartige DB-Felder):** Bei **TextMultilingual** bleiben: Übersetzungen koennen weiterhin **pro Sprache in der DB** gepflegt werden **oder** spaeter mit UiLanguageSet synchronisiert werden (separates Konzept: „Spiegelung“ vs. Duplikat vermeiden).
|
||||
- **`DATA_OBJECTS` / `RESOURCE_OBJECTS`:** Entweder (a) **Dicts** beibehalten und zusaetzlich **deutsche Basis-Texte** als i18n-Keys in `_REGISTRY` registrieren (`context=rbac.*`) fuer Admin/AI, **oder** (b) auf **TextMultilingual-Shape** im Katalog vereinheitlichen (Aufwand: API + Admin-Anzeige).
|
||||
- **Quick Actions:** Entweder (a) **serverseitige** Aufloesung beibehalten und **Gateway `t()`** auf die **deutschen Basis-Strings** aus den Dicts anwenden (Cache pro Request-Sprache), **oder** (b) nur noch **deutsche Keys** ausliefern und **`t()` im Frontend** (wie MandateNavigation) — dann `QuickActionBoard` um `t(action.label)` erweitern.
|
||||
|
||||
**Konkreter naechster technischer Schritt (klein):** `_registerRbacLabels()` in `i18nRegistry.py` — aus allen `DATA_OBJECTS`/`RESOURCE_OBJECTS` die **de**-Texte (und optional Template-**description**-de) als Keys mit `context` `rbac.data` / `rbac.resource` / `rbac.role` ins **xx**-Set syncen, **ohne** das Datenmodell `TextMultilingual` zu ersetzen.
|
||||
|
||||
**Nicht empfohlen:** `Role.description` auf einen reinen String-Key ohne Migration umstellen — bricht **FormGenerator**-Erwartung und bestehende DB-Daten, solange `TextMultilingual` Pflicht bleibt.
|
||||
|
||||
### Phase 7b (UX): TextMultilingual — Button „In alle Sprachen uebersetzen“
|
||||
|
||||
**Ziel:** Echten Mehrwert im Formular: Nutzer traegt den Text **einmal** in der gewuenschten
|
||||
**Ausgangs-Sprache** ein und kann per Klick die **uebrigen** Sprachfelder automatisch fuellen
|
||||
(statt fuenfmal manuell zu tippen).
|
||||
|
||||
**Machbarkeit:** **Ja.** Technisch gut andockbar:
|
||||
|
||||
| Baustein | Bemerkung |
|
||||
|----------|-----------|
|
||||
| **Gateway** | `routeI18n.py` enthaelt bereits `_translateBatch` (KI, Batches, Kapitalisierung `_matchCapitalization`). Ergaenzung: schlanker Endpoint z. B. `POST /api/i18n/translate-field` mit Body `{ "sourceText": "...", "sourceLang": "de", "targetLangs": ["en","fr"] }` und Response `{ "en": "...", "fr": "..." }` — **Auth + Billing** analog zu bestehenden Uebersetzungs-Jobs. |
|
||||
| **Frontend** | `FormGeneratorForm.tsx` — `renderMultilingualField`: neben dem Feld-Label oder unter den Inputs ein Button; onClick: API aufrufen, dann `handleMultilingualChange` fuer jede Zielsprache setzen (Quellsprache unveraendert lassen). Loading/Disabled waehrend der Anfrage; Fehler via Toast. |
|
||||
| **Quellsprache** | Produktregel festlegen: (A) immer **englisch** (`en`), weil im Modell Pflicht, oder (B) **aktuelle UI-Sprache** (`currentLanguage`), oder (C) die **erste nicht-leere** Zeile unter den Sprach-Inputs. Empfehlung: **(C)** mit Fallback auf `en`, damit es intuitiv bleibt. |
|
||||
| **Kosten / Limits** | Gleiche Policy wie Admin-AI-Uebersetzung (Billing-Callback, Rate-Limits). |
|
||||
|
||||
**Abgrenzung:** Kein Ersatz fuer professionelles Review; KI kann Fachbegriffe falsch setzen —
|
||||
Button-Tooltip mit Hinweis optional.
|
||||
|
||||
**Status:** ✅ Umgesetzt (Phase 7 + 7b).
|
||||
|
||||
- `_registerRbacLabels()` registriert 118 Keys (rbac.data, rbac.resource, rbac.role, rbac.quickaction) im xx-Basisset.
|
||||
- `POST /api/i18n/translate-field` Endpoint fuer On-Demand-Uebersetzung von TextMultilingual-Feldern.
|
||||
- FormGenerator: Button „In alle Sprachen uebersetzen" in multilingualen Feldern.
|
||||
|
||||
**Konkreter Umsetzungsplan (Arbeitspakete, Sprints, Abnahme):** siehe
|
||||
`c-work/1-plan/2026-04-gateway-i18n-phase-7-implementation.md`.
|
||||
|
||||
## Abschluss
|
||||
|
||||
- [ ] b-reference/ aktualisiert (gateway/architecture.md, frontend-nyla/architecture.md)
|
||||
- [ ] TOPICS.md aktualisiert (neues Thema: i18n/Mehrsprachigkeit)
|
||||
- [ ] Dieses Dokument -> z-archive/ verschoben
|
||||
- [x] b-reference/ aktualisiert (gateway/architecture.md, frontend-nyla/architecture.md)
|
||||
- [x] TOPICS.md aktualisiert (neues Thema: i18n/Mehrsprachigkeit)
|
||||
- [ ] Dieses Dokument -> z-archive/ verschoben (nach finaler Validierung)
|
||||
133
c-work/3-validate/2026-04-gateway-duplicate-class-names.md
Normal file
133
c-work/3-validate/2026-04-gateway-duplicate-class-names.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<!-- status: done -->
|
||||
<!-- started: 2026-04-09 -->
|
||||
<!-- component: gateway -->
|
||||
|
||||
# Gateway: Doppelte Klassennamen bereinigen
|
||||
|
||||
## Beschreibung und Kontext
|
||||
|
||||
Beim Aufräumen der `@i18nModel`-Migration (Phase 2) wurde festgestellt, dass mehrere Python-Klassen im Gateway **denselben Namen** tragen, obwohl sie in verschiedenen Modulen leben. Das ist problematisch, weil:
|
||||
|
||||
1. **i18n-Kollision:** `@i18nModel` registriert nach `cls.__name__` in einem globalen Dict — bei gleichem Namen überschreibt der letzte Import den ersten.
|
||||
2. **Lesbarkeit:** Import-Aliase (`from ... import TaskResult as WorkflowTaskResult`) sind fragil und leicht vergessen.
|
||||
3. **Tooling:** IDE-Suche, Debugging-Stacktraces und `getModelClasses()` liefern mehrdeutige Treffer.
|
||||
|
||||
**Business-Treiber:** Saubere Klassennamen verhindern stille Label-Fehler in der UI und reduzieren Wartungsaufwand bei zukünftigen Erweiterungen.
|
||||
|
||||
---
|
||||
|
||||
## Vollständige Liste der Duplikate
|
||||
|
||||
Ermittelt per AST-Scan über `gateway/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen):
|
||||
|
||||
### Kritisch: Pydantic-Modelle mit `@i18nModel` (i18n-Dict-Kollision)
|
||||
|
||||
| Klassenname | Datei 1 | Datei 2 | Beschreibung |
|
||||
|-------------|---------|---------|--------------|
|
||||
| **`TaskResult`** | `datamodels/datamodelChat.py` | `datamodels/datamodelWorkflow.py` | Chat: Aufgabenergebnis mit Status/Feedback. Workflow: Minimales Ergebnis mit `actionResult`. Beide haben `@i18nModel("Aufgaben-Ergebnis")`. |
|
||||
| **`RequestContext`** | `datamodels/datamodelWorkflow.py` (Pydantic `BaseModel`) | `auth/authentication.py` (plain `class`) | Workflow: Normalisierter Benutzer-Input. Auth: Request-Kontext mit User/Mandate/Rollen. Kein i18n-Konflikt (Auth-Klasse ist kein Pydantic-Modell), aber Name ist irreführend. |
|
||||
|
||||
### Mittel: Lokale Hilfsklassen (kein i18n, aber verwirrend)
|
||||
|
||||
| Klassenname | Datei 1 | Datei 2 | Beschreibung |
|
||||
|-------------|---------|---------|--------------|
|
||||
| **`AiResponse`** | `datamodels/datamodelWorkflow.py` (Pydantic) | `serviceAi/subStructureFilling.py` (inline `class` in try/except, 4×) | Workflow: Vollständiges AI-Antwort-Modell. StructureFiller: Minimaler Wrapper `AiResponse(content)` als Fallback bei Parse-Fehlern. |
|
||||
| **`TableData`** | `datamodels/datamodelDocument.py` (Pydantic) | `neutralization/.../subProcessList.py` (`@dataclass`) | Document: Strukturierte Tabelle mit Headers/Rows/Caption. Neutralization: Einfache Tabelle mit `source_type`. |
|
||||
| **`Token`** | `datamodels/datamodelSecurity.py` (Pydantic `PowerOnModel`) | `shared/jsonContinuation.py` (`@dataclass`) | Security: DB-Token (JWT, Refresh etc.). JsonContinuation: JSON-Parser-Token (internes Parsing). |
|
||||
|
||||
### Niedrig: Architektur-Helfer (domänengetrennt, kaum Verwechslungsgefahr)
|
||||
|
||||
| Klassenname | Dateien | Beschreibung |
|
||||
|-------------|---------|--------------|
|
||||
| `ChatObjects` | `features/chatbot/interfaceFeatureChatbot.py`, `interfaces/interfaceDbChat.py` | Identische Rolle (Chat-Objekt-Container), ggf. zusammenführbar. |
|
||||
| `ConnectionHelper` | `workflows/methods/methodOutlook/helpers/connection.py`, `workflows/methods/methodSharepoint/helpers/connection.py` | Jeweils Outlook- bzw. SharePoint-spezifisch; Name ist generisch, aber Module sind klar getrennt. |
|
||||
| `DocumentParsingHelper` | `workflows/methods/methodJira/helpers/documentParsing.py`, `workflows/methods/methodSharepoint/helpers/documentParsing.py` | Jira- bzw. SharePoint-spezifisch; gleiche Situation wie `ConnectionHelper`. |
|
||||
| `StructureGenerator` | `serviceAi/subStructureGeneration.py`, `serviceGeneration/subStructureGenerator.py` | Zwei Services mit ähnlicher Aufgabe; ggf. Konsolidierung prüfen. |
|
||||
| `_ResolverDbAdapter` | `features/graphicalEditor/routeFeatureGraphicalEditor.py`, `features/workspace/routeFeatureWorkspace.py` | Interner Adapter (`_`-Prefix); lebt nur im jeweiligen Route-Modul. |
|
||||
| `_ServicesAdapter` | 4× in `serviceCenter/services/*/main*.py` | Interner Adapter pro Service; bewusst gleichnamig, nie cross-importiert. |
|
||||
|
||||
---
|
||||
|
||||
## Lösungsvorschlag
|
||||
|
||||
### 1. `TaskResult` → Umbenennung (Priorität: hoch)
|
||||
|
||||
**Problem:** Beide Klassen haben `@i18nModel("Aufgaben-Ergebnis")` — der letzte Import gewinnt im Label-Dict.
|
||||
|
||||
**Lösung:**
|
||||
|
||||
| Aktuell | Neu | Modul |
|
||||
|---------|-----|-------|
|
||||
| `TaskResult` in `datamodelChat.py` | **`ChatTaskResult`** | Chat-Domäne: Status, Feedback, Error |
|
||||
| `TaskResult` in `datamodelWorkflow.py` | **`WorkflowTaskResult`** | Workflow-Domäne: taskId + actionResult |
|
||||
|
||||
**Betroffene Imports (5 Dateien):**
|
||||
|
||||
- `workflows/processing/modes/modeBase.py` — importiert aus `datamodelChat`
|
||||
- `workflows/processing/modes/modeDynamic.py` — importiert aus `datamodelChat`
|
||||
- `workflows/processing/modes/modeAutomation.py` — importiert aus `datamodelChat` + `datamodelWorkflow` (bereits `as WorkflowTaskResult`)
|
||||
- `workflows/workflowManager.py` — importiert aus `datamodelWorkflow` (bereits `as WorkflowTaskResult`)
|
||||
- `workflows/processing/workflowProcessor.py` — importiert aus `datamodelWorkflow`
|
||||
- `tests/unit/datamodels/test_workflow_models.py` — importiert aus `datamodelWorkflow`
|
||||
|
||||
**i18n-Labels anpassen:**
|
||||
|
||||
- `ChatTaskResult`: `@i18nModel("Chat-Aufgabenergebnis")`
|
||||
- `WorkflowTaskResult`: `@i18nModel("Workflow-Aufgabenergebnis")`
|
||||
|
||||
**Aufwand:** Klein (6 Dateien, reine Umbenennung + Import-Anpassung).
|
||||
|
||||
### 2. `AiResponse` in `subStructureFilling.py` → Inline-Klasse eliminieren (Priorität: mittel)
|
||||
|
||||
**Problem:** 4× identische `class AiResponse` inline in try/except-Blöcken als Fallback-Wrapper.
|
||||
|
||||
**Lösung:** Eine private Klasse `_AiResponseFallback` am Modulanfang definieren, die 4 Inline-Definitionen ersetzen.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class _AiResponseFallback:
|
||||
content: Any
|
||||
```
|
||||
|
||||
**Aufwand:** Klein (1 Datei, 4 Stellen).
|
||||
|
||||
### 3. `TableData` in `subProcessList.py` → Umbenennen (Priorität: mittel)
|
||||
|
||||
**Lösung:** `TableData` in `subProcessList.py` → **`NeutralizationTableData`** (oder `_ParsedTableData`). Wird nur modulintern verwendet.
|
||||
|
||||
**Aufwand:** Minimal (1 Datei).
|
||||
|
||||
### 4. `Token` in `jsonContinuation.py` → Umbenennen (Priorität: niedrig)
|
||||
|
||||
**Lösung:** `Token` → **`JsonToken`** (passend zu `TokenType` → `JsonTokenType`). Wird nur modulintern verwendet.
|
||||
|
||||
**Aufwand:** Minimal (1 Datei, rein intern).
|
||||
|
||||
### 5. `RequestContext` — Kein Handlungsbedarf
|
||||
|
||||
Die Auth-`RequestContext` ist kein Pydantic-Modell und hat kein `@i18nModel`. Die Workflow-`RequestContext` ist ein Pydantic-Modell mit `@i18nModel`. Es gibt **keine Import-Überschneidung** (Auth wird nie aus `datamodelWorkflow` importiert und umgekehrt). Kein Refactoring nötig.
|
||||
|
||||
### 6. Niedrige Kategorie — Kein Handlungsbedarf
|
||||
|
||||
`ChatObjects`, `ConnectionHelper`, `DocumentParsingHelper`, `StructureGenerator`, `_ResolverDbAdapter`, `_ServicesAdapter` leben in klar getrennten Domänen und werden nie cross-importiert. Umbenennung wäre kosmetisch.
|
||||
|
||||
---
|
||||
|
||||
## Umsetzungsreihenfolge
|
||||
|
||||
| Schritt | Was | Dateien | Aufwand |
|
||||
|---------|-----|---------|---------|
|
||||
| 1 | `TaskResult` → `ChatTaskResult` / `WorkflowTaskResult` | 8 | 30 min |
|
||||
| 2 | Inline `AiResponse` → `_AiResponseFallback` | 1 | 10 min |
|
||||
| 3 | `TableData` → `NeutralizationTableData` | 1 | 5 min |
|
||||
| 4 | `Token` → `JsonToken` | 1 | 5 min |
|
||||
|
||||
**Gesamtaufwand:** ~50 min, kein Risiko für Laufzeitverhalten (reine Umbenennungen).
|
||||
|
||||
---
|
||||
|
||||
## Validierung
|
||||
|
||||
- `python -c "import app"` muss fehlerfrei durchlaufen
|
||||
- Bestehende Tests (`tests/unit/datamodels/test_workflow_models.py`) anpassen und grün halten
|
||||
- `getModelAttributeDefinitions` für betroffene Modelle prüfen (Labels eindeutig)
|
||||
210
c-work/3-validate/2026-04-gateway-i18n-phase-7-implementation.md
Normal file
210
c-work/3-validate/2026-04-gateway-i18n-phase-7-implementation.md
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
<!-- status: done -->
|
||||
<!-- lastReviewed: 2026-04-10 -->
|
||||
|
||||
# Gateway i18n — Phase 7: Konkreter Umsetzungsplan
|
||||
|
||||
Dieses Dokument ist der **ausfuehrbare Umsetzungsplan** fuer die in
|
||||
`c-work/2-build/2026-04 gateway-i18n-unified.md` beschriebene **Phase 7** (RBAC-/Katalog-Labels,
|
||||
Quick Actions, optional Phase 7b TextMultilingual-KI-Button). Es ergaenzt das Konzeptdokument um
|
||||
Reihenfolge, Abhaengigkeiten, Dateien und Abnahmekriterien.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ziele
|
||||
|
||||
| ID | Ziel | Messbar |
|
||||
|----|------|---------|
|
||||
| G1 | Alle **RBAC-relevanten** statischen Texte (DATA/RESOURCE-Katalog, optional Template-Rollenbeschreibung **de**) erscheinen im **xx-Basisset** und sind fuer **AI-Sync** / Admin-Sprachen abbildbar | Keys in `UiLanguageSet(xx).entries` mit `context` `rbac.*` |
|
||||
| G2 | **Kein Bruch** von `TextMultilingual` in der DB (`Role.description` etc.); FormGenerator bleibt **multilingual**-kompatibel | Bestehende Formulare unveraendert nutzbar |
|
||||
| G3 | **Quick Actions:** Uebersetzungen konsistent mit dem gewaehlten Ansatz (siehe Arbeitspaket C) | Sichtbar korrekte Sprache nach Wechsel |
|
||||
| G4 | **Phase 7b:** Ein-Klick-Uebersetzung fuer **TextMultilingual**-Felder im Formular (optional eigenes Release) | Button fuellt Zielsprachen; Fehler/Loading klar |
|
||||
|
||||
---
|
||||
|
||||
## 2. Nicht-Ziele (Scope-Ausschluss)
|
||||
|
||||
- **Kein** Ersatz von `TextMultilingual` durch reine String-Keys in `datamodelRbac.Role` ohne Migrationskonzept.
|
||||
- **Kein** vollstaendiges Umbauen aller Admin-UI-Tabellen auf `t()` fuer Katalog-Labels in einem Schritt (kann folgen, wenn G1 live ist).
|
||||
- **Keine** Aenderung der **Bedeutung** von AccessRules oder RBAC-Resolution — nur Label-/i18n-Schicht.
|
||||
|
||||
---
|
||||
|
||||
## 3. Abhaengigkeiten zwischen Arbeitspaketen
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[WP-A: _registerRbacLabels] --> B[WP-B: Admin-Zaehler / Doku]
|
||||
A --> C[WP-C: Quick Actions]
|
||||
D[WP-D: Phase 7b API] --> E[WP-E: FormGenerator Button]
|
||||
A -.-> D
|
||||
```
|
||||
|
||||
- **WP-A** ist **Grundlage** fuer xx-Set und AI-Workflows zu Katalog-Texten.
|
||||
- **WP-C** (Quick Actions) kann **parallel** zu B starten, baut aber auf **gleicher** i18n-Policy auf; empfohlen: A zuerst merge-faehig.
|
||||
- **WP-D/E** (Phase 7b) sind **unabhaengig** von A fuer die reine API, aber **sinnvoll** nach A, damit `_translateBatch`-Nutzung und Billing einheitlich dokumentiert sind.
|
||||
|
||||
---
|
||||
|
||||
## 4. Arbeitspaket A — `_registerRbacLabels()` und Boot-Sync
|
||||
|
||||
### A.1 Inhalt
|
||||
|
||||
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).
|
||||
- Pro Eintrag: `label` ist **Dict** → `key = label.get("de") or label.get("en")` (nicht-leer); `context`:
|
||||
- `rbac.data` fuer DATA_OBJECTS
|
||||
- `rbac.resource` fuer RESOURCE_OBJECTS
|
||||
- Optional **System-`mainSystem`**: `DATA_OBJECTS` / `RESOURCE_OBJECTS` aus `modules/system/mainSystem.py` falls vorhanden.
|
||||
2. **`TEMPLATE_ROLES[].description`:** nur **`de`**-Text als Key registrieren, `context` `rbac.role` (ein Key pro Rolle reicht fuer Admin-Uebersicht; Duplikat-Texte teilen sich dieselbe Key-Zeile — akzeptabel).
|
||||
3. `_syncRegistryToDb()` um Aufruf **`_registerRbacLabels()`** nach `_registerFeatureUiLabels()` erweitern (Reihenfolge dokumentieren).
|
||||
4. **Merge-Logik** (`routeI18n.py` / `xx`-Sync): sicherstellen, dass `context` `rbac.*` wie andere **Gateway**-Kontexte behandelt werden (nicht `ui` ueberschreiben).
|
||||
|
||||
### A.2 Dateien (voraussichtlich)
|
||||
|
||||
| Datei | Aenderung |
|
||||
|-------|-----------|
|
||||
| `gateway/modules/shared/i18nRegistry.py` | `_registerRbacLabels`, Aufruf in `_syncRegistryToDb` |
|
||||
| `gateway/modules/system/mainSystem.py` | Nur falls DATA/RESOURCE dort noch nicht importiert werden — Scan |
|
||||
| `gateway/modules/routes/routeI18n.py` | Nur falls Sync-Logik `rbac.*` explizit filtern muss — pruefen |
|
||||
|
||||
### A.3 Abnahme
|
||||
|
||||
- [x] Nach Gateway-Start: xx-Set enthaelt neue Eintraege mit `context` `rbac.data` / `rbac.resource` / `rbac.role` / `rbac.quickaction` (118 Keys).
|
||||
- [x] Keine Regression: bestehende `ui`- und `api.*`-Keys unveraendert zaehlbar.
|
||||
- [x] Log-Zeile: `i18n rbac labels: 118 new keys (rbac.* context)`.
|
||||
|
||||
### A.4 Aufwand
|
||||
|
||||
- **Klein** (ca. 0.5–1 Tag), wenn Modulliste und Dict-Extraktion zentral und getestet sind.
|
||||
|
||||
---
|
||||
|
||||
## 5. Arbeitspaket B — Admin-Sprachen-UI und Doku
|
||||
|
||||
### B.1 Inhalt
|
||||
|
||||
1. **AdminLanguagesPage** (optional): Spalte oder Filter **„Kontext“** — `rbac.*` sichtbar (falls noch nicht generisch).
|
||||
2. **Wiki:** `gateway-i18n-unified.md` — Verweis auf dieses Umsetzungsplan-Dokument; Status Phase 7 **in Arbeit** → **done** nach Merge.
|
||||
3. **coding-conventions.md** (kurz): Regel „neue DATA/RESOURCE-Labels: `de`-Text als Basis-Key; `en`/`fr` im Dict fuer Legacy-Anzeige bis Migration“.
|
||||
|
||||
### B.2 Abnahme
|
||||
|
||||
- [x] Dokumentation ist verlinkt.
|
||||
- [x] Kein Muss fuer UI-Spalte, wenn Tabelle bereits nach `context` filterbar ist.
|
||||
|
||||
---
|
||||
|
||||
## 6. Arbeitspaket C — Quick Actions (Entscheidung + Umsetzung)
|
||||
|
||||
### C.0 Entscheidung (vor Codieren)
|
||||
|
||||
| Option | Beschreibung | Aufwand |
|
||||
|--------|--------------|---------|
|
||||
| **C1** | **Backend:** `de`-String aus Dict als Basis; Aufloesung in `getQuickActions` via **`t()`** / Cache (Request-Sprache) statt nur `language`-Dict-Lookup | Mittel |
|
||||
| **C2** | **Backend** liefert nur **deutsche Keys**; **Frontend** `QuickActionBoard` nutzt `t(action.label)` / `t(action.description)` (wie Navigation) | Mittel |
|
||||
| **C3** | **Status quo** belassen; nur **WP-A** registriert Keys — Admin kann Sprachen pflegen, **API** bleibt dict-basiert bis spaeter | Gering |
|
||||
|
||||
**Empfehlung:** Zuerst **C3** mit A; **C1 oder C2** in einem **separaten** PR nach Product-Entscheidung.
|
||||
|
||||
### C.1 Schritte fuer C1 (falls gewaehlt)
|
||||
|
||||
1. `mainTrustee.py` (und ggf. andere Features): `QUICK_ACTIONS` / Kategorien auf **deutsche Basis-Strings** umstellen (analog UI_OBJECTS) **oder** Dict beibehalten und **zusaetzlich** `key`/`labelKey` einfuehren.
|
||||
2. `routeFeatureTrustee.getQuickActions`: `_resolveText` ersetzen/ergaenzen durch **`t()`** aus `i18nRegistry` mit Request-Sprache.
|
||||
3. Keys in `xx`/`_REGISTRY` via WP-A oder dedizierte Registrierung.
|
||||
|
||||
### C.2 Abnahme
|
||||
|
||||
- [x] Quick-Action-Labels und -Descriptions als `rbac.quickaction` Keys registriert (C3-Ansatz).
|
||||
- [x] Keine doppelten Keys ohne `context`-Trennung (Composite-Key-Modell beachten).
|
||||
|
||||
---
|
||||
|
||||
## 7. Arbeitspaket D — Phase 7b: API `translate-field`
|
||||
|
||||
### D.1 Inhalt
|
||||
|
||||
1. Neuer Endpoint in `gateway/modules/routes/routeI18n.py`, z. B.:
|
||||
- `POST /api/i18n/translate-field`
|
||||
- Body: `{ "sourceText": string, "sourceLang": string, "targetLangs": string[] }`
|
||||
- Response: `{ "translations": { "de": "...", "fr": "..." } }` (ohne Source-Lang)
|
||||
2. Intern: Wiederverwendung von **`_translateBatch`** mit einem kuenstlichen Key-Set (oder schlanker Helper), inkl. **`_matchCapitalization`**.
|
||||
3. **Auth:** `Depends(getRequestContext)`; **Billing:** gleicher Callback wie bei `translate` Jobs.
|
||||
4. **Rate-Limit** und **Payload-Groesse** (max. Zeichen) begrenzen.
|
||||
|
||||
### D.2 Abnahme
|
||||
|
||||
- [x] Nur authentifizierte Nutzer (`Depends(getCurrentUser)`).
|
||||
- [x] Leerer `sourceText` → 422 (Pydantic `min_length=1`).
|
||||
- [ ] Integrationstest oder manueller Test mit zwei Zielsprachen.
|
||||
|
||||
### D.3 Aufwand
|
||||
|
||||
- **Klein bis mittel** (ca. 1 Tag inkl. Tests).
|
||||
|
||||
---
|
||||
|
||||
## 8. Arbeitspaket E — Phase 7b: FormGenerator Button
|
||||
|
||||
### E.1 Inhalt
|
||||
|
||||
1. `FormGeneratorForm.tsx` — `renderMultilingualField`:
|
||||
- Button **„In alle Sprachen uebersetzen“** (Text via `t()`).
|
||||
- **Quellsprache:** implementierte Regel festhalten (z. B. erste nicht-leere Sprache in `multilingualLangs`-Reihenfolge, sonst `en`).
|
||||
- **Ziel:** alle anderen Codes aus `multilingualLangs` ohne Quelle.
|
||||
2. `onClick`: `POST /api/i18n/translate-field`, dann `handleMultilingualChange` pro Ziel.
|
||||
3. **UX:** Loading-Spinner, `disabled` waehrend Request, **Toast** bei Fehler.
|
||||
4. Optional: Tooltip **Hinweis KI-Qualitaet**.
|
||||
|
||||
### E.2 Abnahme
|
||||
|
||||
- [x] Role-Formular (multilingual description): Button implementiert.
|
||||
- [x] Readonly-Modus: kein Button (nur in Edit-/Create-Modus sichtbar).
|
||||
|
||||
### E.3 Aufwand
|
||||
|
||||
- **Mittel** (ca. 1–1.5 Tage inkl. Styling und Edge Cases).
|
||||
|
||||
---
|
||||
|
||||
## 9. Testplan (Phase 7 gesamt)
|
||||
|
||||
| Nr | Szenario | Erwartung |
|
||||
|----|----------|-----------|
|
||||
| T1 | Boot mit WP-A | xx-Set enthaelt `rbac.*` Eintraege |
|
||||
| T2 | Admin: AI-Uebersetzung fuer ein `rbac.data`-Key | Wert in Zielsprache gesetzt |
|
||||
| T3 | Quick Actions (nach C1/C2) | Texte passen zur UI-Sprache |
|
||||
| T4 | Phase 7b: Button + leerer Source | Validation / keine KI-Call |
|
||||
| T5 | Phase 7b: langer Text | Limit oder Chunking klar |
|
||||
|
||||
---
|
||||
|
||||
## 10. Risiken und Rollback
|
||||
|
||||
| Risiko | Massnahme |
|
||||
|--------|-----------|
|
||||
| Zu viele Keys in xx (Duplikate) | Composite-Key `(key, context)` bleibt Massstab; Dokumentation |
|
||||
| KI-Kosten Phase 7b | Limits, Feature-Flag optional |
|
||||
| Regression Boot-Sync | Feature-Flag `_registerRbacLabels` optional abschaltbar |
|
||||
|
||||
Rollback: WP-A durch Entfernen des Aufrufs `_registerRbacLabels()` deaktivieren; keine DB-Schema-Aenderung fuer A.
|
||||
|
||||
---
|
||||
|
||||
## 11. Reihenfolge-Empfehlung (Sprints)
|
||||
|
||||
| Sprint | Inhalt | Deliverable |
|
||||
|--------|--------|---------------|
|
||||
| **S1** | WP-A + B (minimal) | Rbac-Keys im xx-Set, Doku-Link |
|
||||
| **S2** | WP-C (nach Entscheidung C1/C2/C3) | Quick Actions Policy |
|
||||
| **S3** | WP-D + E | Phase 7b fertig |
|
||||
|
||||
---
|
||||
|
||||
## 12. Links
|
||||
|
||||
- Konzept & Phase-7-Text: `c-work/2-build/2026-04 gateway-i18n-unified.md`
|
||||
- i18n Registry: `gateway/modules/shared/i18nRegistry.py`
|
||||
- i18n API: `gateway/modules/routes/routeI18n.py`
|
||||
- Formular: `frontend_nyla/src/components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx`
|
||||
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- status: draft -->
|
||||
<!-- lastReviewed: 2026-04-07 -->
|
||||
<!-- status: done -->
|
||||
<!-- lastReviewed: 2026-04-10 -->
|
||||
|
||||
# Typed Node Handover System — Spezifikation & Execution Plan
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
doku nachgeführt werden an <!-- status: canonical -->
|
||||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-05 -->
|
||||
|
||||
# Coding-Konventionen
|
||||
|
|
@ -48,6 +48,73 @@ t('Offen (Status)') // vs. t('Offen (Zustand)')
|
|||
- Fehler propagieren -- Exceptions explizit werfen, nicht schlucken
|
||||
- Config ueber `APP_CONFIG` (aus `modules/shared/configuration.py`)
|
||||
|
||||
### i18n-Pflicht: `t()` fuer alle UI-sichtbaren Gateway-Texte
|
||||
|
||||
Jeder Text der im Frontend angezeigt wird (HTTPException-Details, API-Response-Messages, Erfolgs-/Fehlermeldungen) **muss** mit `t()` getaggt werden.
|
||||
|
||||
```python
|
||||
from modules.shared.i18nRegistry import t
|
||||
|
||||
# Fehlermeldung (context automatisch = "api")
|
||||
raise HTTPException(status_code=403, detail=t("Zugriff verweigert", "api.routeSecurity",
|
||||
"Fehlermeldung bei fehlendem Zugriff"))
|
||||
|
||||
# Erfolgsmeldung
|
||||
return {"message": t("Datei erfolgreich hochgeladen", "api.routeFiles",
|
||||
"Bestaetigung nach Datei-Upload")}
|
||||
```
|
||||
|
||||
**Nicht** mit `t()` taggen: Log-Eintraege, AI-Prompts, interne technische Fehlermeldungen.
|
||||
|
||||
Fuer Route-Module gibt es den Shorthand `apiRouteContext`:
|
||||
|
||||
```python
|
||||
from modules.shared.i18nRegistry import apiRouteContext
|
||||
routeApiMsg = apiRouteContext("routeBilling")
|
||||
|
||||
raise HTTPException(status_code=403, detail=routeApiMsg("Zugriff verweigert"))
|
||||
```
|
||||
|
||||
### Pydantic-Models: `@i18nModel` Decorator Pflicht
|
||||
|
||||
Jedes Pydantic-Model das im UI angezeigt wird (Tabellen, Formulare) **muss** den `@i18nModel` Decorator haben. Feld-Labels werden in `json_schema_extra["label"]` definiert.
|
||||
|
||||
```python
|
||||
from modules.shared.i18nRegistry import i18nModel
|
||||
|
||||
@i18nModel("Benutzer")
|
||||
class User(PowerOnModel):
|
||||
name: str = Field(
|
||||
description="Full name of the user",
|
||||
json_schema_extra={"label": "Name", "frontend_type": "text"}
|
||||
)
|
||||
email: str = Field(
|
||||
description="Email address for login and notifications",
|
||||
json_schema_extra={"label": "E-Mail-Adresse", "frontend_type": "text"}
|
||||
)
|
||||
```
|
||||
|
||||
- `@i18nModel("Deutscher Modelname")` -- AI-Kontext kommt automatisch aus dem Class-Docstring
|
||||
- `json_schema_extra={"label": "Deutscher Feldname"}` -- Pflicht fuer jedes UI-sichtbare Feld
|
||||
- `Field(description=...)` -- wird als AI-Kontext fuer die Uebersetzung verwendet
|
||||
- **Kein** `registerModelLabels()` mehr verwenden (entfernt)
|
||||
|
||||
### Feature-Module: Labels als deutsche Basis-Strings
|
||||
|
||||
Neue `DATA_OBJECTS`, `RESOURCE_OBJECTS` und `UI_OBJECTS` Labels verwenden **deutsche Klartext-Strings** als Basis-Key. Bestehende `{en, de, fr}`-Dicts werden beim Boot automatisch ueber `_registerRbacLabels()` registriert (Kontext `rbac.data`, `rbac.resource`, `rbac.role`, `rbac.quickaction`). Fuer **neue** Eintraege: `de`-Text als Basis-Key verwenden, `en`/`fr` im Dict fuer Legacy-Anzeige bis vollstaendige Migration.
|
||||
|
||||
```python
|
||||
DATA_OBJECTS = [
|
||||
{
|
||||
"objectKey": "data.uam.UserInDB",
|
||||
"label": {"en": "User", "de": "Benutzer", "fr": "Utilisateur"},
|
||||
"meta": {"table": "UserInDB", "namespace": "uam"}
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Die `de`-Texte erscheinen automatisch im xx-Basisset und koennen per AI uebersetzt werden.
|
||||
|
||||
## Projektstruktur Gateway
|
||||
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue