From b0ffd5255653963c72cf5b4829b033945904e7c2 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Tue, 20 Jan 2026 08:39:25 +0100 Subject: [PATCH] upd --- .../mandate_implementation_analysis.md | 846 ++++++++++++++++++ 1 file changed, 846 insertions(+) create mode 100644 implementation/Saas Multi Tenant Mandate/mandate_implementation_analysis.md diff --git a/implementation/Saas Multi Tenant Mandate/mandate_implementation_analysis.md b/implementation/Saas Multi Tenant Mandate/mandate_implementation_analysis.md new file mode 100644 index 0000000..07129e0 --- /dev/null +++ b/implementation/Saas Multi Tenant Mandate/mandate_implementation_analysis.md @@ -0,0 +1,846 @@ +# 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 | `