9.5 KiB
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:
UserMandateRoleJunction Table - Logik: Zuordnung User → Mandant erfolgt via
createUserMandate()ininterfaceDbApp.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:
FeatureAccessRoleJunction Table - Logik: Zuordnung User → Feature-Instanz erfolgt via
createFeatureAccess()ininterfaceDbApp.py, welche IMMER mindestens eine Instanz-Rolle verlangt (ValueError wenn leer) - Jedes Feature-Modul definiert seine
TEMPLATE_ROLESinmainXxx.py
Strikte Regeln:
- NIE eine Mandantenrolle (
admin) einerFeatureAccessRolezuweisen - NIE eine Feature-Rolle (
workspace-admin) einerUserMandateRolezuweisen - Admin-Lookup für Feature-Instanzen:
roleLabel.endswith("-admin"), NICHT"admin" in roleLabel _copyTemplateRolessucht:featureCode=X, mandateId=NULL, featureInstanceId=NULL— nieisSystemRole=True- Alle Pfade, die
FeatureAccesserstellen, MÜSSEN mindestens eine instanz-scoped roleId mitgeben
Datenmodelle:
Role:@poweron/gateway/modules/datamodels/datamodelRbac.py— Felder: id, roleLabel, description, mandateId, featureInstanceId, featureCode, isSystemRoleUserMandate:@poweron/gateway/modules/datamodels/datamodelMembership.py— User-Mitgliedschaft in MandantFeatureAccess:@poweron/gateway/modules/datamodels/datamodelMembership.py— User-Zugriff auf Feature-InstanzFeatureInstance:@poweron/gateway/modules/datamodels/datamodelFeatures.py— Instanz eines Features in einem MandantenMandate:@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.py—POST /api/store/activate - Flow: User wählt Feature → wählt Mandant → Backend erstellt
FeatureInstancemitcopyTemplateRoles=True→ findet Admin-Rolle (endswith("-admin")) → weist User viacreateFeatureAccess(userId, instanceId, roleIds=[adminRoleId])zu - Auto-Provisioning:
GET /api/store/mandateserstellt automatisch Personal-Mandate, wenn User keine Admin-Mandate hat - Template-Rollen-Kopie:
@poweron/gateway/modules/interfaces/interfaceFeatures.py—_copyTemplateRoles()undsyncRolesFromTemplate() - 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 vonPowerOnModelindatamodelBase.py. - Legacy: Frühere
_createdAt-ähnliche Spalten werden bei Bootstrap durchmigrateLegacyUnderscoreSysColumns/migrateLegacyUnderscoreSysColumnsAllPoweronDatabasesin diesys*-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)
- CommCoach UDB:
CommcoachDossierViewnutztUnifiedDataBarmithideTabs={['chats']}(Dateien + Quellen). Coaching bleibt bei der bestehenden SSE-Pipeline. KI:CommcoachService._callAinutztgetService("ai", ServiceCenterContext)— dieselbe ServiceCenter-AI-Schicht wie der Workspace inkl. Neutralisierung inmainServiceAi.callAi. NachdocumentCreatedim Stream feuert die ViewfileUploaded, die UDB-FilesTablädt die Liste neu. - Zentrale Neutralisierung & RAG: Prompt-Neutralisierung und Rehydration laufen in
mainServiceAi(stream + non-stream). ToolneutralizeDataim Agent und die Indizierung inmainServiceKnowledgenutzen 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. - 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)