# Multi-Tenant Implementation Analysis - Frontend Nyla **Version:** 1.1 **Datum:** 20. Januar 2026 **Basis:** `mandate_implementation_ui_myla.md` (Konzept) & `mandate_implementation_gateway.md` (Backend) --- ## 1. Zusammenfassung Dieses Dokument analysiert den Implementierungsstand des Multi-Tenant-Systems im Frontend Nyla und vergleicht es mit dem Konzeptdokument. Es enthält: - Was implementiert ist ✅ - Was teilweise implementiert ist ⚠️ - Was noch fehlt ❌ - Strukturempfehlungen für die Integration --- ## 2. Implementierungsstand - Übersicht | Komponente | Status | Details | |------------|--------|---------| | **Core Types** | ✅ Implementiert | `types/mandate.ts` - vollständig | | **Feature Store** | ✅ Implementiert | `stores/featureStore.tsx` - React Context-basiert | | **useCurrentInstance Hook** | ✅ Implementiert | URL-basierte Instanz-Auflösung | | **Instance Permission Hooks** | ✅ Implementiert | `useInstancePermissions.tsx` | | **Permission Gate Component** | ✅ Implementiert | Conditional Rendering | | **Mandate Navigation** | ✅ Implementiert | Hierarchische Tree-Navigation | | **Features API** | ✅ Implementiert | `featuresApi.ts` mit `/api/features/my` | | **URL-Struktur** | ✅ Implementiert | `/mandates/:mandateId/:featureCode/:instanceId/*` | | **Invitation Flow** | ✅ Implementiert | `InvitePage.tsx` + `useInvitations.ts` | | **Admin: Mandates** | ✅ Implementiert | `AdminMandatesPage.tsx` | | **Admin: Users** | ✅ Implementiert | `AdminUsersPage.tsx` | | **Admin: Roles** | ✅ Implementiert | `AdminRolesPage.tsx` | | **Admin: Mandate Roles** | ✅ Implementiert | `AdminMandateRolesPage.tsx` | | **Admin: Invitations** | ✅ Implementiert | `AdminInvitationsPage.tsx` | | **Admin: Feature Access** | ✅ Implementiert | `AdminFeatureAccessPage.tsx` | | **Admin: User Mandates** | ✅ Implementiert | `AdminUserMandatesPage.tsx` | | **AccessRules Editor** | ✅ Implementiert | `components/AccessRules/AccessRulesEditor.tsx` | | **RBAC Export/Import** | ✅ Implementiert | `components/RbacExportImport/RbacExportImport.tsx` | | **Mandate-Admin Section per Mandate** | ⚠️ Teilweise | Nur global, nicht pro Mandant | --- ## 3. Detaillierte Analyse ### 3.1 Core Architecture ✅ #### Types (`src/types/mandate.ts`) **Status: Vollständig implementiert** ```typescript // Implementiert gemäss Konzept: - I18nLabel - AccessLevel ('n' | 'm' | 'g' | 'a') - TablePermission - FieldPermission - InstancePermissions - FeatureInstance - MandateFeature - Mandate - FeaturesMyResponse - User (ohne mandateId!) - FEATURE_REGISTRY ``` **Korrekte Umsetzung der Konzept-Prinzipien:** - User hat KEINE `mandateId` mehr - Permissions sind summarisch pro Instanz - Hierarchie: `Mandate → Feature → Instance → Views` --- ### 3.2 Feature Store ✅ **Datei:** `src/stores/featureStore.tsx` **Status: Vollständig implementiert als React Context** | Konzept-Anforderung | Implementiert | |---------------------|---------------| | `loadFeatures()` | ✅ Lädt von `/api/features/my` | | `setFeatures()` | ✅ Direktes Setzen nach Login | | `getMandateById()` | ✅ | | `getFeatureByCode()` | ✅ | | `getInstanceById()` | ✅ Mit Cache-Map für Performance | | `getAllInstances()` | ✅ | | `hasAnyInstance()` | ✅ | | `reset()` | ✅ Für Logout | **Abweichung vom Konzept:** - Konzept: Zustand-basiert (Zustand Library) - Implementiert: React Context + useState + useRef für Cache **Bewertung:** Funktional äquivalent, React Context ist für die Anwendungsgrösse angemessen. --- ### 3.3 useCurrentInstance Hook ✅ **Datei:** `src/hooks/useCurrentInstance.ts` **Status: Vollständig implementiert** ```typescript // Exportierte Hooks: - useCurrentInstance() // Vollständiger Kontext - useInstance() // Nur Instanz - useInstanceId() // Nur ID - useFeatureCode() // Nur Feature-Code - useMandateId() // Nur Mandate-ID - useIsInFeatureContext() // Boolean Check ``` **Korrekte Umsetzung:** - Liest Parameter aus URL (`useParams`) - Validiert Konsistenz (Instanz gehört zu Mandate/Feature) - Keine Speicherung im globalen State --- ### 3.4 Permission System ✅ **Dateien:** - `src/hooks/useInstancePermissions.tsx` - `src/hooks/usePermissions.ts` #### Instance-basierte Permissions ✅ | Hook | Status | Verwendung | |------|--------|------------| | `useTablePermission(tableName)` | ✅ | CRUD-Checks auf Tabellen | | `useCanViewTable(tableName)` | ✅ | View-Check | | `useCanViewFeatureView(viewCode)` | ✅ | Navigation-Filterung | | `useViewPermissions(viewCodes[])` | ✅ | Bulk View-Checks | | `useFieldPermission(table, field)` | ✅ | Feld-Level Checks | | `useInstancePermissions()` | ✅ | Raw Permissions-Objekt | | `useCanEditRecord()` | ✅ | Record-basierte Prüfung | | `useCanDeleteRecord()` | ✅ | Record-basierte Prüfung | #### PermissionGate Component ✅ ```tsx }> ``` **Implementiert gemäss Konzept** - Conditional Rendering basierend auf Permissions. --- ### 3.5 Navigation ✅ **Datei:** `src/components/Navigation/MandateNavigation.tsx` **Status: Vollständig implementiert** **Struktur wie im Konzept:** ``` SYSTEM (immer) ○ Übersicht ○ Einstellungen ▼ Mandant: Soha Treuhand ├─▼ Feature: Trustee │ ├─▼ Instanz: PamoCreate AG (mit Views) │ └─▼ Instanz: ValueOn AG (mit Views) └─▼ Feature: Workflow └─▼ Instanz: Beratung Dynamic ───────────────────────────── ADMINISTRATION (nur SysAdmin) ○ Mandanten ○ Benutzer ○ Globale Rollen ... ``` **Implementierte Features:** - Hierarchische Tree-Navigation (`TreeNavigation`) - Dynamische Icon-Zuordnung pro Feature - Automatisches Filtern von Views basierend auf Permissions - Admin-Sektion nur für `isSysAdmin` - Empty State wenn keine Instanzen --- ### 3.6 URL-Struktur ✅ **Datei:** `src/App.tsx` **Implementierte Routen:** ``` / → Dashboard /settings → Benutzer-Einstellungen /mandates/:mandateId/:featureCode/:instanceId → Feature Layout /dashboard → Feature Dashboard /contracts → Verträge /documents → Dokumente /positions → Positionen /organisations → Organisationen /roles → Rollen /access → Zugriffe /runs → Workflow Runs /files → Dateien /conversations → Chat /admin/mandates → Admin: Mandanten /admin/users → Admin: Benutzer /admin/roles → Admin: Globale Rollen /admin/user-mandates → Admin: Mandanten-Mitglieder /admin/feature-instances → Admin: Feature-Instanzen /admin/invitations → Admin: Einladungen /admin/mandate-roles → Admin: Mandanten-Rollen /invite/:token → Einladungs-Annahme /login, /register, /password-reset-request, /reset → Auth ``` **Korrekte Umsetzung der Konzept-URL-Struktur.** --- ### 3.7 Invitation Flow ✅ **Dateien:** - `src/pages/InvitePage.tsx` - `src/hooks/useInvitations.ts` **Implementierte Funktionen:** | Feature | Status | |---------|--------| | Token-Validierung | ✅ `validateInvitation(token)` | | Einladung annehmen (auth) | ✅ `acceptInvitation(token)` | | Registrieren + Annehmen | ✅ `registerAndAccept(data)` | | Einladungen erstellen | ✅ `createInvitation()` | | Einladungen widerrufen | ✅ `revokeInvitation()` | | Einladungen auflisten | ✅ `fetchInvitations()` | **InvitePage Features:** - Token-Validierung beim Mount - Unterscheidung: Eingeloggt vs. Nicht eingeloggt - Registrierungsformular für neue User - Login-Redirect für bestehende User - Fehlerbehandlung für ungültige/abgelaufene Tokens --- ### 3.8 Admin Pages ✅ **Alle Admin-Seiten verwenden `FormGeneratorTable` und `FormGeneratorForm`.** | Seite | Status | Funktionen | |-------|--------|------------| | `AdminMandatesPage` | ✅ | CRUD Mandanten, Table mit Pagination | | `AdminUsersPage` | ✅ | CRUD Benutzer | | `AdminRolesPage` | ✅ | CRUD Globale Rollen | | `AdminMandateRolesPage` | ✅ | Rollen pro Mandant, Filter (global/mandate) | | `AdminUserMandatesPage` | ✅ | User-Mandate-Zuordnungen | | `AdminFeatureAccessPage` | ✅ | Feature-Instanz-Zugriffe | | `AdminInvitationsPage` | ✅ | Einladungsverwaltung | --- ## 4. Neu Implementierte RBAC-Komponenten ✅ ### 4.1 AccessRules Editor ✅ **Datei:** `src/components/AccessRules/AccessRulesEditor.tsx` **Status: Vollständig implementiert** Die Komponente ermöglicht die Bearbeitung von RBAC-Regeln pro Rolle mit Tabs für verschiedene Regel-Kontexte. #### Komponenten-Struktur ``` src/components/AccessRules/ ├── AccessRulesEditor.tsx // Hauptkomponente mit Tabs ├── AccessRules.module.css // Styles ├── AccessLevelSelect.tsx // Dropdown für n/m/g/a └── index.ts ``` #### Verwendung ```tsx import { AccessRulesEditor } from '../components/AccessRules'; // In einer Admin-Seite: refetchRoles()} // Optional: Callback nach Speichern /> ``` #### Features | Feature | Status | |---------|--------| | Tabs: DATA, UI, RESOURCE, JSON | ✅ | | AccessLevel Dropdown (n/m/g/a) | ✅ | | Regel hinzufügen | ✅ | | Regel löschen | ✅ | | Permissions-Grid (view, read, create, update, delete) | ✅ | | JSON-Editor für Raw-Bearbeitung | ✅ | | Speichern & Zurücksetzen | ✅ | | Änderungstracking | ✅ | | Read-Only Modus | ✅ | #### API-Hook ```typescript import { useAccessRules } from '../hooks/useAccessRules'; const { rules, // Alle Regeln für die Rolle loading, // Lade-Status saving, // Speicher-Status error, // Fehler-Nachricht fetchRules, // Regeln laden saveRules, // Regeln speichern (Bulk) createRule, // Einzelne Regel erstellen updateRule, // Einzelne Regel aktualisieren deleteRule, // Einzelne Regel löschen getGroupedRules, // Regeln nach Kontext gruppiert } = useAccessRules(roleId); ``` --- ### 4.2 RBAC Export/Import ✅ **Datei:** `src/components/RbacExportImport/RbacExportImport.tsx` **Status: Vollständig implementiert** Die Komponente ermöglicht Export und Import von RBAC-Konfigurationen. #### Komponenten-Struktur ``` src/components/RbacExportImport/ ├── RbacExportImport.tsx // Hauptkomponente ├── RbacExportImport.module.css // Styles └── index.ts ``` #### Verwendung ```tsx import { RbacExportImport } from '../components/RbacExportImport'; // Für Mandant: // Für globale Templates (SysAdmin): ``` #### Features | Feature | Status | |---------|--------| | Export als JSON-Download | ✅ | | Import via File-Upload | ✅ | | Import-Modi: merge, replace, add_only | ✅ | | Datei-Vorschau vor Import | ✅ | | Import-Ergebnis-Anzeige | ✅ | | Warnung bei Replace-Modus | ✅ | | Fehlerbehandlung | ✅ | #### Import-Modi | Modus | Beschreibung | |-------|--------------| | `merge` | Bestehende aktualisieren, neue hinzufügen | | `add_only` | Nur neue hinzufügen, bestehende unverändert | | `replace` | Alle bestehenden löschen und ersetzen | #### API-Hook ```typescript import { useRbacExportImport } from '../hooks/useRbacExportImport'; const { exporting, // Export läuft importing, // Import läuft error, // Fehler-Nachricht lastExport, // Letzter Export lastImportResult, // Letztes Import-Ergebnis exportMandateRbac, // Export für Mandant exportGlobalRbac, // Export für Templates importMandateRbac, // Import in Mandant importGlobalRbac, // Import in Templates downloadExport, // JSON-Download auslösen parseImportFile, // Datei parsen } = useRbacExportImport(); ``` --- ### 4.3 Mandate-Admin Section pro Mandant ⚠️ **Konzept:** ``` ▼ Mandant: Soha Treuhand ├─▼ Feature: Trustee │ └─▼ Instanzen... │ └─▼ ADMINISTRATION (nur Mandate-Admin) ○ Benutzer ○ Rollen ○ Berechtigungen ○ Feature-Instanzen ○ Einladungen ○ RBAC Export/Import ``` **Aktueller Stand:** - Admin-Sektion existiert nur global unter `/admin/*` - Kein Mandate-spezifischer Admin-Bereich in der Navigation **Empfehlung:** Die Navigation sollte pro Mandant einen Admin-Bereich anzeigen wenn der User `Mandate-Admin` Rolle hat. --- ## 5. FormGenerator Komponenten (statt GenericForm) > **Hinweis:** Es gibt keine `GenericForm` Komponente im Codebase. Die generische Form-Funktionalität wird durch die **FormGenerator**-Komponenten bereitgestellt. ### 5.1 Verfügbare Komponenten | Komponente | Pfad | Verwendung | |------------|------|------------| | `FormGeneratorForm` | `components/FormGenerator/FormGeneratorForm/` | Backend-driven Forms | | `FormGeneratorTable` | `components/FormGenerator/FormGeneratorTable/` | Data Tables mit CRUD | | `FormGeneratorList` | `components/FormGenerator/FormGeneratorList/` | Listen-Ansichten | | `FormGeneratorControls` | `components/FormGenerator/FormGeneratorControls/` | Filter/Search UI | ### 5.2 FormGeneratorForm - Verwendung ```tsx import { FormGeneratorForm, type AttributeDefinition } from '../components/FormGenerator/FormGeneratorForm'; // 1. Mit expliziten Attributen const fields: AttributeDefinition[] = [ { name: 'name', label: 'Name', type: 'string', required: true }, { name: 'description', label: 'Beschreibung', type: 'textarea' }, { name: 'enabled', label: 'Aktiv', type: 'boolean' }, { name: 'role', label: 'Rolle', type: 'enum', options: [...] }, ]; // 2. Mit Backend-getriebenen Attributen (fetcht von /api/attributes/{entityType}) ``` ### 5.3 FormGeneratorTable - Verwendung ```tsx import { FormGeneratorTable } from '../components/FormGenerator/FormGeneratorTable'; ``` ### 5.4 Unterstützte Feld-Typen | Type | Beschreibung | Input | |------|--------------|-------| | `string` | Text | `` | | `textarea` | Mehrzeiliger Text | `