wiki/concepts/Kontext-20260328.md
2026-03-28 16:59:18 +01:00

8.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 (44x _-Prefix-Filter für System-Felder)
@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: _saveRecord setzt automatisch _createdAt, _createdBy, _modifiedAt, _modifiedBy
@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

System-Felder (DB-Metadaten) — OFFENER PUNKT

Die DB-Schicht (connectorDbPostgre.py) pflegt automatisch 4 System-Felder für jede Tabelle:

  • _createdAt (float, UTC timestamp)
  • _createdBy (str, userId)
  • _modifiedAt (float, UTC timestamp)
  • _modifiedBy (str, userId)

Diese werden aktuell in interfaceDbApp.py an 44 Stellen via {k: v for k, v in record.items() if not k.startswith("_")} herausgefiltert, bevor Records an die API/Frontend gehen. Es gibt KEINE gemeinsame Base-Klasse — alle 30+ Pydantic-Models erben direkt von BaseModel.

Offene Architektur-Entscheidung: Diese 4 System-Felder sollen im UI als read-only sichtbar sein (z.B. in Tabellen/Formularen). Optionen:

  • (a) PowerOnModel(BaseModel) als Base-Klasse mit den 4 Feldern (mit alias="_createdAt" etc.) einführen, _-Filter entfernen
  • (b) Einige Models (FeatureDataSource, DataSource, FileFolder, Invitation, Messaging) haben bereits eigene createdAt/createdBy als Business-Felder — Namenskonflikte zu klären!
  • Der FormGenerator unterstützt bereits readonly-Attribute korrekt

Weitere offene Themen aus dem vorherigen Chat

  1. CommCoach UDB-Integration: UDB in CommCoach einbinden (ohne Chats-Tab), gleicher AI-Service wie Workspace, CommCoach behält eigene SSE-Chat-Komponente
  2. Zentrale AI-Neutralisierung: RAG mandate-weit verfügbar, Neutralisierungs-Pipeline weiter konsolidieren
  3. Settings-Seite: 5 Tabs vorhanden (profile, appearance, voice, neutralization, privacy) — Vollständigkeit prüfen

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)