202 lines
17 KiB
Markdown
202 lines
17 KiB
Markdown
<!-- status: canonical -->
|
|
<!-- lastReviewed: 2026-04-24 -->
|
|
<!-- verifiedAgainst: gateway (codebase audit 2026-04-07, post Automation Unification) + Typed Action Architecture Phasen 1-5 -->
|
|
|
|
# Gateway -- Architektur
|
|
|
|
## Überblick
|
|
|
|
Das Gateway ist das Python-Backend der PowerOn-Plattform (FastAPI, PostgreSQL). Es kapselt Mandanten- und Feature-Logik hinter einer REST-API und folgt einer klaren Schichtenfolge: **Connectors** sprechen externe Systeme und Datenbanken an, **Interfaces** normalisieren Zugriffe und DTOs, **Services** bündeln fachliche Operationen darauf, und das **ServiceCenter** löst diese Services pro Request mit einheitlichem Kontext auf. Routen in `modules/routes/` sind der HTTP-Einstieg; Security-Middleware und gemeinsame Utilities liegen in `modules/security/` bzw. `modules/shared/`. Feature-spezifische Domänen leben in `modules/features/` als weitgehend autonome Module.
|
|
|
|
## Modulstruktur
|
|
|
|
Unter `gateway/modules/` (Kontext-Audit):
|
|
|
|
| Modul | Zweck |
|
|
|-------|-------|
|
|
| `aicore/` | Model-Registry, Model-Selector, Provider-Plugins (Anthropic, OpenAI, Mistral, Perplexity, Tavily, PrivateLLM) |
|
|
| `auth/` | Authentifizierung, CSRF, Token-Refresh-Middleware, JWT |
|
|
| `connectors/` | DB-Connector (PostgreSQL), Provider-Subpakete (Microsoft, Google, ClickUp, FTP), Ticket/Messaging/Geo-Konnektoren |
|
|
| `datamodels/` | Pydantic-Datenmodelle (u. a. Ai, Billing, Chat, Content, Files, Knowledge, Rbac, Subscription, UiLanguage, Workflow) |
|
|
| `features/` | Feature-Module (autonome Domänen): workspace, graphicalEditor, chatbot, commcoach, neutralization, realEstate, trustee, teamsbot |
|
|
| `interfaces/` | DB-Interfaces (App, Billing, Chat, Knowledge, Management, Subscription), AI-Objects, RBAC, Features, Messaging |
|
|
| `migration/` | Daten-Migrationen |
|
|
| `routes/` | REST-API-Routen (u. a. Admin, Billing, DataFiles, DataSources, i18n, Security, Store, System) |
|
|
| `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, i18nRegistry, Konfiguration, Logging, …) |
|
|
| `system/` | System-Konfiguration, Feature-Discovery (`registry.py`: `loadFeatureMainModules`, `loadFeatureRouters`) |
|
|
| `workflows/` | Workflow-Engine mit Methoden, Aktionen, Execution Engine und konsolidiertem Scheduler |
|
|
|
|
## ServiceCenter (Kern-Orchestrierung)
|
|
|
|
Das ServiceCenter ist die zentrale Schicht, die Kern- und importierbare Services verbindet. Pro Request/Session wird ein **`ServiceCenterContext`** (`serviceCenter/context.py`) mitgeführt und propagiert u. a.:
|
|
|
|
- `user: User` (gesamtes User-Objekt), `mandateId`, `featureInstanceId`
|
|
- `workflow_id`, `workflow`, `feature_code`
|
|
- `requireNeutralization` (optional) — Neutralisierungsflag auf Chat-Ebene
|
|
|
|
Die öffentliche API umfasst u. a. `getService(key, context)` zur Auflösung einer Service-Instanz; registrierte Services sind in `registry.py` als **CORE_SERVICES** und **IMPORTABLE_SERVICES** hinterlegt, mit feature-spezifischer Auflösung und optionaler Vorabladung (`preWarm`).
|
|
|
|
### Services (`serviceCenter/services/`)
|
|
|
|
| Service | Hauptmodul (Auszug) | Zweck |
|
|
|---------|---------------------|-------|
|
|
| `serviceAgent` | `mainServiceAgent.py` | AI-Agent mit vielen Tools (u. a. Dateien, Suche, Container, Web, Mail) |
|
|
| `serviceAi` | `mainServiceAi.py` | AI-Call-Gateway: Neutralisierung, Billing-Preflight, Provider-Auswahl, Streaming, Extraktion, Generierung |
|
|
| `serviceKnowledge` | `mainServiceKnowledge.py` | Knowledge Store: Indexierung, semantische Suche, RAG-Kontext (`buildAgentContext`) |
|
|
| `serviceBilling` | `mainServiceBilling.py` | Billing-Checks, Transaktionen |
|
|
| `serviceChat` | `mainServiceChat.py` | Chat-Persistenz |
|
|
| `serviceExtraction` | `mainServiceExtraction.py` | Dokument-Extraktion (PDF, DOCX, XLSX, …) |
|
|
| `serviceGeneration` | `mainServiceGeneration.py` | Dokument-Generierung |
|
|
| `serviceMessaging` | `mainServiceMessaging.py` | E-Mail, Notifications |
|
|
| `serviceSubscription` | `mainServiceSubscription.py` | Subscription-Verwaltung |
|
|
| `serviceWeb` | `mainServiceWeb.py` | Web-Scraping |
|
|
|
|
**Hinweis (Agent):** Agent-Tools liefern Rohdaten; Neutralisierung vor dem Versand an ein Sprachmodell erfolgt zentral im **serviceAi** (`mainServiceAi.py`), nicht in den Tools selbst.
|
|
|
|
### Einordnung (Framework)
|
|
|
|
Daten- und Steuerfluss: **Client oder Workflow → Service Center → Service → Interface → Connector → externes System**. Das Service Center bündelt dabei Erkennbarkeit (Registry), Konfiguration und querschnittliche Aspekte wie Logging, RBAC-Objekt-Registrierung (`registerServiceObjects`) und konsistente Service-Lebenszyklen; **`serviceHub`** ergänzt dies mit **`PublicService`**, sodass nur bewusst exponierte Methoden nach außen sichtbar sind.
|
|
|
|
## Interfaces (DB-Schicht)
|
|
|
|
Die genannten Module kapseln die Datenbankzugriffe bzw. die zugehörigen Fachverträge (Audit-Liste):
|
|
|
|
| Interface | Verantwortlich für |
|
|
|-----------|-------------------|
|
|
| `interfaceDbApp.py` | User, Mandate, FeatureAccess, UserConnections, Preferences |
|
|
| `interfaceDbBilling.py` | BillingAccount, BillingTransaction, Subscriptions |
|
|
| `interfaceDbChat.py` | ChatWorkflow, ChatMessage, ChatDocument |
|
|
| `interfaceDbKnowledge.py` | FileContentIndex, ContentChunk, RoundMemory (RAG/Knowledge Store) |
|
|
| `interfaceDbManagement.py` | FileItem, Folder, Prompt, DataSource (mandantenweite Stammdaten), UiLanguageSet-Seeding |
|
|
| `interfaceDbSubscription.py` | Subscription-Verwaltung |
|
|
| `interfaceAiObjects.py` | AI-Call-Abstraktion (Text, Embedding, Vision, Streaming) |
|
|
| `interfaceFeatures.py` | Feature-Instanz-Lifecycle, Template-Rollen-Kopie |
|
|
| `interfaceRbac.py` | RBAC-Regelauswertung |
|
|
|
|
Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap) erfüllen dieselbe Normalisierungsrolle gegenüber Connectors bzw. externen APIs; die Tabelle oben entspricht der expliziten DB-/Kern-Zuordnung aus dem Kontext-Audit.
|
|
|
|
## Schlüssel-Dateien
|
|
|
|
| Datei / Pfad | Rolle |
|
|
|--------------|-------|
|
|
| `gateway/app.py` | FastAPI-Anwendung (generischer Entry-Point), Routen, Middleware, EventManager, Scheduler-MainLoop |
|
|
| `gateway/modules/serviceCenter/__init__.py` | Service Center: `getService`, `preWarm`, RBAC-Registrierung für Service-Objekte |
|
|
| `gateway/modules/serviceCenter/context.py` | `ServiceCenterContext` pro Request |
|
|
| `gateway/modules/serviceCenter/registry.py` | Service-Registry (CORE / IMPORTABLE) |
|
|
| `gateway/modules/serviceCenter/resolver.py` | Auflösung von Service-Instanzen inkl. Cache |
|
|
| `gateway/modules/serviceHub/__init__.py` | Hub / DI, `PublicService`-Wrapper für kontrollierte Oberflächen |
|
|
| `gateway/modules/routes/*.py` | HTTP-Endpunkte, Aufruf in Richtung Service Center / Features (inkl. `routeI18n.py` für DB-backed i18n mit AI-Übersetzung) |
|
|
| `gateway/modules/interfaces/*.py` | Stabile Verträge und DB-Zugriffe (keine direkte Vendor-Logik in Services) |
|
|
| `gateway/modules/connectors/*.py` | Vendor-spezifische Adapter (Auth, Transport, Mapping) |
|
|
| `gateway/modules/security/*` | RBAC-Auswertung, RBAC-Katalog, Root-Access |
|
|
| `gateway/modules/auth/*` | CSRF, Token-Refresh-Middleware, JWT, OAuth |
|
|
| `gateway/modules/shared/*` | Querschnitt: Konfiguration, Audit-Logging, Events, Utilities |
|
|
| `gateway/modules/system/registry.py` | Feature-Discovery, Router-Laden, Katalog-Registrierung beim App-Start |
|
|
| `gateway/modules/workflows/workflowManager.py` | Zentrale Workflow-Steuerung (Workspace/Chat Workflows) |
|
|
| `gateway/modules/workflows/automation2/executionEngine.py` | Graph-Execution-Engine: topoSort, Transit-Routing, `_normalizeToSchema` nach Execute, `flow.merge`-Wait, Resume-Schema-Validierung |
|
|
| `gateway/modules/workflows/scheduler/mainScheduler.py` | Konsolidierter Workflow-Scheduler |
|
|
| `gateway/modules/interfaces/interfaceBootstrap.py` | System-Bootstrap (Templates, Billing, Stripe) |
|
|
|
|
## i18n (Mehrsprachigkeit)
|
|
|
|
Das Gateway nutzt ein DB-basiertes Sprachsystem (`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()`, `resolveText()`, `@i18nModel` Decorator, `_REGISTRY`, `_CACHE`, `_setLanguage`, Boot-Sync |
|
|
| `attributeUtils.py` | `modules/shared/` | `getModelLabels()` / `getModelLabel()` lesen aus `i18nRegistry.MODEL_LABELS`, nutzen `resolveText()` |
|
|
| `routeI18n.py` | `modules/routes/` | Admin-API: Sprachset-CRUD, AI-Uebersetzung, xx-Sync, TextMultilingual-Batch-Uebersetzung |
|
|
| `app.py` | `gateway/` | Boot-Hooks (`_syncRegistryToDb`, `_loadCache`), Request-Middleware (`_setLanguage`) |
|
|
|
|
### Architektur-Regeln
|
|
|
|
1. **`t()` NUR mit String-Literalen:** `t("Speichern")` ist korrekt, `t(variable)` ist verboten. Jeder i18n-Key muss als Literal im Code stehen, damit er beim Import registriert wird.
|
|
2. **Backend uebersetzt, Frontend rendert:** Das Backend liefert uebersetzte Strings via API. Das Frontend ruft `t()` nur fuer eigene statische UI-Texte auf, nie fuer Werte die vom Backend kommen.
|
|
3. **Fallback `[key]`:** Wenn eine Uebersetzung fehlt, gibt `t()` `[key]` zurueck (z.B. `[Speichern]`), damit fehlende Uebersetzungen im UI sofort sichtbar sind.
|
|
4. **Keine lokalen Resolve-Helfer:** Alle Label-Aufloesung laeuft ueber `resolveText()` (zentral in `i18nRegistry.py`). Keine `_resolveLabel()`, `_resolveTextMultilingual()`, `_storeLabelText()` etc. in Route-Dateien.
|
|
|
|
### Zentrale Funktionen
|
|
|
|
**`t(key: str) -> str`** — Tag + Translate:
|
|
- Bei Import: registriert Key in `_REGISTRY`
|
|
- Bei Runtime: liefert `_CACHE[lang][key]`, Fallback `[key]`
|
|
- Sprache kommt aus `_CURRENT_LANGUAGE` ContextVar (gesetzt durch Middleware)
|
|
|
|
**`resolveText(value: Any, lang: Optional[str] = None) -> str`** — Universelle Label-Aufloesung:
|
|
- `str` → `t(value)` (behandelt als i18n-Key)
|
|
- `dict` → Nutzersprache aus Kontext (oder `lang` wenn gesetzt), dann `xx`, dann erster nicht-leerer Wert (keine eckigen Klammern — das ist Inhalt, kein fehlender UI-Key)
|
|
- `TextMultilingual` → `model_dump()` dann dict-Logik
|
|
- `None` → `""`
|
|
|
|
### 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). `resolveText()` nutzt denselben Mechanismus.
|
|
|
|
### TextMultilingual
|
|
|
|
Felder vom Typ `TextMultilingual` speichern Benutzertexte mehrsprachig. `xx` ist das Pflichtfeld (Quelltext/Deutsch), weitere Sprachen werden dynamisch als Extra-Felder gespeichert. Bei neuer Sprache werden alle TextMultilingual-Felder per Batch-Job automatisch uebersetzt (`routeI18n._translateTextMultilingualFields`). On-Demand: `POST /api/i18n/translate-field`.
|
|
|
|
### 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.
|
|
|
|
## Feature: Trustee -- Daten-Tabellen-Endpunkte
|
|
|
|
Alle 13 Trustee-Tabellen sind ueber paginierte, RBAC-gefilterte GET-Endpunkte abrufbar. Die sechs CRUD-Modelle (`TrusteeOrganisation`, `TrusteeRole`, `TrusteeAccess`, `TrusteeContract`, `TrusteeDocument`, `TrusteePosition`) haben weiterhin die etablierten REST-Routen; sieben weitere (zuvor nur als JSON-Export oder Aggregat-Endpunkt verfuegbar) wurden ergaenzt:
|
|
|
|
| Endpunkt | Modell | Zweck |
|
|
|----------|--------|-------|
|
|
| `GET /api/trustee/{instanceId}/data/accounts` | `TrusteeDataAccount` | Synchronisierter Kontenplan (read-only) |
|
|
| `GET /api/trustee/{instanceId}/data/journal-entries` | `TrusteeDataJournalEntry` | Synchronisierte Buchungskoepfe (read-only) |
|
|
| `GET /api/trustee/{instanceId}/data/journal-lines` | `TrusteeDataJournalLine` | Synchronisierte Buchungszeilen (read-only) |
|
|
| `GET /api/trustee/{instanceId}/data/contacts` | `TrusteeDataContact` | Synchronisierte Kontakte (read-only) |
|
|
| `GET /api/trustee/{instanceId}/data/account-balances` | `TrusteeDataAccountBalance` | Synchronisierte Saldenliste (read-only) |
|
|
| `GET /api/trustee/{instanceId}/accounting/configs` | `TrusteeAccountingConfig` | Connector-Konfiguration (read-only; Secrets maskiert) |
|
|
| `GET /api/trustee/{instanceId}/accounting/syncs` | `TrusteeAccountingSync` | Audit-Eintraege der Sync-Laeufe (read-only) |
|
|
|
|
Alle sieben Endpunkte teilen sich den Helper `_paginatedReadEndpoint` (`routeFeatureTrustee.py`), der das Pattern aus `get_documents` / `get_positions` reproduziert: Unified Filter API (`mode=filterValues|ids`), `_validateInstanceAccess` fuer Instanz-Gating und `getRecordsetPaginatedWithRBAC` mit `featureCode` + `data.feature.trustee.<Model>` fuer datenbasierten RBAC. FK-Felder werden automatisch via `enrichRowsWithFkLabels` aufgeloest (siehe [FK Label Resolution](fk-label-resolution.md)).
|
|
|
|
UI-seitig sind diese Endpunkte unter `/mandates/{m}/trustee/{i}/data-tables[?tab=<key>]` (View `TrusteeDataTablesView`) zugaenglich; UI-Sichtbarkeit der Seite haengt am Permission-Eintrag `ui.feature.trustee.data-tables` (Template-Rollen `trustee-viewer`, `trustee-user`, `trustee-accountant`, Admin via Wildcard).
|
|
|
|
## Typed Action Architecture (4-Schichten)
|
|
|
|
Seit Phase 1-5 (April 2026) folgt jede Workflow-Aktion einem strikten 4-Schichten-Modell. Quellen: `wiki/c-work/3-validate/2026-04-typed-action-architecture.md`, Tests in `gateway/tests/unit/workflows/`, `gateway/tests/integration/trustee/`.
|
|
|
|
| Schicht | Modul / Verantwortung | Type-Anker |
|
|
|---------|-----------------------|------------|
|
|
| **1. Editor (Frontend)** | `frontend_nyla/src/components/FlowEditor/nodes/shared/` -- `RequiredAttributePicker`, `DataPicker` (strict-mode + Object-Drill-Down mit `*`-Wildcard), `paramValidation.ts` | Action-Signaturen aus dem Catalog (`/api/automation2/catalog`) |
|
|
| **2. Action / Method** | `gateway/modules/workflows/methods/method<Feature>/actions/*.py` (`extractFromFiles`, `processDocuments`, `syncToAccounting`, ...) | Typisierte Pydantic-Eingabe + `ActionResult`-Output, `FeatureInstanceRef` als Discriminator-Envelope |
|
|
| **3. Adapter** | `gateway/modules/features/graphicalEditor/nodeDefinitions/registerNodeWithMethod` -- leitet Node-Definitions aus Action-Signaturen ab, liefert Snapshot fuer den Editor (`adapter_validator`) | Snapshot-Test `test_staticNodesHaveNoDriftAgainstLiveMethods` (`_KNOWN_ADAPTER_DRIFTS = frozenset()`) |
|
|
| **4. Runtime** | `gateway/modules/workflows/automation2/executionEngine.py` -- `executeGraph` mit `materializeFeatureInstanceRefs` + `materializeConnectionRefs`, `_unwrapTypedRef` fuer Action-Calls | Migrations-Helper in `automation2/featureInstanceRefMigration.py` + DB-CLI `scripts/script_migrate_feature_instance_refs.py` |
|
|
|
|
Konsequenzen:
|
|
|
|
- **Single source of truth** ist die Action-Signatur. Editor, Adapter, Runtime und AI-Agent (`actionToolAdapter`) lesen alle dieselbe Catalog-Sicht.
|
|
- **Pick-not-push** auf Schicht 4: Runtime resolviert `connectionReference` und unwrappt typisierte Envelopes (`FeatureInstanceRef`, `DataRef`) automatisch -- Legacy-Aktionen bleiben funktionsfaehig.
|
|
- **Save-with-errors** ist explizit erlaubt (AC-9-Patch im `CanvasHeader`); Run wird mit `executeBlockedReason` blockiert, der Save-Toast meldet Pflicht-Fehler-Anzahl.
|
|
- **DB-Hygiene** ist optional via `script_migrate_feature_instance_refs.py` (`--dry-run` standard) -- ohne Skript laufen Workflows korrekt, der Editor zeigt aber bis zum naechsten Save noch das Legacy-Format.
|
|
|
|
## 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.
|
|
- **Datenbank:** Persistenz und die genannten Domänen-Reads/Writes laufen über die **Interface**-Schicht, nicht ad hoc aus Routen heraus.
|
|
- **Service Center:** Aufrufe laufen über die zentrale Auflösung (`getService` + Kontext); Workflows und Routen konsumieren dieselbe Landschaft.
|
|
- **Sicherheit & Governance:** RBAC und Geheimnisse werden zentral geführt; Service-Aufrufe und Workflow-Schritte sollen nachvollziehbar sein (Audit); Kontingente und Limits pro Mandant/Service sind vorgesehen.
|
|
- **HTTP-Einstieg:** Globale Middleware (CSRF, Token-Refresh unter `modules/auth/`); RBAC-Auswertung und Katalog unter `modules/security/`.
|
|
- **Code-Konventionen (Projekt):** Interne Hilfsfunktionen mit Präfix **`_`**; Bezeichner in **camelCase** für Variablen und Funktionen.
|