846 lines
25 KiB
Markdown
846 lines
25 KiB
Markdown
# 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
|
|
<PermissionGate table="TrusteeContract" action="create">
|
|
<Button>Neuer Vertrag</Button>
|
|
</PermissionGate>
|
|
|
|
<PermissionGate view="trustee-admin" fallback={<AccessDenied />}>
|
|
<AdminPanel />
|
|
</PermissionGate>
|
|
```
|
|
|
|
**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:
|
|
<AccessRulesEditor
|
|
roleId={selectedRole.id}
|
|
roleName={selectedRole.roleLabel}
|
|
isTemplate={true} // Optional: Template-Badge anzeigen
|
|
readOnly={false} // Optional: Nur-Lesen-Modus
|
|
onSave={() => 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:
|
|
<RbacExportImport
|
|
mandateId="mand-123"
|
|
mandateName="Soha Treuhand"
|
|
featureCode="trustee" // Optional: Nur für Feature
|
|
/>
|
|
|
|
// Für globale Templates (SysAdmin):
|
|
<RbacExportImport
|
|
isGlobal={true}
|
|
featureCode="trustee" // Optional
|
|
/>
|
|
```
|
|
|
|
#### 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: [...] },
|
|
];
|
|
|
|
<FormGeneratorForm
|
|
attributes={fields}
|
|
data={initialData} // Optional: Für Edit-Mode
|
|
mode="create" // 'create' | 'edit' | 'display'
|
|
onSubmit={handleSubmit}
|
|
onCancel={handleCancel}
|
|
submitButtonText="Erstellen"
|
|
cancelButtonText="Abbrechen"
|
|
/>
|
|
|
|
// 2. Mit Backend-getriebenen Attributen (fetcht von /api/attributes/{entityType})
|
|
<FormGeneratorForm
|
|
entityType="TrusteeContract"
|
|
data={contract}
|
|
mode="edit"
|
|
onSubmit={handleUpdate}
|
|
/>
|
|
```
|
|
|
|
### 5.3 FormGeneratorTable - Verwendung
|
|
|
|
```tsx
|
|
import { FormGeneratorTable } from '../components/FormGenerator/FormGeneratorTable';
|
|
|
|
<FormGeneratorTable
|
|
data={contracts}
|
|
columns={[
|
|
{ key: 'name', label: 'Name', type: 'string', sortable: true },
|
|
{ key: 'status', label: 'Status', type: 'enum' },
|
|
]}
|
|
loading={isLoading}
|
|
pagination={true}
|
|
pageSize={25}
|
|
searchable={true}
|
|
filterable={true}
|
|
sortable={true}
|
|
actionButtons={[
|
|
{ type: 'edit', onAction: handleEdit },
|
|
{ type: 'delete', title: 'Löschen' },
|
|
]}
|
|
onDelete={handleDelete}
|
|
hookData={{
|
|
refetch,
|
|
permissions,
|
|
handleInlineUpdate,
|
|
}}
|
|
/>
|
|
```
|
|
|
|
### 5.4 Unterstützte Feld-Typen
|
|
|
|
| Type | Beschreibung | Input |
|
|
|------|--------------|-------|
|
|
| `string` | Text | `<input type="text">` |
|
|
| `textarea` | Mehrzeiliger Text | `<textarea>` |
|
|
| `integer` | Ganzzahl | `<input type="number">` |
|
|
| `float` | Dezimalzahl | `<input type="number">` |
|
|
| `boolean` | Ja/Nein | `<input type="checkbox">` |
|
|
| `enum` | Auswahl | `<select>` |
|
|
| `multiselect` | Mehrfachauswahl | Checkboxes |
|
|
| `date` | Datum | `<input type="date">` |
|
|
| `datetime` | Datum+Zeit | `<input type="datetime-local">` |
|
|
| `email` | E-Mail | `<input type="email">` |
|
|
| `url` | URL | `<input type="url">` |
|
|
| `file` | Datei | `<input type="file">` |
|
|
| `textmultilingual` | Mehrsprachig | Inputs pro Sprache |
|
|
|
|
---
|
|
|
|
## 6. Integrations-Empfehlungen
|
|
|
|
### 6.1 Neue Feature-View hinzufügen
|
|
|
|
**Schritt 1:** View-Komponente erstellen
|
|
|
|
```tsx
|
|
// src/pages/views/trustee/TrusteeNewView.tsx
|
|
|
|
import React from 'react';
|
|
import { useCurrentInstance } from '../../../hooks/useCurrentInstance';
|
|
import { useTablePermission } from '../../../hooks/useInstancePermissions';
|
|
import { FormGeneratorTable } from '../../../components/FormGenerator/FormGeneratorTable';
|
|
|
|
export const TrusteeNewView: React.FC = () => {
|
|
const { instance } = useCurrentInstance();
|
|
const { canCreate, canUpdate, canDelete } = useTablePermission('TrusteeNewTable');
|
|
|
|
// Daten laden...
|
|
|
|
return (
|
|
<div>
|
|
<h2>Neue View</h2>
|
|
<FormGeneratorTable ... />
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
**Schritt 2:** In `FEATURE_REGISTRY` registrieren
|
|
|
|
```typescript
|
|
// src/types/mandate.ts
|
|
|
|
export const FEATURE_REGISTRY: Record<string, FeatureConfig> = {
|
|
trustee: {
|
|
// ...
|
|
views: [
|
|
// Bestehende Views...
|
|
{ code: 'newview', label: { de: 'Neue View', en: 'New View' }, path: 'newview' },
|
|
]
|
|
},
|
|
};
|
|
```
|
|
|
|
**Schritt 3:** In `VIEW_COMPONENTS` registrieren
|
|
|
|
```tsx
|
|
// src/pages/FeatureView.tsx
|
|
|
|
import { TrusteeNewView } from './views/trustee/TrusteeNewView';
|
|
|
|
const VIEW_COMPONENTS: Record<string, Record<string, ViewComponent>> = {
|
|
trustee: {
|
|
// Bestehende Views...
|
|
newview: TrusteeNewView,
|
|
},
|
|
};
|
|
```
|
|
|
|
**Schritt 4:** Route hinzufügen
|
|
|
|
```tsx
|
|
// src/App.tsx
|
|
|
|
<Route path="newview" element={<FeatureViewPage view="newview" />} />
|
|
```
|
|
|
|
---
|
|
|
|
### 6.2 AccessRulesEditor in Admin-Seiten integrieren
|
|
|
|
**Beispiel: Integration in AdminRolesPage**
|
|
|
|
```tsx
|
|
// src/pages/admin/AdminRolesPage.tsx
|
|
|
|
import { useState } from 'react';
|
|
import { AccessRulesEditor } from '../../components/AccessRules';
|
|
|
|
export const AdminRolesPage: React.FC = () => {
|
|
const [selectedRole, setSelectedRole] = useState<Role | null>(null);
|
|
|
|
return (
|
|
<div className={styles.twoColumnLayout}>
|
|
{/* Linke Spalte: Rollen-Liste */}
|
|
<div className={styles.roleList}>
|
|
<FormGeneratorTable
|
|
data={roles}
|
|
columns={columns}
|
|
actionButtons={[
|
|
{ type: 'view', onAction: setSelectedRole },
|
|
]}
|
|
/>
|
|
</div>
|
|
|
|
{/* Rechte Spalte: AccessRules Editor */}
|
|
{selectedRole && (
|
|
<AccessRulesEditor
|
|
roleId={selectedRole.id}
|
|
roleName={selectedRole.roleLabel}
|
|
isTemplate={!selectedRole.mandateId}
|
|
onSave={() => refetch()}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### 6.3 RBAC Export/Import in Admin-Seiten integrieren
|
|
|
|
**Beispiel: Standalone-Seite oder Modal**
|
|
|
|
```tsx
|
|
// src/pages/admin/AdminRbacExportImportPage.tsx
|
|
|
|
import { RbacExportImport } from '../../components/RbacExportImport';
|
|
|
|
export const AdminRbacExportImportPage: React.FC = () => {
|
|
const [selectedMandateId, setSelectedMandateId] = useState<string>('');
|
|
const { user } = useCurrentUser();
|
|
|
|
return (
|
|
<div className={styles.adminPage}>
|
|
<h1>RBAC Export/Import</h1>
|
|
|
|
{/* Mandant-Auswahl */}
|
|
<select
|
|
value={selectedMandateId}
|
|
onChange={(e) => setSelectedMandateId(e.target.value)}
|
|
>
|
|
<option value="">-- Mandant wählen --</option>
|
|
{mandates.map(m => (
|
|
<option key={m.id} value={m.id}>{m.name}</option>
|
|
))}
|
|
</select>
|
|
|
|
{/* Export/Import für gewählten Mandant */}
|
|
{selectedMandateId && (
|
|
<RbacExportImport
|
|
mandateId={selectedMandateId}
|
|
mandateName={mandates.find(m => m.id === selectedMandateId)?.name}
|
|
/>
|
|
)}
|
|
|
|
{/* Globale Templates (nur SysAdmin) */}
|
|
{user?.isSysAdmin && (
|
|
<div style={{ marginTop: '2rem' }}>
|
|
<h2>Globale Templates</h2>
|
|
<RbacExportImport isGlobal={true} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### 6.4 Mandate-Admin Navigation hinzufügen (Empfehlung)
|
|
|
|
**In `MandateNavigation.tsx` erweitern:**
|
|
|
|
```tsx
|
|
// Nach den Feature-Nodes pro Mandant:
|
|
|
|
function mandateToTreeNode(mandate: Mandate, userId: string): TreeNodeItem | null {
|
|
// ... bestehender Code ...
|
|
|
|
// Admin-Sektion für Mandate-Admins hinzufügen
|
|
const isMandateAdmin = checkMandateAdminRole(userId, mandate.id);
|
|
|
|
if (isMandateAdmin) {
|
|
children.push({
|
|
id: `${mandate.id}-admin`,
|
|
label: 'Administration',
|
|
icon: <FaCog />,
|
|
children: [
|
|
{ id: `${mandate.id}-admin-users`, label: 'Benutzer', path: `/mandates/${mandate.id}/admin/users` },
|
|
{ id: `${mandate.id}-admin-roles`, label: 'Rollen', path: `/mandates/${mandate.id}/admin/roles` },
|
|
{ id: `${mandate.id}-admin-instances`, label: 'Feature-Instanzen', path: `/mandates/${mandate.id}/admin/instances` },
|
|
{ id: `${mandate.id}-admin-rbac`, label: 'RBAC Export/Import', path: `/mandates/${mandate.id}/admin/rbac` },
|
|
],
|
|
});
|
|
}
|
|
|
|
return { /* ... */ };
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. API-Anbindung
|
|
|
|
### 7.1 Implementierte Endpoints
|
|
|
|
| Endpoint | Frontend-Verwendung |
|
|
|----------|---------------------|
|
|
| `GET /api/features/my` | `featuresApi.fetchMyFeatures()` |
|
|
| `GET /api/features/available` | `featuresApi.fetchAvailableFeatures()` |
|
|
| `GET /api/invitations/validate/:token` | `useInvitations().validateInvitation()` |
|
|
| `POST /api/invitations/accept/:token` | `useInvitations().acceptInvitation()` |
|
|
| `POST /api/invitations/register-and-accept` | `useInvitations().registerAndAccept()` |
|
|
| `GET /api/invitations/` | `useInvitations().fetchInvitations()` |
|
|
| `POST /api/invitations/` | `useInvitations().createInvitation()` |
|
|
| `DELETE /api/invitations/:id` | `useInvitations().revokeInvitation()` |
|
|
|
|
### 7.2 Neu implementierte Endpoint-Anbindungen
|
|
|
|
| Endpoint | UI-Komponente | Hook |
|
|
|----------|---------------|------|
|
|
| `GET /api/rbac/roles/:id/rules` | `AccessRulesEditor` | `useAccessRules` |
|
|
| `PUT /api/rbac/roles/:id/rules` | `AccessRulesEditor` | `useAccessRules` |
|
|
| `POST /api/rbac/roles/:id/rules` | `AccessRulesEditor` | `useAccessRules` |
|
|
| `PATCH /api/rbac/rules/:id` | `AccessRulesEditor` | `useAccessRules` |
|
|
| `DELETE /api/rbac/rules/:id` | `AccessRulesEditor` | `useAccessRules` |
|
|
| `GET /api/mandates/:id/rbac/export` | `RbacExportImport` | `useRbacExportImport` |
|
|
| `POST /api/mandates/:id/rbac/import` | `RbacExportImport` | `useRbacExportImport` |
|
|
| `GET /api/admin/rbac/global/export` | `RbacExportImport` | `useRbacExportImport` |
|
|
| `POST /api/admin/rbac/global/import` | `RbacExportImport` | `useRbacExportImport` |
|
|
| `GET /api/features/instances/:id/rbac/export` | `RbacExportImport` | `useRbacExportImport` |
|
|
|
|
### 7.3 Noch zu implementieren
|
|
|
|
| Endpoint | Fehlende UI-Komponente |
|
|
|----------|------------------------|
|
|
| `POST /api/features/instances/:id/sync-roles` | Sync-Button in Admin |
|
|
|
|
---
|
|
|
|
## 8. Zusammenfassung der Empfehlungen
|
|
|
|
### ✅ Abgeschlossen
|
|
1. **AccessRulesEditor** - Vollständig implementiert
|
|
2. **RBAC Export/Import UI** - Vollständig implementiert
|
|
|
|
### Priorität 1 (Hoch)
|
|
1. **Mandate-Admin Navigation** - Pro Mandant Admin-Bereich für Mandate-Admins
|
|
2. **Integration der neuen Komponenten** in bestehende Admin-Seiten
|
|
|
|
### Priorität 2 (Mittel)
|
|
3. **Template-Sync UI** - Button für Rollen-Synchronisation von Templates
|
|
4. **Admin-Route für RBAC Export/Import** hinzufügen
|
|
|
|
### Priorität 3 (Niedrig)
|
|
5. **Chatworkflow Views** - Aktuell nur Placeholder
|
|
6. **Chatbot Views** - Aktuell nur Placeholder
|
|
|
|
---
|
|
|
|
## 9. Checkliste für Feature-Entwickler
|
|
|
|
### 9.1 Beim Hinzufügen neuer Features
|
|
|
|
- [ ] Types in `types/mandate.ts` ergänzen
|
|
- [ ] View in `FEATURE_REGISTRY` registrieren
|
|
- [ ] Komponente in `VIEW_COMPONENTS` registrieren
|
|
- [ ] Route in `App.tsx` hinzufügen
|
|
- [ ] Permissions im Backend definieren (`trustee-newview`)
|
|
- [ ] API-Hook erstellen wenn nötig
|
|
- [ ] `FormGeneratorForm` für CRUD-Formulare nutzen
|
|
- [ ] `FormGeneratorTable` für Listen nutzen
|
|
- [ ] `PermissionGate` für bedingte UI-Elemente
|
|
- [ ] `useTablePermission` für Record-basierte Checks
|
|
|
|
### 9.2 Beim Arbeiten mit RBAC
|
|
|
|
- [ ] `AccessRulesEditor` für Rollen-Berechtigungen nutzen
|
|
- [ ] `RbacExportImport` für Backup/Migration nutzen
|
|
- [ ] `useAccessRules` Hook für programmatische RBAC-Verwaltung
|
|
- [ ] `useRbacExportImport` Hook für Export/Import-Logik
|
|
|
|
---
|
|
|
|
## 10. Neue Komponenten - Dateiübersicht
|
|
|
|
### 10.1 AccessRules
|
|
|
|
```
|
|
src/
|
|
├── hooks/
|
|
│ └── useAccessRules.ts // RBAC-Regeln Hook
|
|
└── components/
|
|
└── AccessRules/
|
|
├── AccessRulesEditor.tsx // Hauptkomponente
|
|
├── AccessLevelSelect.tsx // Dropdown für n/m/g/a
|
|
├── AccessRules.module.css // Styles
|
|
└── index.ts // Exports
|
|
```
|
|
|
|
### 10.2 RBAC Export/Import
|
|
|
|
```
|
|
src/
|
|
├── hooks/
|
|
│ └── useRbacExportImport.ts // Export/Import Hook
|
|
└── components/
|
|
└── RbacExportImport/
|
|
├── RbacExportImport.tsx // Hauptkomponente
|
|
├── RbacExportImport.module.css // Styles
|
|
└── index.ts // Exports
|
|
```
|