364 lines
17 KiB
Markdown
364 lines
17 KiB
Markdown
|
|
# Dashboard Widgets – Designprinzipien (Extraktion)
|
|||
|
|
|
|||
|
|
**Status:** Analyse / Arbeitspapier
|
|||
|
|
**Stand:** 2026-07-04
|
|||
|
|
**Geltungsbereich:** Konfigurierbare Übersicht (Widget-Katalog, Layout, Entitlements, Frontend-Registry) — keine Chart-/Metrik-Berechnung
|
|||
|
|
|
|||
|
|
**Serie:** Designprinzipien für Produktfamilie · Dokument 7 von n
|
|||
|
|
**Vorgänger:** [UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md](./UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md)
|
|||
|
|
|
|||
|
|
**Kernkomponenten:**
|
|||
|
|
|
|||
|
|
| Bereich | Pfade |
|
|||
|
|
|---------|-------|
|
|||
|
|
| Katalog (SSoT) | `backend/widget_catalog.py` |
|
|||
|
|
| Layout-Schema | `backend/dashboard_layout_schema.py` |
|
|||
|
|
| Config-Validierung | `backend/dashboard_widget_config.py` |
|
|||
|
|
| Entitlements | `backend/dashboard_widget_entitlements.py`, `widget_feature_requirements_db.py` |
|
|||
|
|
| Produkt-Standard | `backend/system_dashboard_product_default.py` |
|
|||
|
|
| HTTP | `backend/routers/app_dashboard.py` |
|
|||
|
|
| Frontend-Registry | `frontend/src/widgetSystem/dashboardWidgetRegistry.jsx` |
|
|||
|
|
| Registrierung | `frontend/src/widgetSystem/registerDashboardWidgets.js` |
|
|||
|
|
| Layout-Editor | `frontend/src/pages/DashboardConfigurePage.jsx` |
|
|||
|
|
| Fehler-Isolation | `frontend/src/widgetSystem/WidgetErrorBoundary.jsx` |
|
|||
|
|
| Leitfaden | `DASHBOARD_WIDGETS_AGENT_GUIDE.md` |
|
|||
|
|
| Registry-Meta | [REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](./REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Modul
|
|||
|
|
|
|||
|
|
**Dashboard Widgets**
|
|||
|
|
|
|||
|
|
Erweiterbares System für **konfigurierbare Startübersicht**: Backend-Katalog definiert erlaubte Widget-IDs; Nutzer speichern Reihenfolge, Ein/Aus und optionale `config` pro Profil; Frontend rendert über eine lokale Komponenten-Registry.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Fachliche Verantwortung
|
|||
|
|
|
|||
|
|
Das Modul übernimmt:
|
|||
|
|
|
|||
|
|
1. **Widget-Katalog** — IDs, Titel, Beschreibung, optionale Feature-Anforderung (`requires_feature`).
|
|||
|
|
2. **Layout-Persistenz** — `profiles.dashboard_layout` (JSON v1: `{ version, widgets[] }`).
|
|||
|
|
3. **Validierung** — Erlaubte IDs, keine Duplikate, max. 32 Widgets, mindestens eines aktiv.
|
|||
|
|
4. **Pro-Widget-Config** — Whitelist pro Widget-ID; Normalisierung beim Speichern.
|
|||
|
|
5. **Standard-Layouts** — Code-Fallback (`DEFAULT_PRODUCT_DASHBOARD_WIDGET_IDS`), Admin-Override (`system_config`), Lab-Template (`DEFAULT_LAB_WIDGET_IDS`).
|
|||
|
|
6. **Entitlements** — `allowed` im Katalog; Layout bereinigt bei fehlender Berechtigung.
|
|||
|
|
7. **Frontend-Rendering** — Registry mappt Katalog-ID → React-Komponente + Props aus `layoutEntry.config`.
|
|||
|
|
8. **Nutzer-Konfigurator** — „Übersicht anpassen“ (Sortieren, Toggle, Config-Editoren).
|
|||
|
|
|
|||
|
|
Es übernimmt **nicht**:
|
|||
|
|
|
|||
|
|
- Berechnung von KPIs, Charts, Scores (→ Data Layer + Chart-Endpoints, siehe [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md))
|
|||
|
|
- Tier-/Subscription-Logik in Widgets (→ Feature System, siehe [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md))
|
|||
|
|
- Prompt-/KI-Ausführung (Widget zeigt nur UI; Pipeline läuft über eigene API)
|
|||
|
|
|
|||
|
|
### Datenfluss (Happy Path)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
WIDGET_CATALOG (Backend)
|
|||
|
|
→ GET /api/app/widgets/catalog (+ allowed via check_feature_access)
|
|||
|
|
→ GET /api/app/dashboard-layout
|
|||
|
|
→ coalesce_effective_layout (Profil oder Standard)
|
|||
|
|
→ merge_missing_catalog_widgets (neue IDs anhängen)
|
|||
|
|
→ apply_entitlements_to_layout_dict
|
|||
|
|
→ Frontend: ensureDashboardWidgetsRegistered()
|
|||
|
|
→ WidgetRenderer: enabled widgets → mapProps(layoutEntry.config) → Component
|
|||
|
|
→ PUT /api/app/dashboard-layout (Pydantic + Entitlements + speichern)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Layout-Eintrag (Struktur)
|
|||
|
|
|
|||
|
|
| Feld | Bedeutung |
|
|||
|
|
|------|-----------|
|
|||
|
|
| `id` | Muss in `WIDGET_CATALOG` existieren |
|
|||
|
|
| `enabled` | Sichtbar auf der Übersicht |
|
|||
|
|
| `config` | Optional; nur für whitelisted Widgets mit Inhalt erlaubt |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Administrierte vs. code-definierte Konfiguration
|
|||
|
|
|
|||
|
|
| Konfiguration | Speicherort | Wer pflegt? |
|
|||
|
|
|---------------|-------------|-------------|
|
|||
|
|
| Widget-IDs, Metadaten, Default-Aktivierung | `widget_catalog.py` | Entwickler |
|
|||
|
|
| Produkt-Standard-Layout (live) | `system_config.dashboard_product_default` | Admin |
|
|||
|
|
| Produkt-Standard (Fallback) | `DEFAULT_PRODUCT_DASHBOARD_WIDGET_IDS` | Entwickler |
|
|||
|
|
| Lab-/Editor-Standard | `DEFAULT_LAB_WIDGET_IDS` | Entwickler |
|
|||
|
|
| Nutzer-Layout | `profiles.dashboard_layout` | Nutzer |
|
|||
|
|
| Feature-Gate (Katalog) | `requires_feature` pro Eintrag | Entwickler |
|
|||
|
|
| Feature-Gate (Override) | `widget_feature_requirements` + Marker | Admin |
|
|||
|
|
| Config-Schema pro Widget | `dashboard_widget_config.py` | Entwickler |
|
|||
|
|
| React-Komponente | `registerDashboardWidgets.js` | Entwickler |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Designprinzipien
|
|||
|
|
|
|||
|
|
### 1. Backend-Katalog als Single Source of Truth für IDs
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `WIDGET_CATALOG` ist die einzige autoritative Liste erlaubter Widget-IDs; `ALLOWED_WIDGET_IDS` wird daraus abgeleitet — nicht manuell duplizieren. |
|
|||
|
|
| **Begründung** | Layout-Validator, API und Default-Layouts bleiben synchron; unbekannte IDs werden beim PUT abgewiesen. |
|
|||
|
|
| **Quelle** | `widget_catalog.py`; Agent-Guide §4 |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Frontend-Registry ist zweite manuelle Bindung (kein Build-Time-Gate). |
|
|||
|
|
|
|||
|
|
### 2. Dual Registry: Backend-Kanon + Frontend-Komponentenbindung
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Jede Katalog-ID braucht einen Eintrag in `registerDashboardWidget({ id, Component, mapProps })`; idempotent via `ensureDashboardWidgetsRegistered()`. |
|
|||
|
|
| **Begründung** | React-Komponenten können nicht im Python-Katalog leben; explizite Zuordnung hält Bundle tree-shakeable. |
|
|||
|
|
| **Quelle** | `registerDashboardWidgets.js`, `dashboardWidgetRegistry.jsx` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Fehlende Registrierung → Laufzeit „Unbekanntes Widget“, kein CI-Fail. |
|
|||
|
|
|
|||
|
|
### 3. Layout als versioniertes Profil-JSON
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Nutzer-Layout in `profiles.dashboard_layout`; Schema `version: 1`, Liste `{ id, enabled, config? }`. |
|
|||
|
|
| **Begründung** | Pro Profil anpassbar; Reset auf NULL → System-Standard. |
|
|||
|
|
| **Quelle** | `DashboardLayoutPayload`, `app_dashboard.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Nur v1; Schema-Evolution braucht Migrationspfad. |
|
|||
|
|
|
|||
|
|
### 4. Validierung an der API-Grenze (Pydantic)
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Jeder GET/PUT-Pfad normalisiert über `DashboardLayoutPayload`: Duplikat-IDs, unbekannte IDs, leeres Layout (kein enabled) → Fehler. |
|
|||
|
|
| **Begründung** | Keine korrupten Layouts in der DB; Frontend kann auf gültige Struktur vertrauen. |
|
|||
|
|
| **Quelle** | `dashboard_layout_schema.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Ungültiges gespeichertes Layout → Fallback auf Standard (`coalesce_effective_layout`). |
|
|||
|
|
|
|||
|
|
### 5. Config nur für explizit whitelisted Widgets
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `WIDGETS_ALLOWING_CONFIG`: Widgets **ohne** Eintrag dürfen nur leere `config` haben; sonst Validierungsfehler. |
|
|||
|
|
| **Begründung** | Verhindert unkontrollierte JSON-Blobs und stille Ignorierung unbekannter Keys. |
|
|||
|
|
| **Quelle** | `dashboard_widget_config.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Pro Widget heterogene Schemas (chart_days vs. KPI-Tiles vs. show_*-Booleans). |
|
|||
|
|
|
|||
|
|
### 6. Strikte Config-Keys (Whitelist, Normalisierung)
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Unbekannte Keys in `config` werden abgelehnt; bekannte Keys typgeprüft und normalisiert (z. B. `chart_days` 7–90, KPI max. 9 Kacheln). |
|
|||
|
|
| **Begründung** | Vorhersagbares Verhalten; Editor und Backend stimmen überein. |
|
|||
|
|
| **Quelle** | `_validate_chart_days_only`, `_validate_kpi_board_config`, History-Viz-Defaults |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Frontend-Normalizer (`bodyChartDays.js`, `*VizConfig.js`) teils parallel — Abweichungsrisiko. |
|
|||
|
|
|
|||
|
|
### 7. Config-Größenlimit
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `MAX_WIDGET_CONFIG_JSON_BYTES` (3072) — keine großen Blobs in Layout-JSON. |
|
|||
|
|
| **Begründung** | DB-Spalte und API-Payload bleiben schlank; Config = Präferenzen, nicht Datenspeicher. |
|
|||
|
|
| **Quelle** | `dashboard_widget_config.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | — |
|
|||
|
|
|
|||
|
|
### 8. Katalog-Erweiterung ohne Layout-Reset
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `merge_missing_catalog_widgets` hängt neue Katalog-IDs ans bestehende Layout an (`enabled: false`). |
|
|||
|
|
| **Begründung** | Nutzer müssen nach Deploy nicht resetten; „Übersicht anpassen“ zeigt neue Optionen. |
|
|||
|
|
| **Quelle** | `dashboard_layout_schema.py`; Agent-Guide |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Reihenfolge neuer Widgets immer am Ende. |
|
|||
|
|
|
|||
|
|
### 9. Mehrere Standard-Layouts (Produkt vs. Lab vs. Admin)
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | **Produkt:** `get_product_default_base_dict` (DB-Override oder `DEFAULT_PRODUCT_DASHBOARD_WIDGET_IDS`). **Lab:** `lab_default_layout_dict` für Editor/Reset. **Nutzer:** eigenes JSON oder NULL. |
|
|||
|
|
| **Begründung** | Onboarding-Default getrennt von Entwickler-/Lab-Template; Admin kann Produkt-Standard ohne Deploy ändern. |
|
|||
|
|
| **Quelle** | `system_dashboard_product_default.py`, `widget_catalog.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Feldname `lab_default_layout` historisch irreführend (Servertemplate, nicht nur Lab). |
|
|||
|
|
|
|||
|
|
### 10. Entitlements zentral, Widgets konsumieren nur `allowed`
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Sichtbarkeit über `check_feature_access` in `widget_id_allowed`; Katalog liefert `allowed` pro Zeile. Widgets/React duplizieren **keine** Tier-Logik. |
|
|||
|
|
| **Begründung** | Eine Wahrheit für „darf angezeigt werden“; spätere Feature-Cluster ohne Widget-Refactor. |
|
|||
|
|
| **Quelle** | `dashboard_widget_entitlements.py`; Agent-Guide §0 |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Inhalts-Endpoints (Charts, KI) brauchen **eigenes** Feature-Gate (Defense in Depth). |
|
|||
|
|
|
|||
|
|
### 11. Layout-Persistenz bereinigt nicht erlaubte Widgets
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `apply_entitlements_to_layout_dict`: bei fehlender Berechtigung `enabled: false`; mindestens `welcome` bleibt aktiv. GET und PUT wenden an. |
|
|||
|
|
| **Begründung** | Keine „gespeichert aber nie sichtbar“-Zombies; Downgrade/Tier-Wechsel degradieren gracefully. |
|
|||
|
|
| **Quelle** | `dashboard_widget_entitlements.py`, `app_dashboard.py` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Policy ist deaktivieren, nicht entfernen — IDs bleiben im JSON. |
|
|||
|
|
|
|||
|
|
### 12. DB-Override für Widget-Feature-Anforderungen
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Katalog-`requires_feature` ist Default; Admin kann per `dashboard_widget_requirement_custom` + `widget_feature_requirements` überschreiben (AND-Semantik). |
|
|||
|
|
| **Begründung** | Runtime-Anpassung ohne Code-Deploy; Marker-Zeile trennt Custom von Fallback. |
|
|||
|
|
| **Quelle** | `widget_feature_requirements_db.py`, Migration 041 |
|
|||
|
|
| **Tragfähigkeit** | **mittel–hoch** |
|
|||
|
|
| **Einschränkung** | Zwei Quellen (Code + DB) — Dokumentation und Admin-UI nötig. |
|
|||
|
|
|
|||
|
|
### 13. mapProps: Layout-Config → Komponenten-Props
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Registry-Eintrag mappt `ctx.layoutEntry.config` auf typisierte Props (`chartDays`, `kpiConfig`, `bodyHistoryVizConfig`, …). |
|
|||
|
|
| **Begründung** | Widget-Komponenten bleiben layout-agnostisch; Normalisierung an einer Stelle pro ID. |
|
|||
|
|
| **Quelle** | `registerDashboardWidgets.js` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Teilweise Normalisierung in Widget statt in `mapProps` (inkonsistent, aber dokumentiert). |
|
|||
|
|
|
|||
|
|
### 14. Refresh-Koordination über Context
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `refreshTick` + `requestRefresh()` im Render-Context; Widgets laden Daten bei Tick-Änderung neu; Aktionen (z. B. Schnelleingabe) rufen `requestRefresh`. |
|
|||
|
|
| **Begründung** | Kein globales State-Monster; gezielte Invalidierung nach Capture. |
|
|||
|
|
| **Quelle** | `dashboardWidgetRegistry.jsx`, Widget-Implementierungen |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Kein feingranulares Cache pro Widget. |
|
|||
|
|
|
|||
|
|
### 15. Fehler-Isolation pro Widget
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `WidgetErrorBoundary` um jede Instanz — Render-Fehler crashen nicht die ganze Übersicht. |
|
|||
|
|
| **Begründung** | Robuste PWA; ein defektes Chart blockiert nicht Gewicht-Eingabe. |
|
|||
|
|
| **Quelle** | `WidgetErrorBoundary.jsx` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Kein automatisches Retry/Reporting. |
|
|||
|
|
|
|||
|
|
### 16. Konfigurator filtert nach `allowed`
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | `DashboardConfigurePage` blendet Widgets mit `allowed === false` aus der bearbeitbaren Liste aus. |
|
|||
|
|
| **Begründung** | Nutzer sehen keine Optionen, die sie nicht nutzen dürfen (Agent-Guide A2). |
|
|||
|
|
| **Quelle** | `DashboardConfigurePage.jsx` |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Bereits gespeicherte disabled Einträge können im JSON verbleiben. |
|
|||
|
|
|
|||
|
|
### 17. Widgets konsumieren Data Layer, duplizieren keine Logik
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Chart-/KPI-Widgets rufen Chart-Endpoints bzw. API-Fassaden auf; Berechnungen leben in `data_layer/`, nicht in Widget-JS. |
|
|||
|
|
| **Begründung** | Gleiche Zahlen wie Verlauf, KI-Platzhalter und Export. |
|
|||
|
|
| **Quelle** | Layer-2b `*_history_viz`-Widgets; [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md) |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Legacy-Widgets unter `dashboard-widgets-legacy/` teils ältere Fetch-Pfade. |
|
|||
|
|
|
|||
|
|
### 18. Dedizierte Config-Editoren für komplexe Widgets
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Prinzip** | Einfache `chart_days`: Set `CHART_DAYS_WIDGET_IDS` im Layout-Editor; komplexe Config: eigene Editor-Komponenten (`KpiBoardConfigEditor`, `*VizConfigEditor`). |
|
|||
|
|
| **Begründung** | UX skaliert mit Config-Komplexität; Backend-Schema und Editor bleiben parallel pflegbar. |
|
|||
|
|
| **Quelle** | `widgetSystem/*ConfigEditor.jsx`, Agent-Guide §3.4 |
|
|||
|
|
| **Tragfähigkeit** | **hoch** |
|
|||
|
|
| **Einschränkung** | Jedes neue komplexe Widget = Editor + Validator + Tests. |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Nicht übernehmen
|
|||
|
|
|
|||
|
|
1. **Tier-Logik in React-Widgets** — nur `allowed` aus API; keine hardcodierten Plan-Namen.
|
|||
|
|
|
|||
|
|
2. **`ALLOWED_WIDGET_IDS` manuell pflegen** — immer aus Katalog ableiten.
|
|||
|
|
|
|||
|
|
3. **Config ohne Backend-Whitelist** — stille Ignorierung unbekannter Keys in Widgets.
|
|||
|
|
|
|||
|
|
4. **Nur UI-Gating ohne API-Absicherung** — Chart-/KI-/Export-Endpoints weiterhin `check_feature_access` (403).
|
|||
|
|
|
|||
|
|
5. **Frontend-Registry vergessen** — Katalog-Eintrag ohne `registerDashboardWidget` → Laufzeitfehler statt Build-Fail.
|
|||
|
|
|
|||
|
|
6. **Große Daten in `config`** — Layout ist Präferenzspeicher, kein Blob-Store (>3072 Bytes).
|
|||
|
|
|
|||
|
|
7. **Doppelte Widget-IDs im Layout** — Validator verbietet; Editor muss dasselbe erzwingen.
|
|||
|
|
|
|||
|
|
8. **Neue Katalog-IDs ohne `merge_missing_catalog_widgets`-Pfad** — Nutzer-Layouts veralten unsichtbar.
|
|||
|
|
|
|||
|
|
9. **Kompletter Katalog nur in DB** — schwer testbar; Code-Katalog + optionale Feature-Overrides ist das Muster.
|
|||
|
|
|
|||
|
|
10. **Evidence-Pflicht à la Placeholder-Registry** — 22 Metadatenfelder pro Widget wären Overkill; Tiefe an Risiko anpassen ([REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](./REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md)).
|
|||
|
|
|
|||
|
|
11. **Ein Default für alles** — Produkt-Onboarding, Lab-Template und Admin-Override haben unterschiedliche Zwecke; nicht vermischen.
|
|||
|
|
|
|||
|
|
12. **Fehlender Cross-Check Backend ↔ Frontend IDs** — empfohener Test/Gate fehlt im Ist-Stand; nicht als „optional“ ignorieren.
|
|||
|
|
|
|||
|
|
13. **Berechnungslogik im Widget** — KPIs/Scores gehören in Data Layer, nicht in `useEffect`-Mathe.
|
|||
|
|
|
|||
|
|
14. **Entitlements beim Speichern ablehnen statt deaktivieren** — Mitai wählt deaktivieren; Policy bewusst festlegen und dokumentieren.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Modul-Inventar (Ist-Stand)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
backend/
|
|||
|
|
├── widget_catalog.py # WIDGET_CATALOG, DEFAULT_*_IDS
|
|||
|
|
├── dashboard_layout_schema.py # Pydantic, merge_missing, defaults
|
|||
|
|
├── dashboard_widget_config.py # WIDGETS_ALLOWING_CONFIG, Validatoren
|
|||
|
|
├── dashboard_widget_entitlements.py # allowed, layout cleanup
|
|||
|
|
├── widget_feature_requirements_db.py # Admin-Override
|
|||
|
|
├── system_dashboard_product_default.py
|
|||
|
|
└── routers/app_dashboard.py
|
|||
|
|
|
|||
|
|
frontend/src/
|
|||
|
|
├── widgetSystem/
|
|||
|
|
│ ├── dashboardWidgetRegistry.jsx
|
|||
|
|
│ ├── registerDashboardWidgets.js
|
|||
|
|
│ ├── layoutEditor.js
|
|||
|
|
│ ├── bodyChartDays.js, *VizConfig.js
|
|||
|
|
│ └── *ConfigEditor.jsx
|
|||
|
|
├── components/dashboard-widgets/ # Produkt-Widgets
|
|||
|
|
├── components/dashboard-widgets-legacy/ # ältere Kern-Widgets
|
|||
|
|
└── pages/DashboardConfigurePage.jsx
|
|||
|
|
|
|||
|
|
DB:
|
|||
|
|
├── profiles.dashboard_layout
|
|||
|
|
├── system_config.dashboard_product_default
|
|||
|
|
├── dashboard_widget_requirement_custom
|
|||
|
|
└── widget_feature_requirements
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Katalog-Umfang:** ~24 Widget-IDs (Stand `widget_catalog.py`); ~13 mit konfigurierbarer `config`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Verwandte Dokumentation
|
|||
|
|
|
|||
|
|
- Agent-Guide (normativ): [DASHBOARD_WIDGETS_AGENT_GUIDE.md](../../technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md)
|
|||
|
|
- Registry-Meta: [REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](./REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md)
|
|||
|
|
- Feature-Gates: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md)
|
|||
|
|
- Datenberechnung: [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md)
|
|||
|
|
- Architektur §9: `.claude/rules/ARCHITECTURE.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Geplante Folgedokumente (Serie)
|
|||
|
|
|
|||
|
|
| # | Modul | Status |
|
|||
|
|
|---|-------|--------|
|
|||
|
|
| 1–6 | … | ✅ |
|
|||
|
|
| 7 | Dashboard Widgets | ✅ dieses Dokument |
|
|||
|
|
| 8 | Navigation / IA | ✅ |
|
|||
|
|
| 9 | Migration & Deploy | ✅ |
|