upd
This commit is contained in:
parent
5690e64dba
commit
b0ffd52556
1 changed files with 846 additions and 0 deletions
|
|
@ -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
|
||||
<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
|
||||
```
|
||||
Loading…
Reference in a new issue