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=` - 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=`, `featureInstanceId=`, `mandateId=` - Templates: `isSystemRole=False`, `mandateId=NULL`, `featureInstanceId=NULL`, `featureCode=` (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.py` — `POST /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`)