Files
Dashboard/docs/LEITPLANKEN.md
T
dejanandClaude Opus 5 99be627dad refactor(dashboard): Seiten von der Datenquelle entkoppeln
Die Seiten holten ihre Zahlen selbst aus einem globalen Store. HiveGrid Cloud
verlangt reine Screens nach dem Muster <XPage vm={} actions={} /> — jede Seite
hätte beim Einbau auseinandergenommen werden müssen.

Neue Schichtung:

  view-models/<seite>.vm.ts   baue<Seite>VM(daten, filter) → VMState<…>
                              reine Funktion, kein React, kein Store
  pages/<Seite>.tsx           ({ vm, optionen }) → JSX      wird portiert
  routes/<Seite>Route.tsx     Store + Builder + Seite       wird ersetzt

view-models/index.ts spiegelt VMState wortgleich aus @hivegrid/view-models;
beim Einbau ist es ein Import-Wechsel. Der Loader ruft denselben Builder mit
echten Daten, die Seiten bleiben unberührt.

Dabei abgefallen: die fünf Seitenzustände (idle · loading · ready · empty ·
error) über SeitenZustand — bisher lief der Prototyp nur im Zustand "Daten da",
in der Cloud sind alle fünf DoD-Pflicht. Die Filterleiste bekommt ihre
Auswahllisten jetzt als Prop (in der Software die Facetten aus dem Loader)
statt sie selbst aus dem Datensatz zu ziehen.

Store- und Rohdatenzugriff gibt es damit ausschließlich in routes/. Alle sechs
Seiten rendern pixelgleich; typecheck, lint und build sind grün.

Nicht geändert: Next.js bleibt. Im gesamten Projekt gibt es vier
Next-spezifische Importe, alle in AppShell und app/layout — beide Dateien
entfallen beim Einbau ohnehin, weil die Cloud Shell und Root-Layout mitbringt.
Ein Framework-Wechsel wäre Aufwand ohne Ertrag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
2026-08-29 17:39:41 +02:00

217 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Leitplanken aus HiveGrid Cloud
Welche Bereiche der Zielanwendung bereits Davids finale Subframe-Screens tragen
und welche noch auf Interim-UI laufen — und was daraus für dieses Dashboard
verbindlich ist.
Warum die Unterscheidung zählt: Ein nachgezogener Screen ist eine
**Design-Entscheidung**, an der man sich ausrichten kann. Eine Interim-UI ist
eine **Notlösung des Devs** — sie kopieren hieße, einen Platzhalter zum Standard
zu erklären.
Stand der Auswertung: 2026-08-29 gegen den lokalen Repo-Stand.
---
## 1. Woran man es im Code erkennt
Der Repo pflegt dafür bewusste Marker. In absteigender Verlässlichkeit:
| Muster | Bedeutung |
|---|---|
| `Interim-UI (AD-28)` im Kopfkommentar | Optik ist ausdrücklich vorläufig |
| `design-nachzug` | offener Punkt — steht auch in sonst fertigen Screens für einzelne Reste |
| Kopfkommentar mit Subframe-Screen-ID (`WF-P8 S03`, `S02/S02L/S03/S05`), Page-UUID oder „gegen Davids Export vom …" | nachgezogen, Optik ist abgestimmt |
| `@subframe/sync-disable` in `apps/web/app/ui/**` | lokal geänderte Komponente, die der Sync nicht überschreiben darf |
Ein typischer Interim-Kopf (`projects/PipelineKanbanPage.tsx`):
> `// R-P8b (P8 configurable Kanban) Interim-UI (AD-28) — pipeline board screen`
> `// (D-KANBAN), composed from ~/ui …`
Ein typischer nachgezogener Kopf (`projects/ProjektListPage.tsx`):
> `// WF-P8 S03 "Projekt-Liste" — rebuilt against Davids Subframe export of`
> `// 2026-07-28 (page 5c5bdb0a-995e-4c22-aa8b-e48333c60297) …`
**Autoritativ ist aber die Liste, nicht der Kommentar:**
`.planning/SUBFRAME-FLOW-INVENTAR.md` trackt jeden Subframe-Flow mit Seitenzahl,
Owner und Stand. Der dortige Hinweis ist wichtig: Der Subframe-Sync pflegt nur
Components, Layouts und Theme — **Pages werden nie automatisch integriert**,
jeder Screen wird einzeln hinter der Loader/Action-Grenze verdrahtet.
**Grenze der Methode:** Ein fehlender Marker sagt nichts. Von 214
`*Page.tsx`-Dateien tragen 92 einen Interim-Marker, 36 einen Subframe-Bezug und
**86 gar keinen** — überwiegend Plattform-Admin (31) und Integrationen (13),
also interne Flächen mit niedrigem Politur-Druck.
---
## 2. Die Abgrenzung
### Nachgezogen — als Leitplanke brauchbar
| Bereich | Stand laut Inventar | Im Code |
|---|---|---|
| **Team-Chat** | 🟢 24 von 24 Screens integriert (Handoff 2026-08-08) | `screens/chat/` — kein einziger Interim-Marker |
| **Form-Builder** | ✅ integriert (PR #71) | `screens/forms/` — Kopf nennt „WF-P16, screens S02/S02L/S03/S05" |
| **Automation / Workflow-Editor** | 🟡 voller Delta-Nachzug (Davids „V1 Vollbild minimal") | `screens/automation/` — 6 Screens mit Subframe-Bezug, keiner interim |
| **Projekt-Pipelines** | 🟡 Kernstrecke S01–S07 integriert | `screens/projects/` — 7 nachgezogen, 4 noch interim (darunter das Kanban selbst) |
| **Aufgaben** | 🟡 Stufen 0–6 fertig | `screens/tasks/` — 2 nachgezogen, 1 interim |
| **Lead-Liste** | 🟡 Kernstrecke (`/leads` = S01, `/leads/inbox` = S02) | `screens/leads/` — 2 nachgezogen, 6 noch interim |
### Vollständig Interim — nicht als Vorbild nehmen
Kein einziger nachgezogener Screen: **HR** (21 Seiten), **Mobile-PWA** (19),
**CRM** (6), **Booking** (5), **DSGVO/Privacy** (5), **E-Mail-Postfach** (4),
**Files** (3), **Kalender** (2), **Audit** (2), Signatur, Plugins, Auth —
**und das Dashboard** (1).
### Noch gar nicht entworfen
Die zehn Auth-Flows (Login/2FA, Passwort-Reset, Set-Password, Admin-RBAC,
Signup, Konto löschen, 2FA verwalten, Passwort ändern, Workspace-Auswahl,
Profil & Sicherheit) stehen im Inventar auf ❌ offen — zusammen 44 Seiten.
Ergänzend: Die 30 Designer-Briefs unter `.planning/designer-briefs/` haben ihren
Block „Davids Delta" durchgehend **leer**. Die tatsächlichen Handoffs werden
über das Flow-Inventar und die Ticket-Docs geführt, nicht über die Briefs —
102 Ticket-Docs führen einen offenen `design-nachzug`.
---
## 3. Was daraus für dieses Dashboard folgt
### 3.1 KPI-Kachel: `StatsCard` ist gesetzt
Die nachgezogenen Screens benutzen durchgehend `~/ui/components/StatsCard`
(Billing-Übersicht, Zahlungsseite, Admin-Health, Admin-Jobs, Admin-Billing).
Die API ist knapp:
```tsx
<StatsCard
trend="neutral" | "positive" | "negative"
icon={<FeatherUsers />}
label={t("…")}
value={formatters.number(totalSeats)}
percentage={t("…")} // "" um den Slot abzuschalten
/>
```
Unsere `KPICard` kann mehr: Sparkline, Akzentfarbe, `richtungGut` (steigender
Wert ist je nach Kennzahl gut oder schlecht), Trendlabel, ⋯-Menü zum Ausblenden.
Das ist fachlich begründet — **aber es ist eine Abweichung vom gesetzten
Baustein.** Beim Einbau gibt es genau zwei saubere Wege:
1. `StatsCard` erweitern und die Datei mit `@subframe/sync-disable` schützen
(so wurde es dort schon einmal gemacht, siehe Kopf der Komponente), oder
2. die eigene Karte bewusst als lokale Komposition begründen.
Was nicht geht: eine zweite KPI-Kachel kommentarlos danebenstellen.
### 3.2 Raster: 16 px, mobil einspaltig
Das durchgängige Muster der nachgezogenen Screens:
```
mobile:grid-cols-1 grid w-full grid-cols-4 gap-4
```
`gap-4` = 16 px = unser Kartenabstand ✓. Das `mobile:`-Präfix ist der
hauseigene Breakpoint und in 44 Stellen belegt — unser Prototyp hat kein
Mobil-Verhalten und muss es beim Einbau ergänzen.
### 3.3 Filterleiste: `FilterBar` statt Eigenbau
`ProjektListPage`, `AutomationListPage`, `AutomationExecutionsPage`,
`FormsAdminPage` und die Betriebsmittel-Übersicht nutzen alle
`~/ui/components/FilterBar`. Unsere `AnalyticsToolbar` ist handgebautes
Tailwind — funktional gleichwertig, aber am gesetzten Baustein vorbei. Das ist
die auffälligste Stelle, an der der Prototyp beim Einbau umgestellt gehört.
Bemerkenswert: Die Betriebsmittel-Übersicht wurde 2026-08-19 genau in diese
Richtung überarbeitet — „auf kompakte Kennzahlen plus echte `FilterBar`
umgestellt". Kennzahlenreihe über Filterleiste über Liste ist dort also bereits
das etablierte Muster. Unser Seitenaufbau folgt derselben Logik.
### 3.4 Weitere Konventionen der fertigen Screens
- Seitenkopf über `PageShell` / `PageHeader` / `PageBody`, nie eigenes Chrome
- i18n mit Namespace: `t("billing:subscriptionOverview.summary.plan")`
- Screen-Komponente ist rein: `({ vm, actions })`, kein `useLoaderData`,
kein `useFetcher` — Navigation und Schreibpfade sind Callbacks
- Tabellen über `~/ui/components/Table`, Dichte über die Komponente wählen
---
## 4. Wo es keine Leitplanke gibt: die Diagramme
Recharts kommt im gesamten Repo an **drei** Stellen vor: die beiden
Dashboard-Diagramme und `leads/LeadAnalyticsPage.tsx`. Es gibt keine geteilte
Palette, kein Chart-Theme, keine Kategorienregel — die vorhandenen Diagramme
setzen ihre Farben direkt im JSX.
Auch Davids Standards decken das nicht ab:
`.planning/INTERIM-UI-DESIGN-STANDARDS.md` regelt Spacing, Control-Höhen,
Dialoggrößen und Zustände sehr genau, **Datenvisualisierung gar nicht**.
Für dieses Dashboard heißt das beides:
- Für Kacheln, Filter, Tabellen und Seitenaufbau **gibt es** einen Standard —
daran halten wir uns, statt ihn neu zu erfinden.
- Für Diagramme gibt es keinen. Was wir in
[DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) und `chartTheme.ts` festlegen, füllt eine
echte Lücke und wird im Zweifel zur Referenz für alle späteren Charts. Das ist
der wertvollste, aber auch der begründungspflichtigste Teil der Übergabe —
deshalb steht zu jeder Regel dort, warum sie so ist.
---
## 5. Selbst nachprüfen
```sh
cd <hivegrid-cloud>
# Interim-Screens
grep -rl "Interim-UI\|AD-28" apps/web/app/components/screens --include='*Page.tsx'
# nachgezogene Screens
grep -rl "Davids\|WF-P[0-9]" apps/web/app/components/screens --include='*Page.tsx'
# autoritative Flow-Liste
cat .planning/SUBFRAME-FLOW-INVENTAR.md
```
Die Zahlen in diesem Dokument sind eine Momentaufnahme. Das Flow-Inventar wird
fortgeschrieben (Stand dort: 2026-08-25, 12. Update) — vor einer Entscheidung
lieber neu zählen.
---
## 6. Wo dieser Prototyp bewusst abweicht
Ein Abgleich mit den nachgezogenen Cloud-Screens fördert drei Stellen zutage, an
denen dieser Prototyp anders arbeitet. Sie stehen hier, damit sie beim Einbau
als **Entscheidung** erkennbar sind und nicht als Versehen wegkorrigiert werden.
| Thema | Cloud | Hier | Begründung |
|---|---|---|---|
| **Zahlen in Tabellen** | linksbündig; `align-right` nur für die Aktionsspalte | rechtsbündig mit `tabular-nums` | IBM Carbon und die eigene Planung (`UI_UX_GUIDELINES.md` §2) verlangen es: Nur rechtsbündig stehen Tausenderstellen untereinander, und genau darum geht es in einem Analytics-Dashboard. Die Cloud-Tabellen zeigen überwiegend Text, nicht Beträge |
| **Filterleiste** | `~/ui` `FilterBar` mit Facetten-Slots | eigene `AnalyticsToolbar` | Der Prototyp braucht ein Zeitraum-Segment-Control, das die FilterBar nicht kennt. Beim Einbau ist das der erste Umbau — die Logik passt fast 1:1 auf `FacetFilterBar` |
| **Formatierung** | `locale/format.ts`, Prozent erwartet 0–1 | eigene `formatters.ts`, Prozent erwartet 0–100 | Der Prototyp hat keine i18n-Schicht. Beim Einbau ersetzen, aber die **Achsenformatierung** (`achsenFormat`, `nettesRaster`) hat dort kein Gegenstück und sollte mitkommen |
Umgekehrt übernommen wurden: keine Versalien in Spaltenköpfen, Raster mit 16 px
Abstand, Kennzahlenreihe über Filterleiste über Liste, Leerzustände an jeder
Visualisierung.
**Bereits umgesetzt:** Die Seiten sind reine `({ vm })`-Komponenten mit dem
wortgleich gespiegelten `VMState`-Vertrag, die Berechnung liegt in reinen
Buildern unter `view-models/`, und die fünf Seitenzustände sind ausgestaltet.
Store-Zugriff gibt es ausschließlich in `routes/` — genau der Schicht, die beim
Einbau durch den Loader ersetzt wird.
**Offen für den Einbau** (Portierungsarbeit, keine Gestaltung): Texte über
i18n-Keys, `mobile:`-Verhalten, `data-ui-id` auf allen Flächen, Textalternative
je Diagramm, `actions`-Callbacks statt Demo-Toasts. Details in
[ZIELSYSTEM.md](ZIELSYSTEM.md) Abschnitt 3.