docs(quick-260922-m1h): Hinweis bei gesperrter Kachel, Changelog und Entwicklerdoku
- eine Kachel ohne Bauteil (entfernter Typ oder gesperrtes Modul) zeigt statt des rohen Typnamens den Satz `widgets.unavailable`, zentriert und grau; Schluessel in de.json und en.json - Entwicklerdoku: neuer Abschnitt "Eine Kachel zum Modul" im Modul-Walkthrough — die drei verbliebenen Stellen und was eine Kachel mit moduleSlug automatisch tut - Changelog unter "Unveroeffentlicht - Geaendert" Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -400,6 +400,40 @@ Für ein Modul mit Unterrouten (Einstellungsseite, Verwaltungsansicht) orientier
|
||||
`dkv-fleet` oder `tender-radar` — beide haben zusätzliche `settings/page.tsx` bzw. weitere
|
||||
Unterverzeichnisse, die vom selben `layout.tsx` mitgedeckt werden.
|
||||
|
||||
### Eine Kachel zum Modul
|
||||
|
||||
Ein Modul kann zusätzlich als Kachel auf dem Dashboard erscheinen. Seit
|
||||
`quick-260922-m1h` sind dafür **drei** Stellen nötig (vorher waren es sieben):
|
||||
|
||||
1. **Die Kachel-Komponente schreiben** — `apps/web/src/components/dashboard/widgets/<name>-widget.tsx`,
|
||||
nimmt die `WidgetProps` aus `widget-registry.tsx` (`instanceId`, `config`, `isEditMode`) entgegen.
|
||||
2. **Den Typ eintragen** — in `WIDGET_TYPES` in `packages/shared/src/index.ts`. Gehört die Kachel zu
|
||||
einem Modul, zusätzlich `WIDGET_MODULE_SLUGS['<typ>'] = '<modul-slug>'` in derselben Datei. Das ist
|
||||
die einzige Liste: die API validiert `POST /dashboard/widgets` per `@IsIn` gegen genau sie, und
|
||||
das Frontend leitet Registry und Katalog davon ab.
|
||||
3. **Anmelden** — `registerWidget('<typ>', <Name>Widget)` in `apps/web/src/app/(portal)/page.tsx`,
|
||||
neben den übrigen Aufrufen. Der Aufruf steht dort und nicht in der Registry, weil die Kachel über
|
||||
den Wrapper wieder die Registry importiert — ein Import aus der Registry heraus wäre ein
|
||||
Zirkelimport.
|
||||
|
||||
Dazu kommen wie bei jeder Oberfläche die **Übersetzungsschlüssel** (`<typ>.name` und
|
||||
`<typ>.description` unter `widgets` in `de.json` **und** `en.json`), ein **Symbol** als Inline-SVG
|
||||
und die **Größenvorgaben** in `WIDGET_CONSTRAINTS` (`minW`/`minH` = kleinste noch bedienbare Kachel,
|
||||
`defaultW`/`defaultH` = Startgröße) — beides in `widget-registry.tsx`. Ein Test in
|
||||
`widget-registry.test.tsx` prüft, dass `WIDGET_TYPES`, Registry und Constraints deckungsgleich sind;
|
||||
vergisst man eine Stelle, schlägt er fehl.
|
||||
|
||||
**Was eine Kachel mit `moduleSlug` automatisch tut:** Sie verschwindet für Benutzer, die das Modul
|
||||
nicht nutzen dürfen — aus dem Katalog („Widget hinzufügen", `visibleWidgetTypes`) und aus dem
|
||||
Dashboard selbst. Ist die Modulliste unbekannt, weil ihr Abruf fehlschlug, bleibt die Kachel
|
||||
ebenfalls verborgen (fail-closed). Eine bereits angelegte Kachel eines gesperrten Moduls rendert
|
||||
nicht mehr leer, sondern zeigt den Hinweis `widgets.unavailable`.
|
||||
|
||||
**Wie beim Modul-Gate gilt auch hier:** Der Katalogfilter ist Komfort, nicht Zugriffskontrolle. Die
|
||||
verbindliche Prüfung sitzt serverseitig in `DashboardService.getWidgets()` (filtert Kacheln
|
||||
gesperrter Module fail-closed aus `GET /dashboard/widgets`) — und die Daten, die eine Modul-Kachel
|
||||
anzeigt, holt sie über die Endpunkte ihres Moduls, die `@UseModule('<slug>')` tragen müssen.
|
||||
|
||||
## Mandantentrennung
|
||||
|
||||
Der tatsächliche Mechanismus ist `TenantGuard` (`apps/api/src/tenant/tenant.guard.ts`), global als
|
||||
|
||||
Reference in New Issue
Block a user