Files
Dashboard/HANDOVER.md
T
dejanandClaude Opus 5 831a6ec9ad Dashboard als Widget-Flaeche bauen, Platzhalter ersetzen
Das Dashboard ist ein eigenes Feature neben Analytics: der
Begruessungsbildschirm, nicht ein zweiter Analysebereich. Es zeigt heute nur
Auswertungen, ist aber so gebaut, dass die spaeteren Bereiche als weitere
Kacheln dazukommen und nicht als Umbau.

Aufbau: Begruessung, vier Kennzahlen (je ein Link in die Analyse),
Handlungsbedarf, vier Diagramme, drei reservierte Plaetze.

Drei Entscheidungen, die dabei getroffen wurden:

- Kein seitenweiter Filter. Jede Kachel traegt ihren eigenen Zeitraum und
  schreibt ihn in den Kopf. Das ist das Bedienmodell der Software (P11) und
  war die unbequemere Variante; eine Filterleiste haette beim Einbau alle
  Kacheln wieder auseinandergenommen.

- Das Raster ist aus DashboardPage.tsx der Software uebernommen, nicht
  erfunden: dieselben Klassen, dieselbe Ableitung aus size.w und position.x.
  Der Software fehlt dafuer eine Zeile (position.x === 9); vermerkt in
  WidgetRaster.tsx.

- Die reservierten Plaetze zeigen keine erfundenen Zahlen. "2 neue Antraege"
  aus dem Nichts liest sich in einer Abnahme wie eine fertige Funktion.

Absichtliche Doppelung: Der Handlungsbedarf steht jetzt auf dem Dashboard und
weiterhin auf der Analytics-Uebersicht. Ihn dort zu entfernen haette die
offene Frage 5.1 mitentschieden. Dokumentiert in Abschnitt 3a des
Scope-Papiers, aufzuloesen vor dem Port.

Nebenbei zwei Fehler behoben, die auch Analytics betrafen:

- Die Beschriftungen der Zeitachse liefen in schmalen Karten ineinander
  (fuenf Kalenderwochen brauchen 200px, eine halbe Kachel bei 768px hat 150).
  Recharts duennt sie jetzt selbst aus und haelt Anfang und Ende.

- Das Zeitraum-Etikett im Kachelkopf schaltete per Viewport-Breakpoint, die
  Kachelbreite haengt aber am Raster. Bei 1024px blieben dem Untertitel 77px,
  und er lief ins Diagramm. Jetzt Container-Query.

Die Wurzel leitet auf /dashboard statt /analytics — wie in der Software, wo
nach der Anmeldung der Begruessungsbildschirm steht.

tsc, lint, build, verify:carbon und verify:layout (7 Seiten x 9 Breiten)
laufen sauber.

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

145 lines
7.6 KiB
Markdown

# Übergabe an die Entwicklung
> **Rangfolge:** Wo dieser Prototyp von HiveGrid Cloud abweicht, **gilt
> HiveGrid** — Schrift, Schriftgrößen, Abstände, Farben, Control-Höhen,
> App-Shell. Dass hier dieselbe Schrift und dieselbe Seitenleisten-Komponente
> stecken, dient nur der Lesbarkeit neben der Software; es ist keine Vorlage,
> an der sich die Software auszurichten hätte. Verbindlich sind aus diesem Repo
> die Kennzahl-Definitionen, die Diagrammregeln, das Verhalten und die
> Navigationsstruktur als Verabredung. Ausführlich:
> [`docs/ZIELSYSTEM.md`](docs/ZIELSYSTEM.md) Abschnitt 0.
>
> **Ebenfalls vor dem Einbau lesen:**
> [`docs/SCOPE-ANALYTICS-DASHBOARD.md`](docs/SCOPE-ANALYTICS-DASHBOARD.md),
> insbesondere Abschnitt 3a. Der Handlungsbedarf steht dort **absichtlich
> doppelt** — auf dem Dashboard und auf der Analytics-Übersicht —, weil das
> Entfernen eine offene Produktfrage mitentschieden hätte. Das ist vor dem
> Port aufzulösen und nicht zu übernehmen.
Dieser Prototyp liefert **Gestaltung und Interaktion**, nicht die Anbindung.
Was echt ist, was Attrappe ist und was beim Einbau zu tun bleibt:
---
## 1. Was fertig ist und übernommen werden kann
| Bereich | Datei(en) | Zustand |
|---|---|---|
| Kennzahlen-Berechnung | `features/dashboard/data/calculations.ts` | **Reine Funktionen** über typisierten Eingangsdaten — direkt übernehmbar |
| Chart-Theme | `features/dashboard/utils/chartTheme.ts` | Carbon-Tokens, Palette, Achsen-Props, Margins |
| Formatierung | `features/dashboard/utils/formatters.ts` | Deutsche Zahlen-, Währungs- und Datumsformate |
| Chart-Komponenten | `features/dashboard/components/charts/` | Vollständig, mit Leerzuständen und Tooltips |
| Karten & Tabellen | `features/dashboard/components/cards/`, `tables/` | Vollständig |
| Filtersystem | `features/dashboard/context/FilterContext.tsx`, `data/filtering.ts` | State und Relevanzlogik fertig |
| Seitenaufbau | `features/dashboard/pages/` | **Reine Komponenten** `({ vm })` — kein Store-Zugriff, direkt übernehmbar |
| View-Model-Builder | `features/dashboard/view-models/*.vm.ts` | Reine Funktionen `(daten, filter) → VMState<…>`; im Loader wiederverwendbar |
| Seitenzustände | `components/layout/SeitenZustand.tsx` | idle · loading · empty · error ausgestaltet |
---
## 2. Was echte Logik braucht
### 2.1 Datenquelle austauschen
Alles hängt an **einer** Stelle: `features/dashboard/data/seed.ts` exportiert
`DATENSATZ` vom Typ `Datensatz`. Diesen Export durch echte Daten ersetzen —
Loader, Server-Query oder Service, je nach Architektur. Alle Berechnungen und
Komponenten arbeiten unverändert weiter.
Feldzuordnung zu den HiveGrid-Entities steht in [`docs/DATENMODELL.md`](docs/DATENMODELL.md).
**Achtung Zeitbezug:** `features/dashboard/utils/dateUtils.ts` definiert
`HEUTE` als festen Stichtag (30.07.2026), damit der Prototyp reproduzierbar
bleibt. Beim Einbau durch `new Date()` ersetzen — die Konstante wird an
elf Stellen verwendet, alle über den Import.
### 2.2 Filter serverseitig anwenden
Aktuell wird komplett clientseitig gefiltert (`data/filtering.ts`). Bei echten
Datenmengen gehört das in die Query. Der State im `FilterContext` lässt sich
dafür in URL-Parameter serialisieren; die Relevanzlogik (`FILTER_RELEVANZ`)
bleibt clientseitig, weil sie nur die Anzeige steuert.
### 2.3 Aktionen ohne Wirkung
Diese Elemente lösen bewusst nur einen Hinweis-Toast aus:
| Element | Wo | Erwartetes Verhalten |
|---|---|---|
| Export (Seitenkopf) | `components/layout/PageHeader.tsx` | PDF-/CSV-Export der Ansicht |
| Teilen | `components/layout/PageHeader.tsx` | Link mit eingefrorenen Filtern |
| Aktualisieren | `components/layout/PageHeader.tsx` | Daten neu laden |
| „Als Bild exportieren" | `components/cards/ChartCard.tsx` | PNG-Export des Charts |
| Einträge in „Handlungsbedarf" | `components/cards/AlertList.tsx` | Absprung in die jeweilige Arbeitsliste — die Handlung je Zeile (`aktion`) beschreibt, was dort passieren soll |
| Tabellenzeilen | `components/tables/DataTable.tsx` | Absprung auf den Datensatz |
| Suche und Glocke (Kopfzeile) | `components/layout/AppShell.tsx` | Attrappe, gehört zur bestehenden Shell |
### 2.4 Was funktioniert und erhalten bleiben sollte
- **Zeitraum-Umschaltung** rechnet alle Kennzahlen und Charts neu, inklusive Trendvergleich zur Vorperiode
- **Mehrfachfilter** (Gewerk, Status, Quelle, Region, Mitarbeiter) mit entfernbaren Chips
- **Seitenabhängige Filterrelevanz** — irrelevante Filter werden gar nicht erst angeboten
- **Widgets ausblenden** über das ⋯-Menü jeder Karte, Wiedereinblenden über die Filterleiste, persistiert
- **Tabellen** sortieren, durchsuchen, blättern
- **Hover** auf Balken, Ringsegmenten, Trichterstufen und Verlaufspunkten
- **Legenden im Ring** heben beim Klick das jeweilige Segment hervor
- **Tastaturbedienung**: sichtbarer Fokus auf allen interaktiven Elementen, Escape schließt Dropdown und Karten-Menü
Persistiert wird in `localStorage` unter `hivegrid.analytics.*`. In der echten
Software gehört das an das Benutzerprofil.
---
## 3. Bewusste Entscheidungen
**Recharts statt der Subframe-Chart-Komponenten.** Die Subframe-Wrapper
(`ui/components/AreaChart` etc.) geben zu wenig Kontrolle über Achsen, Tooltips
und Ringproportionen, um die Carbon-Regeln umzusetzen. Die übrige Oberfläche
nutzt weiterhin die Subframe-Bibliothek und deren Design-Tokens.
**Deterministische Dummy-Daten.** Fester Seed statt `Math.random()`: Die Zahlen
bleiben über Reloads und Screenshots identisch, sonst ist keine Abstimmung über
konkrete Werte möglich.
**Team-Seite enthalten,** obwohl die Planung sie für v2 vorgesehen hatte.
Auslastung ist im Handwerk die Kennzahl, nach der disponiert wird — ohne sie
fehlt dem Dashboard der Bezug zum Tagesgeschäft.
**Kein Dark Mode.** Die Carbon-Palette ist hier im Light Theme hinterlegt.
Ein Dark Theme braucht die zweite Palettenvariante (in `@carbon/charts`
enthalten) und eigene Kontrastprüfung — bewusst nicht angefangen, statt es
halb zu machen.
---
## 4. Empfohlene Reihenfolge beim Einbau
1. `data/types.ts` gegen die echten Entity-Typen abgleichen
2. `data/seed.ts` durch die echte Datenquelle ersetzen
3. `HEUTE` in `utils/dateUtils.ts` auf `new Date()` umstellen
4. `view-models/index.ts` gegen `@hivegrid/view-models` tauschen — der Vertrag
(`VMState`) ist wortgleich, es ist ein Import-Wechsel
5. Eine Seite vollständig durchziehen (Übersicht): Loader ruft
`baueUebersichtVM()`, die Route rendert `<UebersichtSeite vm={…} />`. Der
Container unter `routes/` entfällt dabei, die Seite bleibt unverändert.
Dabei zeigt sich, welche Felder in den echten Daten fehlen
6. Texte auf i18n-Keys ziehen, `data-ui-id` ergänzen, `mobile:`-Verhalten
nachrüsten (siehe `docs/LEITPLANKEN.md`)
7. Filter serverseitig nachziehen, sobald die Datenmengen es erfordern
8. Export, Absprünge und Persistenz am Benutzerprofil ergänzen
---
## 5. Offene Punkte für die Fachabstimmung
- **Auslastung** rechnet produktive Stunden gegen Vertragsstunden. Ob Rüst- und
Fahrzeiten als produktiv zählen, ist eine betriebliche Festlegung — die
Schwellen (70 % / 95 %) stehen in `components/charts/AuslastungsBalken.tsx`.
- **Umsatz** ist hier Zahlungseingang, nicht Rechnungsstellung. Für die
betriebswirtschaftliche Auswertung kann die andere Definition gewünscht sein;
beide Varianten sind aus denselben Daten berechenbar.
- **Deckungsbeitrag** basiert auf einer geschätzten Marge je Auftrag. Ob echte
Kostendaten vorliegen, ist offen.
- **Förderquote BAFA/KfW** ist als eigener Block angelegt, weil sie im
Wärmepumpengeschäft entscheidend ist. Sie braucht ein Feld am Auftrag.