wiki/z-archive/concepts/Navigation-API-Konzept.md

863 lines
24 KiB
Markdown

# Navigation API Konzept
## Übersicht
Dieses Dokument beschreibt das Konzept für die Navigation-API, welche dem UI alle notwendigen Informationen für das Rendering der Navigation liefert. Die API ist die **Single Source of Truth** für die Navigationsstruktur.
## Grundprinzipien
### 1. Backend liefert, UI rendert
- Das **Gateway** bestimmt, welche Navigationselemente ein User sehen darf
- Das **UI** rendert nur das, was es vom Gateway erhält
- Keine Permission-Logik im UI für Navigation
### 2. Trennung von Daten und Darstellung
- Die API liefert **keine Style-Elemente** (Icons, CSS-Klassen, etc.)
- Die API liefert **UI-Komponenten-Codes**, die das UI auf seine Komponenten mappt
- Verschiedene UIs können dieselben Daten unterschiedlich darstellen
### 3. Nur sichtbare Elemente
- Elemente ohne Zugriffsberechtigung werden **nicht** in den Baum aufgenommen
- Kein `hasAccess: false` - wenn kein Zugriff, dann nicht im Response
### 4. Fehlertoleranz
- Wenn ein Code im UI nicht gemappt werden kann → Fehlertext im Nav-Tree
- Synchronisationsprobleme zwischen Gateway und UI werden sofort sichtbar
### 5. Personalisierbare Sortierung
- Jedes Element hat eine `order` Nummer für die Sortierung
- User können die Reihenfolge anpassen durch User-Settings
- Gateway liefert bereits sortiert (Default + User-Override)
---
## API Response Struktur
### Endpoint
```
GET /api/navigation
```
### Response Format
```json
{
"language": "de",
"blocks": [
{
"type": "static",
"id": "system",
"title": "SYSTEM",
"order": 10,
"items": [...]
},
{
"type": "static",
"id": "workflows",
"title": "WORKFLOWS",
"order": 20,
"items": [...]
},
{
"type": "dynamic",
"id": "features",
"title": "FEATURES",
"order": 100,
"mandates": [...]
}
]
}
```
---
## Block-Typen
### Static Block
Für System-Seiten, die nicht an Feature-Instanzen gebunden sind.
```json
{
"type": "static",
"id": "system",
"title": "SYSTEM",
"order": 10,
"items": [
{
"uiComponent": "page.system.home",
"uiLabel": "Übersicht",
"uiPath": "/",
"order": 10,
"objectKey": "ui.system.home"
},
{
"uiComponent": "page.system.settings",
"uiLabel": "Einstellungen",
"uiPath": "/settings",
"order": 20,
"objectKey": "ui.system.settings"
}
]
}
```
**Felder pro Item:**
| Feld | Beschreibung |
|------|--------------|
| `uiComponent` | Eindeutiger Code für UI-Mapping (z.B. `page.system.home`) |
| `uiLabel` | Anzeigetext (bereits in der gewählten Sprache) |
| `uiPath` | URL-Pfad für Navigation |
| `order` | Sortierreihenfolge (Default oder User-Override) |
| `objectKey` | Vollqualifizierter RBAC-Objektname (für Debugging/Referenz) |
### Dynamic Block
Für Feature-Instanzen, gruppiert nach Mandanten.
```json
{
"type": "dynamic",
"id": "features",
"title": "FEATURES",
"order": 100,
"mandates": [
{
"id": "5ce04434-c4ce-4269-9861-19ff7ebc2a1d",
"uiLabel": "SOHA Treuhand AG",
"order": 10,
"features": [
{
"uiComponent": "feature.trustee",
"uiLabel": "Treuhand",
"order": 10,
"instances": [
{
"id": "2fc48f66-ad1b-4581-aa87-6aaa1e7c16e0",
"uiLabel": "ValueOn AG 2026",
"order": 10,
"views": [
{
"uiComponent": "page.feature.trustee.dashboard",
"uiLabel": "Übersicht",
"uiPath": "/mandates/5ce04434.../trustee/2fc48f66.../dashboard",
"order": 10,
"objectKey": "ui.feature.trustee.dashboard"
},
{
"uiComponent": "page.feature.trustee.positions",
"uiLabel": "Positionen",
"uiPath": "/mandates/5ce04434.../trustee/2fc48f66.../positions",
"order": 20,
"objectKey": "ui.feature.trustee.positions"
}
]
}
]
}
]
}
]
}
```
**Hinweis:** Der `dynamic` Block ist nur vorhanden, wenn der User mindestens eine Feature-Instanz hat.
**Sortierung auf allen Ebenen:**
- Mandanten: `mandates[].order`
- Features: `features[].order`
- Instanzen: `instances[].order`
- Views: `views[].order`
---
## User-Personalisierung (Order Override)
### Konzept
User können die Reihenfolge der Navigation anpassen. Die Einstellungen werden in den User-Settings gespeichert.
### User Settings Struktur
```json
{
"userId": "user-123",
"settings": {
"navOrder": {
"page.system.home": 10,
"page.system.prompts": 5,
"page.admin.users": 100,
"feature.trustee": 20,
"feature.realestate": 10,
"mandate.5ce04434-...": 5,
"instance.2fc48f66-...": 1
}
}
}
```
### Merge-Logik im Gateway
```
Effektive Order = User-Override ?? Default-Order ?? 50
```
1. Gateway lädt Default-Order aus Konfiguration
2. Gateway lädt User-Settings (falls vorhanden)
3. Für jedes Element: User-Order überschreibt Default
4. Sortierung erfolgt im Gateway, UI erhält bereits sortiert
### Sortier-Priorität
| Ebene | Key für navOrder | Beispiel |
|-------|------------------|----------|
| Block | Block-ID | `"system"`, `"workflows"`, `"features"` |
| Static Item | uiComponent | `"page.system.home"` |
| Mandate | `mandate.{id}` | `"mandate.5ce04434-..."` |
| Feature | uiComponent | `"feature.trustee"` |
| Instance | `instance.{id}` | `"instance.2fc48f66-..."` |
| View | uiComponent | `"page.feature.trustee.dashboard"` |
### API für Order-Update
```
PUT /api/user/settings/navOrder
Body: { "page.system.prompts": 5, "feature.trustee": 20 }
```
---
## Code-Konvention
### Statische Seiten
```
page.system.<page-name>
page.admin.<page-name>
```
Beispiele:
- `page.system.home`
- `page.system.settings`
- `page.system.prompts`
- `page.admin.users`
- `page.admin.mandates`
### Feature-Seiten
```
page.feature.<feature-code>.<view-name>
```
Beispiele:
- `page.feature.trustee.dashboard`
- `page.feature.trustee.positions`
- `page.feature.trustee.instance-roles`
- `page.feature.realestate.projects`
### Feature-Codes (für Gruppierung)
```
feature.<feature-code>
```
Beispiele:
- `feature.trustee`
- `feature.realestate`
- `feature.chatworkflow`
---
## ObjectKey-Konvention (RBAC)
Die `objectKey` werden für Access Rules verwendet und sind vollqualifiziert:
### UI Objekte
```
ui.system.<name> → System-Seiten
ui.admin.<name> → Admin-Seiten
ui.feature.<code>.<view> → Feature-Views
```
### DATA Objekte
```
data.system.<table> → System-Tabellen
data.feature.<code>.<table> → Feature-Tabellen
```
### RESOURCE Objekte
```
resource.system.<action> → System-Aktionen
resource.feature.<code>.<action> → Feature-Aktionen
```
---
## UI Mapping & Fehlerbehandlung
### UI Code Registry
Das UI definiert ein Mapping von Codes zu Komponenten:
```typescript
// frontend_nyla/src/config/pageRegistry.ts
export const PAGE_REGISTRY: Record<string, PageDefinition> = {
// Static pages
'page.system.home': {
component: HomePage,
icon: FaHome,
layout: 'default',
},
'page.system.settings': {
component: SettingsPage,
icon: FaCog,
layout: 'default',
},
'page.admin.users': {
component: AdminUsersPage,
icon: FaUsers,
layout: 'admin',
},
// Feature pages
'page.feature.trustee.dashboard': {
component: TrusteeDashboardView,
icon: FaChartBar,
layout: 'feature',
},
'page.feature.trustee.positions': {
component: TrusteePositionsView,
icon: FaListAlt,
layout: 'feature',
},
// ...
};
export const FEATURE_REGISTRY: Record<string, FeatureDefinition> = {
'feature.trustee': {
icon: FaBriefcase,
color: '#e74c3c',
},
'feature.realestate': {
icon: FaBuilding,
color: '#3498db',
},
};
```
### Fehlerbehandlung
Wenn ein `uiComponent` Code nicht gemappt werden kann:
```typescript
function renderNavItem(item: NavItem) {
const pageDef = PAGE_REGISTRY[item.uiComponent];
if (!pageDef) {
// Fehler sichtbar machen!
return (
<NavError>
⚠️ Unbekannter Code: {item.uiComponent}
<small>ObjectKey: {item.objectKey}</small>
</NavError>
);
}
return (
<NavLink to={item.uiPath} icon={pageDef.icon}>
{item.uiLabel}
</NavLink>
);
}
```
**Wichtig:** Fehler werden im Nav-Tree angezeigt, nicht versteckt! So werden Synchronisationsprobleme zwischen Gateway und UI sofort sichtbar.
### Sortierung im UI
Das UI sortiert die bereits vom Gateway sortierten Elemente NICHT neu. Die Sortierung erfolgt ausschliesslich im Gateway basierend auf:
1. Default-Order aus Konfiguration
2. User-Override aus Settings (falls vorhanden)
```typescript
// UI rendert in der Reihenfolge wie empfangen
function renderBlock(block: Block) {
// items sind bereits sortiert
return block.items.map(item => renderNavItem(item));
}
```
---
## Implementierungsschritte
### Phase 1: Gateway - Navigation Endpoint
1. **Neuer Endpoint** `/api/navigation` erstellen
2. **Static Blocks** aus `NAVIGATION_SECTIONS` generieren
3. **Dynamic Block** aus Feature-Instanzen generieren
4. **Permission-Filter** anwenden (nur sichtbare Elemente)
5. **uiComponent Codes** gemäß Konvention setzen
6. **Default-Order** für alle Elemente setzen
### Phase 2: Gateway - Access Rules
1. **TEMPLATE_ROLES** auf vollqualifizierte `objectKey` umstellen
2. **Permission-Check** auf `objectKey` umstellen
3. **Migration** bestehender Access Rules (falls nötig)
### Phase 3: Gateway - User Settings
1. **User Settings Modell** erweitern mit `navOrder`
2. **API Endpoint** `PUT /api/user/settings/navOrder` erstellen
3. **Merge-Logik** implementieren (User-Override → Default)
4. **Sortierung** vor Response durchführen
### Phase 4: Frontend
1. **PAGE_REGISTRY** erstellen mit uiComponent → Component Mapping
2. **FEATURE_REGISTRY** erstellen mit Feature-Code → Style Mapping
3. **useNavigation Hook** auf neuen Endpoint umstellen
4. **MandateNavigation** refactoren für neue Datenstruktur
5. **Fehlerhandling** für unbekannte uiComponents implementieren
### Phase 5: Frontend - Drag & Drop (Optional)
1. **Drag & Drop UI** für Nav-Tree Sortierung
2. **API Call** bei Order-Änderung
3. **Optimistic Update** für schnelle UX
### Phase 6: Cleanup
1. **FEATURE_REGISTRY** (alte Version in mandate.ts) entfernen
2. **Hardcodierte Navigation** im Frontend entfernen
3. **Tests** für Synchronisation Gateway ↔ UI
---
## Beispiel: Vollständige Response
```json
{
"language": "de",
"blocks": [
{
"type": "static",
"id": "system",
"title": "SYSTEM",
"order": 10,
"items": [
{
"uiComponent": "page.system.home",
"uiLabel": "Übersicht",
"uiPath": "/",
"order": 10,
"objectKey": "ui.system.home"
},
{
"uiComponent": "page.system.settings",
"uiLabel": "Einstellungen",
"uiPath": "/settings",
"order": 20,
"objectKey": "ui.system.settings"
}
]
},
{
"type": "static",
"id": "workflows",
"title": "WORKFLOWS",
"order": 20,
"items": [
{
"uiComponent": "page.system.playground",
"uiLabel": "Chat Playground",
"uiPath": "/workflows/playground",
"order": 10,
"objectKey": "ui.system.playground"
},
{
"uiComponent": "page.system.chats",
"uiLabel": "Chats",
"uiPath": "/workflows/list",
"order": 20,
"objectKey": "ui.system.chats"
}
]
},
{
"type": "static",
"id": "basedata",
"title": "BASISDATEN",
"order": 30,
"items": [
{
"uiComponent": "page.system.prompts",
"uiLabel": "Prompts",
"uiPath": "/basedata/prompts",
"order": 10,
"objectKey": "ui.system.prompts"
},
{
"uiComponent": "page.system.files",
"uiLabel": "Dateien",
"uiPath": "/basedata/files",
"order": 20,
"objectKey": "ui.system.files"
}
]
},
{
"type": "static",
"id": "admin",
"title": "ADMINISTRATION",
"order": 200,
"items": [
{
"uiComponent": "page.admin.users",
"uiLabel": "Benutzer",
"uiPath": "/admin/users",
"order": 10,
"objectKey": "ui.admin.users"
},
{
"uiComponent": "page.admin.mandates",
"uiLabel": "Mandanten",
"uiPath": "/admin/mandates",
"order": 20,
"objectKey": "ui.admin.mandates"
}
]
},
{
"type": "dynamic",
"id": "features",
"title": "MEINE FEATURES",
"order": 100,
"mandates": [
{
"id": "5ce04434-c4ce-4269-9861-19ff7ebc2a1d",
"uiLabel": "SOHA Treuhand AG",
"order": 10,
"features": [
{
"uiComponent": "feature.trustee",
"uiLabel": "Treuhand",
"order": 10,
"instances": [
{
"id": "2fc48f66-ad1b-4581-aa87-6aaa1e7c16e0",
"uiLabel": "ValueOn AG 2026",
"order": 10,
"views": [
{
"uiComponent": "page.feature.trustee.dashboard",
"uiLabel": "Übersicht",
"uiPath": "/mandates/5ce04434-c4ce-4269-9861-19ff7ebc2a1d/trustee/2fc48f66-ad1b-4581-aa87-6aaa1e7c16e0/dashboard",
"order": 10,
"objectKey": "ui.feature.trustee.dashboard"
},
{
"uiComponent": "page.feature.trustee.positions",
"uiLabel": "Positionen",
"uiPath": "/mandates/5ce04434-c4ce-4269-9861-19ff7ebc2a1d/trustee/2fc48f66-ad1b-4581-aa87-6aaa1e7c16e0/positions",
"order": 20,
"objectKey": "ui.feature.trustee.positions"
},
{
"uiComponent": "page.feature.trustee.documents",
"uiLabel": "Dokumente",
"uiPath": "/mandates/5ce04434-c4ce-4269-9861-19ff7ebc2a1d/trustee/2fc48f66-ad1b-4581-aa87-6aaa1e7c16e0/documents",
"order": 30,
"objectKey": "ui.feature.trustee.documents"
}
]
}
]
}
]
},
{
"id": "abc123-mandate-2",
"uiLabel": "Partner AG",
"order": 20,
"features": [
{
"uiComponent": "feature.realestate",
"uiLabel": "Immobilien",
"order": 10,
"instances": [
{
"id": "def456-instance",
"uiLabel": "Objektstudien ZH",
"order": 10,
"views": [
{
"uiComponent": "page.feature.realestate.dashboard",
"uiLabel": "Übersicht",
"uiPath": "/mandates/abc123-mandate-2/realestate/def456-instance/dashboard",
"order": 10,
"objectKey": "ui.feature.realestate.dashboard"
},
{
"uiComponent": "page.feature.realestate.projects",
"uiLabel": "Projekte",
"uiPath": "/mandates/abc123-mandate-2/realestate/def456-instance/projects",
"order": 20,
"objectKey": "ui.feature.realestate.projects"
}
]
}
]
}
]
}
]
}
]
}
```
---
## Vorteile dieses Ansatzes
1. **Single Source of Truth**: Gateway definiert, was sichtbar ist
2. **Keine Permission-Logik im UI**: Alles was kommt, wird gerendert
3. **Flexibles UI**: Verschiedene UIs können dieselben Daten anders darstellen
4. **Fehlertoleranz**: Synchronisationsprobleme werden sofort sichtbar
5. **Saubere Trennung**: Daten (Gateway) vs. Darstellung (UI)
6. **Testbarkeit**: API-Response kann einfach getestet werden
7. **Dokumentation**: Codes und ObjectKeys sind selbstdokumentierend
8. **Personalisierung**: User können Navigation individuell sortieren
9. **Konsistente Sortierung**: Gateway sortiert zentral, UI respektiert die Reihenfolge
---
## Offene Fragen (Beantwortet)
1. Soll der `dynamic` Block vor oder nach den `static` Blocks kommen? → **Diese initiale Reihenfolge: System, `<dynamic>`, workflows, basisdaten, migrate to features, administration**
2. Braucht es eine Versionierung der API für Breaking Changes? → **Nein**
3. Wie werden Feature-spezifische Sub-Navigationen behandelt (z.B. Tabs innerhalb einer View)? → **Tabs innerhalb einer View werden als separate Views behandelt**
4. Soll der Default-Order-Abstand 10 sein (erlaubt Einfügen zwischen Elementen)? → **Ja**
5. Soll die Order-Personalisierung auch für Admins pro Mandate/Feature-Instanz möglich sein (System-Default vs. User-Override)? → **Ja**
---
## Code-Analyse: IST-Zustand
### Gateway (Backend)
#### 1. `mainSystem.py` - Statische Navigation
```python
# IST: Items haben id, label, path, icon, objectKey
# NEU: Brauchen uiComponent, uiLabel, uiPath, order (ohne icon)
NAVIGATION_SECTIONS = [
{
"id": "system",
"order": 10, # ✓ Vorhanden
"items": [
{
"id": "home",
"objectKey": "ui.system.home", # ✓ Korrekt
"label": {"en": "Home", "de": "Übersicht"},
"icon": "FaHome", # ✗ Muss entfernt werden
"path": "/",
},
]
}
]
```
**Änderungen:**
- `icon` entfernen (UI mappt selbst)
- Item-Level `order` hinzufügen
- Felder umbenennen für API Response
#### 2. `routeSystem.py` - Navigation Endpoint
```python
# IST: GET /api/system/navigation
# Gibt zurück: { "sections": [...], "language": "de" }
# NEU: GET /api/navigation
# Soll zurückgeben: { "blocks": [...], "language": "de" }
```
**Änderungen:**
- Neuer kombinierter Endpoint
- Static Blocks + Dynamic Block zusammenführen
- Response-Struktur gemäss Konzept
#### 3. `mainTrustee.py` - Feature Views
```python
# IST: TEMPLATE_ROLES verwendet Kurznamen
TEMPLATE_ROLES = [
{
"roleLabel": "trustee-client",
"accessRules": [
{"context": "UI", "item": "dashboard", "view": True}, # ✗ Kurzname!
{"context": "UI", "item": "positions", "view": True}, # ✗ Kurzname!
]
}
]
# ABER: UI_OBJECTS verwendet vollqualifizierte Namen
UI_OBJECTS = [
{"objectKey": "ui.feature.trustee.dashboard", ...}, # ✓ Vollständig
]
```
**Inkonsistenz gefunden!** `item` in AccessRules muss `objectKey` entsprechen.
#### 4. `routeAdminFeatures.py` - Permission Logic
```python
# IST: _deriveViewPermissions ist TRUSTEE-spezifisch!
def _deriveViewPermissions(permissions):
# Hard-coded: TrusteePosition → positions view
# Hard-coded: TrusteeDocument → documents view
```
**Problem:** Nicht generisch, funktioniert nur für Trustee.
### Frontend (UI)
#### 1. `MandateNavigation.tsx`
```typescript
// IST: Zwei separate Datenquellen
const { sections } = useNavigation(); // Static von API
const mandates = useMandates(); // Dynamic von API
// IST: FEATURE_ICONS definiert im Frontend
const FEATURE_ICONS = { trustee: <FaBriefcase /> };
```
**Problem:** Navigation wird im Frontend zusammengebaut, nicht vom Backend.
#### 2. `mandate.ts` - FEATURE_REGISTRY
```typescript
// IST: Doppelte Definition von Views!
export const FEATURE_REGISTRY = {
trustee: {
views: [
{ code: 'dashboard', label: {...}, path: 'dashboard' }, // ✗ Kurzname
{ code: 'positions', label: {...}, path: 'positions' }, // ✗ Kurzname
]
}
};
```
**Duplizierung:** Views sind in `mainTrustee.py` UND `mandate.ts` definiert!
---
## Impact-Analyse
### Phase 1: Gateway - Navigation Endpoint
| Datei | Änderungstyp | Aufwand | Breaking |
|-------|--------------|---------|----------|
| `routeSystem.py` | Neu/Refactor | Hoch | Ja |
| `mainSystem.py` | Update | Mittel | Nein |
| `routeAdminFeatures.py` | Integrieren | Hoch | Nein |
**Konkrete Aufgaben:**
1. Neuen Endpoint `GET /api/navigation` erstellen
2. Static Blocks aus `NAVIGATION_SECTIONS` generieren
3. Dynamic Block aus `_getMyFeatureInstances`-Logik generieren
4. Permission-Filter auf beide anwenden
5. `icon` aus Response entfernen
6. Felder umbenennen: `label→uiLabel`, `path→uiPath`, neu `uiComponent`
7. `order` auf Item-Level hinzufügen
### Phase 2: Gateway - Access Rules Migration
| Datei | Änderungstyp | Aufwand | Breaking |
|-------|--------------|---------|----------|
| `mainTrustee.py` | Update | Mittel | Ja (DB) |
| `mainRealEstate.py` | Update | Mittel | Ja (DB) |
| Migration Script | Neu | Mittel | - |
**Konkrete Aufgaben:**
1. `TEMPLATE_ROLES.item` auf vollqualifizierte ObjectKeys umstellen
2. Migration: Bestehende AccessRules in DB aktualisieren
3. Permission-Check in `_checkUiPermission` anpassen
### Phase 3: Gateway - User Settings
| Datei | Änderungstyp | Aufwand | Breaking |
|-------|--------------|---------|----------|
| `datamodelUam.py` | Erweitern | Gering | Nein |
| `routeSystem.py` | Endpoint | Gering | Nein |
**Konkrete Aufgaben:**
1. `UserSettings` Tabelle oder JSON-Feld in User
2. `PUT /api/user/settings/navOrder` Endpoint
3. Merge-Logik in Navigation-Endpoint
### Phase 4: Frontend
| Datei | Änderungstyp | Aufwand | Breaking |
|-------|--------------|---------|----------|
| `pageRegistry.ts` | Neu | Hoch | - |
| `useNavigation.ts` | Refactor | Mittel | Ja |
| `MandateNavigation.tsx` | Refactor | Hoch | Ja |
| `mandate.ts` | Cleanup | Gering | Ja |
**Konkrete Aufgaben:**
1. `PAGE_REGISTRY` erstellen mit uiComponent → Component Mapping
2. `FEATURE_REGISTRY` mit `feature.*` Codes
3. `useNavigation` für neuen Endpoint anpassen
4. `MandateNavigation` für Blocks-Struktur refactoren
5. Error-Handling für unbekannte uiComponents
---
## Kritische Punkte
### 1. Breaking Changes
Die Umstellung erfordert **simultane Änderungen** in Gateway UND Frontend. Empfehlung:
- Feature-Flag für neuen Endpoint
- Alte Endpoints temporär behalten
- Frontend schrittweise migrieren
### 2. Datenbank-Migration
Bestehende AccessRules haben `item="dashboard"`, neu soll `item="ui.feature.trustee.dashboard"` sein.
```sql
-- Beispiel-Migration
UPDATE access_rules
SET item = 'ui.feature.trustee.' || item
WHERE role_id IN (SELECT id FROM roles WHERE feature_code = 'trustee')
AND context = 'UI'
AND item IS NOT NULL;
```
### 3. Performance
Navigation mit vielen Instanzen kann langsam werden. Empfehlungen:
- Response cachen pro User
- Cache invalidieren bei Permission-Änderungen
- Lazy-Loading für sehr grosse Deployments prüfen
### 4. Feature-spezifische View-Ableitung
`_deriveViewPermissions` ist Trustee-spezifisch. Optionen:
- **A)** Jedes Feature definiert seine Ableitungslogik
- **B)** Keine Ableitung, nur explizite UI-Rules
- **C)** Generische Mapping-Konfiguration pro Feature
**Empfehlung:** Option B - Explizite UI-Rules sind klarer und testbarer.
---
## Empfohlene Reihenfolge
1. **Schritt 1:** `PAGE_REGISTRY` im Frontend erstellen (unabhängig)
2. **Schritt 2:** Neuen `/api/navigation` Endpoint mit Feature-Flag
3. **Schritt 3:** Frontend auf neuen Endpoint umstellen
4. **Schritt 4:** AccessRules-Migration
5. **Schritt 5:** User-Settings für Order
6. **Schritt 6:** Alte Endpoints/Code entfernen