wiki/concepts/Kontext-20260328.md

9.5 KiB

Kontext: Wir arbeiten an einer Multi-Tenant-Applikation mit Feature-Store-Modell. Ich möchte UI und Gateway austesten und offene Themen weiterführen. Hier ist der vollständige architektonische Kontext:


Architektur-Überblick

  • Backend (Gateway): @poweron/gateway — FastAPI (Python), PostgreSQL
  • Frontend: @poweron/frontend_nyla — React/TypeScript (Vite)
  • Konzeptdokument: @poweron/wiki/concepts/Multi-Mandate-Onboarding-und-Store-Konzept.md
  • Umsetzungsbericht (103 Punkte OK): @poweron/wiki/concepts/Multi-Mandate-Umsetzungsbericht.md

RBAC-Rollenmodell (KRITISCH — nie verwechseln!)

Es gibt ZWEI vollständig getrennte Rollensysteme. Siehe auch: @poweron/.cursor/rules/rbac-role-separation.mdc

1. Mandantenrollen (Mandate Roles)

  • Labels: admin, user, viewer (generisch)
  • Gespeichert mit: featureCode=NULL, featureInstanceId=NULL, mandateId=<id>
  • Templates: isSystemRole=True, mandateId=NULL, featureCode=NULL
  • Verknüpfung: UserMandateRole Junction Table
  • Logik: Zuordnung User → Mandant erfolgt via createUserMandate() in interfaceDbApp.py, welche IMMER mindestens eine Mandate-Rolle verlangt (ValueError wenn leer)

2. Feature-Instanz-Rollen (Feature Instance Roles)

  • Labels: workspace-admin, workspace-user, workspace-viewer, automation-admin, etc. (Feature-Prefix!)
  • Gespeichert mit: featureCode=<code>, featureInstanceId=<id>, mandateId=<id>
  • Templates: isSystemRole=False, mandateId=NULL, featureInstanceId=NULL, featureCode=<code> (globale Vorlagen)
  • Verknüpfung: FeatureAccessRole Junction Table
  • Logik: Zuordnung User → Feature-Instanz erfolgt via createFeatureAccess() in interfaceDbApp.py, welche IMMER mindestens eine Instanz-Rolle verlangt (ValueError wenn leer)
  • Jedes Feature-Modul definiert seine TEMPLATE_ROLES in mainXxx.py

Strikte Regeln:

  1. NIE eine Mandantenrolle (admin) einer FeatureAccessRole zuweisen
  2. NIE eine Feature-Rolle (workspace-admin) einer UserMandateRole zuweisen
  3. Admin-Lookup für Feature-Instanzen: roleLabel.endswith("-admin"), NICHT "admin" in roleLabel
  4. _copyTemplateRoles sucht: featureCode=X, mandateId=NULL, featureInstanceId=NULL — nie isSystemRole=True
  5. Alle Pfade, die FeatureAccess erstellen, MÜSSEN mindestens eine instanz-scoped roleId mitgeben

Datenmodelle:

  • Role: @poweron/gateway/modules/datamodels/datamodelRbac.py — Felder: id, roleLabel, description, mandateId, featureInstanceId, featureCode, isSystemRole
  • UserMandate: @poweron/gateway/modules/datamodels/datamodelMembership.py — User-Mitgliedschaft in Mandant
  • FeatureAccess: @poweron/gateway/modules/datamodels/datamodelMembership.py — User-Zugriff auf Feature-Instanz
  • FeatureInstance: @poweron/gateway/modules/datamodels/datamodelFeatures.py — Instanz eines Features in einem Mandanten
  • Mandate: @poweron/gateway/modules/datamodels/datamodelUam.py — Mandantenmodell mit mandateType (system/personal/company), isSystem, deletedAt

Feature-Store-Konzept ("Own Instance Pattern")

  • UI: @poweron/frontend_nyla/src/pages/Store.tsx — Pro Mandant ein "Aktivieren für [Mandant]" Button
  • Backend: @poweron/gateway/modules/routes/routeStore.pyPOST /api/store/activate
  • Flow: User wählt Feature → wählt Mandant → Backend erstellt FeatureInstance mit copyTemplateRoles=True → findet Admin-Rolle (endswith("-admin")) → weist User via createFeatureAccess(userId, instanceId, roleIds=[adminRoleId]) zu
  • Auto-Provisioning: GET /api/store/mandates erstellt automatisch Personal-Mandate, wenn User keine Admin-Mandate hat
  • Template-Rollen-Kopie: @poweron/gateway/modules/interfaces/interfaceFeatures.py_copyTemplateRoles() und syncRolesFromTemplate()
  • Orphan Control: Letzer FeatureAccess entfernt → FeatureInstance wird gelöscht

Schlüssel-Backend-Dateien

Datei Zweck
@poweron/gateway/modules/interfaces/interfaceDbApp.py Kern-DB-Interface: createUserMandate, createFeatureAccess, _provisionMandateForUser; Domain-Models nutzen PowerOnModel / sys*-Metadaten
@poweron/gateway/modules/interfaces/interfaceFeatures.py Feature-Instanz-Verwaltung: _copyTemplateRoles, syncRolesFromTemplate
@poweron/gateway/modules/routes/routeStore.py Store-API: activate, mandates-list
@poweron/gateway/modules/routes/routeAdminFeatures.py Admin-API: add_user_to_feature_instance (Rollen-Validierung: nur Instanz-Rollen!), rename instance
@poweron/gateway/modules/routes/routeSystem.py /api/navigation — liefert isAdmin pro FeatureInstance
@poweron/gateway/modules/routes/routeSecurityLocal.py Login, Register, _provisionMandateForUser
@poweron/gateway/modules/shared/attributeUtils.py Generiert Attribute aus Pydantic-Models für FormGenerator
@poweron/gateway/modules/connectors/connectorDbPostgre.py DB-Connector: sysCreatedAt / sysCreatedBy / sysModifiedAt / sysModifiedBy; Migration alter _createdAt-Spalten via migrateLegacyUnderscoreSysColumns (Bootstrap)
@poweron/gateway/modules/migration/migrateRootUsers.py Root→Personal-Mandate-Migration

Schlüssel-Frontend-Dateien

Datei Zweck
@poweron/frontend_nyla/src/pages/Store.tsx Feature-Store mit Mandate-Kontext
@poweron/frontend_nyla/src/components/UnifiedDataBar/UnifiedDataBar.tsx UDB: Chats, Files, Sources Tabs
@poweron/frontend_nyla/src/components/UnifiedDataBar/ChatsTab.tsx Chats: Aktiv/Archiv, Rename/Delete/Archive Icons
@poweron/frontend_nyla/src/components/UnifiedDataBar/FilesTab.tsx Files: Scope/Neutralize Icons
@poweron/frontend_nyla/src/components/UnifiedDataBar/SourcesTab.tsx Sources: Scope/Neutralize auf Active Sources
@poweron/frontend_nyla/src/components/Navigation/MandateNavigation.tsx Nav-Tree mit Rename-Icon für Instanz-Admins
@poweron/frontend_nyla/src/components/Navigation/TreeNavigation/TreeNavigation.tsx Generischer Tree mit actions-Slot
@poweron/frontend_nyla/src/components/OnboardingAssistant.tsx Globaler Onboarding-Assistent (Dashboard, dismissible, reaktivierbar via UserSection)
@poweron/frontend_nyla/src/components/Navigation/UserSection.tsx User-Kontextmenü: Guthaben, Einstellungen, Onboarding
@poweron/frontend_nyla/src/pages/Settings.tsx User-Settings: profile, appearance, voice, neutralization, privacy
@poweron/frontend_nyla/src/components/FormGenerator/ Dynamische Formulare aus Backend-Attribut-Definitionen
@poweron/frontend_nyla/src/hooks/useNavigation.ts Navigation-Hook mit FeatureInstance.isAdmin
@poweron/frontend_nyla/src/pages/views/workspace/WorkspacePage.tsx Workspace-Feature-Seite
@poweron/frontend_nyla/src/pages/views/commcoach/CommcoachDossierView.tsx CommCoach mit UDB (hideTabs: chats), gleicher instanceId/mandateId-Kontext wie Workspace
@poweron/gateway/modules/datamodels/datamodelBase.py PowerOnModel: sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy (camelCase, UI-readonly vorbereitet)

System-Felder (DB-Metadaten)

  • Spalten / Modelle: sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy — gepflegt durch den Connector (connectorDbPostgre.py); viele Domain-Models erben von PowerOnModel in datamodelBase.py.
  • Legacy: Frühere _createdAt-ähnliche Spalten werden bei Bootstrap durch migrateLegacyUnderscoreSysColumns / migrateLegacyUnderscoreSysColumnsAllPoweronDatabases in die sys*-Felder übernommen.
  • UI: FormGenerator unterstützt readonly-Attribute; wo Metadaten in Listen/Forms explizit gezeigt werden sollen, Felder als readonly markieren (schrittweise je Screen).

Produkt-Themen (Stand laut Umsetzung)

  1. CommCoach UDB: CommcoachDossierView nutzt UnifiedDataBar mit hideTabs={['chats']} (Dateien + Quellen). Coaching bleibt bei der bestehenden SSE-Pipeline. KI: CommcoachService._callAi nutzt getService("ai", ServiceCenterContext) — dieselbe ServiceCenter-AI-Schicht wie der Workspace inkl. Neutralisierung in mainServiceAi.callAi. Nach documentCreated im Stream feuert die View fileUploaded, die UDB-FilesTab lädt die Liste neu.
  2. Zentrale Neutralisierung & RAG: Prompt-Neutralisierung und Rehydration laufen in mainServiceAi (stream + non-stream). Tool neutralizeData im Agent und die Indizierung in mainServiceKnowledge nutzen denselben Neutralization-Service. Mandanten-RAG in CommCoach: Bei Retrieval-Intent „Thema erinnern“ (RECALL_TOPIC) werden nach Keyword-Suche zusätzlich Embedding + searchSessionsByTopicRag (Knowledge-Interface, mandate-scoped) eingespeist; die Prompt-Zeile „Relevante Sessions und Mandantenwissen …“ fasst Sessions und RAG-Snippets zusammen.
  3. Settings (5 Tabs): Profil (Modal + Konto + About), Darstellung (Theme + UI-Sprache), Stimme (STT/TTS API), Datenneutralisierung (Erklärung + Platzhalter-Mappings-Liste), Datenschutz (Kurztext Mandant/Features + Link GDPR). Für tiefergehende Neutralizer-Konfiguration (Feature-Instanz) bleiben die Feature-spezifischen Admin-UIs zuständig.

Coding-Konventionen

  • Alle internen Funktionen beginnen mit _ Prefix (z.B. _copyTemplateRoles)
  • camelCase für alle Variablen und Funktionsnamen (kein snake_case)
  • Keine unnötigen Fallbacks — Fehler müssen propagiert werden
  • Keine Deprecations — alte Logik löschen statt deprecaten
  • Keine Backwards-Compatibility-Workarounds
  • Pydantic-Models sind die einzige Quelle für UI-Feld-Definitionen (via attributeUtils.py)