# Frontend Nyla -- Architektur ## Überblick Frontend Nyla ist eine React-Single-Page-Application (SPA) mit TypeScript und Vite. Routing über React Router; Schichten: Presentation (Pages, Components), Business Logic (Hooks, `*Logic`-Module), Data Access (`api.ts`, Feature-API-Module), Infrastructure (Contexts, Provider, Konfiguration). **PageManager** lädt Seiten dynamisch (Lazy Loading, State Preservation, Lifecycle-Hooks). Authentifizierung über Azure MSAL; HTTP über Axios mit Interceptors. Technologie-Stack (Stand UI-Doku): React 19.x, Vite 5.x, TypeScript 5.8.x, React Router DOM 7.x, Axios, `@azure/msal-browser` / `@azure/msal-react`, Framer Motion, XState, CSS Modules, React Icons. ## Ordnerstruktur (src/) | Ordner | Inhalt | |--------|--------| | `pages/` | Seiten: `admin/`, `basedata/`, `billing/`, `settings/`, `views/` (workspace, commcoach, chatbot, trustee, graphicalEditor, realestate, neutralization, teamsbot) | | `components/` | Wiederverwendbar: FormGenerator (Table, Form, Tree, List, Report), Navigation, UnifiedDataBar, FlowEditor (Graphical Editor), OnboardingAssistant | | `hooks/` | useApiRequest (useApi.ts), useFiles, useNavigation, useConfirm, usePrompt, useResizablePanels, `useSpeechAudioCapture` (`useVoiceStream`: Mic + WebSocket `/voice-google/stt/stream`, optionale STT-`open`-Parameter), etc. | | `contexts/` | FileContext, PekContext, ToastContext, WorkflowSelectionContext | | `api/` | API-Client (`api.ts`) und Feature-spezifische API-Module | | `core/` | PageManager | | `layouts/` | Layout-Komponenten | | `locales/` | i18n: API-basiertes Language-Loading (`index.ts`, `types.ts`), keine statischen Locale-Files | | `types/` | TypeScript-Typen | | `utils/` | Utility-Funktionen | Ergänzend typische Root-Dateien und Bereiche im Repo: `main.tsx`, `App.tsx`, `api.ts` (Root), `auth/` (MSAL, ProtectedRoute), `assets/` — Feature-Module unter `components/` oft nach Muster: Haupt-`.tsx`, `*.module.css`, `*Logic.tsx`, `*Types.ts`, optional `index.ts`. ## Wichtige UI-Komponenten | Komponente | Zweck | |------------|-------| | `UnifiedDataBar (UDB)` | Multi-Tab-Panel: Chats, Files, Sources — wird in Workspace, CommCoach und Graphical Editor genutzt. Sources-Tab hat 4. Action-Button: RAG-Index-Toggle pro DataSource (Consent-gesteuert via `PATCH /api/rag/inventory/{dsId}/index-toggle`) | | `FormGenerator` | Dynamische Formulare/Tabellen aus Backend-Attribut-Definitionen (siehe [formgenerator.md](formgenerator.md)) | | `FormGeneratorTree` | Generische Baumkomponente mit Provider-Pattern (`TreeNodeProvider`), Multiselect, DnD, Inline-Editing, Scope/Neutralize, Batch-Actions; ersetzt fruehere `FolderTree`-Komponente (siehe [formgenerator.md](formgenerator.md)) | | `MandateNavigation` | Feature-Baum-Navigation mit Mandanten-Kontext | | `Automation2FlowEditor` | Konsolidierter n8n-style Flow-Builder (Graphical Editor) mit 3-Column-Layout: [UDB + Chat/Tracing] [Canvas + Header] [Nodes] | | `FlowCanvas` | Custom React Canvas fuer Workflow-Graph-Rendering mit Node-Highlighting (SSE Live-Tracing) | | `RunTracingPanel` | Live-Tracing von Workflow-Runs via SSE mit Fallback-Polling | | `EditorChatPanel` | AI Chat im Editor mit Drag&Drop-Dateianhang und Source-Picker | | `CanvasHeader` | Workflow-Metadaten, Versioning (Draft/Publish/Archive), Save-as-Template, New-from-Template | | `TemplatePicker` | Modal zur Auswahl von Workflow-Vorlagen beim Erstellen neuer Workflows | | `WorkspacePage` | AI-Workspace mit Chat, UDB, Agent-Streaming | | `RagInventoryPage` | Globale RAG-Inventar-Seite (`/rag-inventory`): pro Connection Card mit Consent-Toggle, Stop-Button, Reindex, DataSource-Uebersicht. Primaerer Ort fuer RAG-Management (keine duplizierte UI auf ConnectionsPage). API: `/api/rag/inventory/*` | | `RagRunningBadge` | Floating-Badge in `MainLayout.tsx`: zeigt laufende RAG-Bootstrap-Jobs, Polling gegen `/api/rag/inventory/jobs`, Click-through zum RAG-Inventar | | `AddConnectionWizard` | Connector-Type-Aware Wizard (Google/MSFT/ClickUp/Infomaniak): dynamische Step-Definition pro Typ, integrierter MSFT Admin-Consent-Step + Infomaniak-PAT-Step. Keine Kostenschaetzung, keine Preferences — nur Anbieter → Consent → Connect | | `TrusteeDataTablesView` | Konsolidierte Daten-Tabellen-Seite (Treuhand): 13 Tabs (Stammdaten, Lokale Daten, Konfiguration, Buchhaltungs-Daten) ueber generischen `TrusteeDataTab`-Wrapper, Lazy-Mount pro Tab, URL-State `?tab=`, read-only fuer Sync-Tabellen | | Teams Bot Views (`pages/views/teamsbot/`) | Dashboard (KPI + SSE), Assistent (Wizard), Module (CRUD + `?moduleId`), Live-Session (SSE + MFA), Settings — API `api/teamsbotApi.ts`; Architektur [teams-bot/architecture.md](../teams-bot/architecture.md) | ## Routing - **Einstieg:** `main.tsx` rendert `App.tsx` mit Providern (z. B. Sprache, Auth) und **React Router** (`Routes` / `Route`). - **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 `` (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). - **Teams Bot:** `pages/views/teamsbot/` — fünf Tabs (Dashboard, Assistent, Module, Live-Session, Einstellungen). Dashboard: `teamsbotApi.createDashboardStream` (SSE). Live-Session: `createSessionStream`. Module-Liste: URL `?moduleId=` klappt ein Modul auf. Detail: [teams-bot/architecture.md](../teams-bot/architecture.md). - **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/geaenderte UI-Text MUSS mit `t('Deutscher Klartext')` getaggt werden. **`t()` darf NUR String-Literale enthalten** — `t(variable)` ist verboten. Werte vom Backend (Labels, Descriptions) sind bereits uebersetzt und werden direkt gerendert. Variable Interpolation: `t('Text {var}', {var: 'Wert'})`. Fallback: Ziel-Set → `de`-Set → `[key]` (eckige Klammern machen fehlende Uebersetzungen sichtbar). Keine statischen Locale-Files. Fuer statische Frontend-Maps (z.B. Wochentage, Monatsnamen, Status-Labels) wird `t()` per `switch`/Funktion mit Literalen aufgerufen, nicht ueber Map-Lookup. - **TextMultilingual:** Felder vom Typ `TextMultilingual` rendern dynamisch Eingabefelder fuer alle verfuegbaren Sprachen (aus `availableLanguages`). `xx` ist das Pflichtfeld (Quelltext). 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 - **Keine Browser-Dialoge** (`alert` / `confirm` / `prompt`) — stattdessen `useConfirm()` und `usePrompt()` Hooks - **i18n-Pflicht:** Jeder UI-Text (Label, Button, Placeholder, Tooltip, Fehlermeldung) MUSS mit `t('Deutscher Klartext')` getaggt werden. Hardcodierte deutsche Strings im JSX sind nicht erlaubt. Import: `const { t } = useLanguage();`. **`t()` darf NUR String-Literale enthalten** — nie Variablen. Backend-Werte (feature.label, role.description etc.) sind bereits uebersetzt und werden direkt gerendert. - Alle internen Funktionen mit `_` Prefix - camelCase für Variablen und Funktionen ## Schlüssel-Dateien | Datei / Bereich | Rolle | |-----------------|--------| | `main.tsx` | Application Entry Point | | `App.tsx` | Root-Komponente, Router-Setup, Provider | | `api.ts` (Root) | Axios-Instanz, Base URL, Token-Interceptor, 401-Handling | | `hooks/useSpeechAudioCapture.ts` | `useVoiceStream`: STT-Streaming; `start(language, sttOpenOptions?)`; CommCoach setzt `model`/`lightweight`/`singleUtterance`, Workspace nutzt Defaults | | `layouts/MainLayout.tsx` | Haupt-Shell mit MandateNavigation + Outlet | | `config/pageRegistry.tsx` | PAGE_REGISTRY, FEATURE_REGISTRY, Lazy Imports | | `core/PageManager/` | State Preservation, Lifecycle, Caching | | `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; `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 | | `components/FlowEditor/editor/TemplatePicker.tsx` | Template-Auswahl-Modal | | `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` | | `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 | ## Tab-Pattern fuer mehrere Modelle pro Seite Wenn eine Feature-Seite N verwandte Modelle in eigenen Tabs zeigen soll (Beispiel: `TrusteeDataTablesView` mit 13 Trustee-Tabellen), gilt folgendes Muster: 1. **Pro Tab ein Wrapper-Component**, das exakt einen Hook aufruft. So bleiben React Hook Rules eingehalten und inaktive Tabs fetchen keine Daten (Lazy-Mount). 2. **`FormGeneratorTable` direkt im Wrapper** (siehe [formgenerator.md](formgenerator.md) -- "Bei Tabs / Wrapper-Komponenten"). Jeder Wrapper reicht die Flex-Chain (`flex:1; min-height:0`) durch, sonst kollabiert die Tabelle auf 0 px. 3. **URL-State via `?tab=`** (`useSearchParams`). Erlaubt Deep-Links aus Notifications, Quick Actions oder Doku. 4. **Read-only-Tabs**: separater Wrapper ohne Operations-Hook, `readOnly={true}`. Sync-Tabellen (z.B. `TrusteeData*`) verzichten auf Edit-/Delete-Buttons, damit der naechste Sync nicht versehentlich ueberschriebene Daten zerstoert. 5. **Tab-Bar** im Stil bestehender Trustee-Tab-Seiten (`TrusteeAbschlussView`, `TrusteeAccountingSettingsView`); Gruppierung per `TabGroupDef` (z.B. "Stammdaten", "Lokale Daten", "Konfiguration", "Buchhaltungs-Daten") erhoeht Lesbarkeit bei vielen Tabs. 6. **Spalten-Definitionen** kommen aus `getModelAttributeDefinitions(...)` (Backend) -- nie hardcodiert. So bleibt das UI automatisch synchron mit Pydantic-Modellaenderungen. ## FlowEditor -- Typed Action Architecture (Phasen 1-5) Seit April 2026 stuetzt sich der FlowEditor (Graphical Editor) auf eine typisierte Action-Architektur. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `frontend_nyla/src/components/FlowEditor/**/*.test.tsx`. ### Picker-Komponenten | Komponente | Datei | Zweck | |------------|-------|-------| | `RequiredAttributePicker` | `nodes/shared/RequiredAttributePicker.tsx` | Auflistung + Auswahl von 0/1/N Pflicht-Attributen (`featureInstanceId`, `connection`, ...). Bei genau einer Quelle: Auto-Bind mit Override-Knopf; bei N: explizite Auswahl; bei 0: Hint "Iterieren-Vorschlag" oder Ressource fehlt. | | `DataPicker` | `nodes/shared/DataPicker.tsx` | Strict-Type-Filter (`expectedParamType`) + Object-Drill-Down + `*`-Wildcard fuer List-Iteration. Default ist Strict-Mode (`Nur kompatible`-Toggle). Hard-Mismatches werden ausgeblendet, Coerce-Faelle (z.B. `int -> str`) bleiben sichtbar. | | `paramValidation.ts` | `nodes/shared/paramValidation.ts` | Single source of truth fuer Pflicht-Feld-Pruefung. Liefert `nodeErrors: List[NodeError]` (genutzt von Save-Toast, Run-Block, Node-Highlighting). | ### Save / Run Gating (AC-9) - **Save** ist immer erlaubt (auch mit Pflicht-Fehlern). `CanvasHeader.tsx` zeigt nach Save bei Fehlern einen amber-Banner ("Gespeichert mit X Pflicht-Fehlern in Y Nodes"). - **Run** wird per `executeBlockedReason` blockiert; der Button wechselt auf "Pflicht-Felder fehlen", behaelt `aria-disabled` und triggert `onExecuteBlockedClick` (markiert die First-Error-Node). - Hintergrund: `executeGraph` validiert serverseitig zusaetzlich (Port-Mismatch, fehlende Pflicht-Bindings) und liefert klare Fehlermeldungen falls jemand den Editor-Block umgeht. ### FeatureInstanceRef im Frontend - `featureInstanceId`-Bindings werden als typisierter Envelope `{$type: "FeatureInstanceRef", id, featureCode}` ans Backend geschickt; das Backend persistiert sie 1:1 (Phase 5). - Der Picker zeigt `[]