Files
Dashboard/docs/ZIELSYSTEM.md
T
dejanandClaude Opus 5 6a0b36ddcc Geviertstriche aus Text, Kommentaren und Doku entfernen
467 Stellen. Nicht durch einen anderen Strich ersetzt, sondern durch das
Satzzeichen, das an der jeweiligen Stelle richtig ist: Doppelpunkt, wo eine
Erlaeuterung folgt; Komma, wo der Satz weiterlaeuft; Punkt, wo zwei
Hauptsaetze aneinanderstiessen. Ein Halbgeviertstrich waere nur derselbe
Griff mit kuerzerem Strich gewesen.

Regelbasiert ersetzt und danach nachgeprueft, weil eine Regel allein nicht
reicht. Gefunden und einzeln korrigiert:

- Eingeschobene Saetze mit Strichpaar. Nur der oeffnende Strich passte ins
  Muster, der schliessende blieb als "—," stehen. Drei Stellen, jetzt mit
  Klammern oder als eigener Satz.

- Doppelte Doppelpunkte, wo beide Striche eines Paars zu Doppelpunkten wurden
  ("Globale Regeln: Schrift, Groessen, Abstaende: kommen aus HiveGrid").
  Sieben Stellen in Doku und Oberflaeche, jetzt in Klammern.

- Pfade, denen ein Komma statt eines Doppelpunkts folgte.

- Ausgerichtete Kommentartabellen, in denen der Strich eine Spalte war.

Nicht angefasst: drei Geviertstriche, die keine Prosa sind, sondern
Tabellenplatzhalter fuer "kein Wert" (Trichter, Auftraege, Kunden). Dort ist
der Strich die Angabe selbst; ihn zu entfernen liesse leere Zellen zurueck.

tsc, lint, build, verify:carbon und verify:layout laufen sauber.

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

17 KiB

Zielsystem: HiveGrid Cloud

Wohin dieser Prototyp eingebaut wird, was dort heute schon steht und was beim Einbau konkret anzupassen ist.

Repo: HiveGrid-Cloud (Gitea git.tool-ctrl.de/toolctrl-labs/HiveGrid-Cloud). pnpm-Monorepo, React Router 7, Prisma/Postgres, mandantenfähig mit RLS. apps/web (Tenant- und Admin-App), dazu api, worker, desktop, hocuspocus, portal-domain-controller und rund 40 Pakete unter packages/. Größenordnung: 678 Route-Dateien, davon 575 im Core-Manifest.


0. Rangfolge beim Einbau: HiveGrid gewinnt

Dieser Prototyp ist nachrangig. Wo er von HiveGrid Cloud abweicht, gilt HiveGrid, ohne Rückfrage, ohne Ausnahme. Das betrifft alles Globale:

Wer bestimmt
Schrift, Schriftgrößen, Zeilenhöhen HiveGrid
Abstände, Paddings, Margins, Raster HiveGrid
Farben der Oberfläche, Rahmen, Radien, Schatten HiveGrid
Control-Höhen, Komponentenvarianten, Zustände HiveGrid
App-Shell, Seitenleiste, Kopfzeile, Seitenkopf HiveGrid
i18n, Formatierung, Zeitzone HiveGrid

Dass dieser Prototyp dieselbe Schrift, dieselbe Seitenleisten-Komponente und dieselben Token benutzt, hat einen einzigen Zweck: Er soll neben der Software lesbar sein und nicht wie ein Fremdkörper wirken. Es ist keine Vorlage, an der sich die Software auszurichten hätte. Fällt beim Einbau auf, dass hier ein Wert von HiveGrid abweicht, ist der Wert hier falsch, nicht dort.

Was aus diesem Repo verbindlich ist

Nur das Fachliche und das Analytics-Eigene:

  1. Die Navigationsstruktur als Verabredung: zwei Einträge in der Seitenleiste (Dashboard, Analytics), und Analytics trägt eine innere Leiste mit den fünf Analyse-Seiten. Verbindlich ist die Struktur, nicht ihre Umsetzung hier: In der Software werden diese zwei Einträge in die bestehende AppSidebar eingehängt und die innere Leiste über das dortige SidebarIconsLayout gebaut. Unser Nachbau ist die Beschreibung, nicht das Bauteil.
  2. Kennzahl-Definitionen (KPI-KATALOG.md), was gerechnet wird, mit welchem Zeitbezug.
  3. Diagrammregeln (DESIGN-SYSTEM.md): Palette, Achsen, Diagrammwahl, Leerzustände. Das ist die Lücke, die HiveGrid heute nicht füllt (siehe LEITPLANKEN.md Abschnitt 4).
  4. Verhalten: Filterlogik, Zeitbezüge, Widget-Sichtbarkeit, Sortier- und Blätterverhalten.

Was aus diesem Repo Gerüst ist und wegfällt

components/layout/AppShell.tsx, unsere Kopie der Seitenleiste, PageHeader, die Kopfzeile mit Suche und Glocke, die Routen unter app/ und die Attrappe des angemeldeten Benutzers (data/nutzer.ts). All das existiert, damit der Prototyp alleine lauffähig und beurteilbar ist. Beim Einbau übernehmen SubframeAppShell, AppSidebar, PageShell, requireMember und die Loader der Software.

Das Kachelraster des Dashboards ist die Ausnahme in dieser Liste: Es ist kein Gerüst, sondern aus DashboardPage.tsx der Software übernommen, dieselben Klassen, dieselbe Ableitung aus size.w und position.x. Es fällt nicht weg, es trifft dort auf sein Original.

Kurz: Aus diesem Repo kommt der Inhalt des Analytics-Bereichs, der Aufbau des Dashboards und die Verabredung, wo beide in der Navigation sitzen. Alles andere kommt aus HiveGrid.


1. Der Platz dieses Prototyps

Das Ziel ist der Tenant-Dashboard-Screen unter …/<tenant>/dashboard. Dort liegt bereits eine Implementierung:

Datei Was drin steht
apps/web/app/components/screens/dashboard/DashboardPage.tsx Widget-Grid, 495 Zeilen
…/DashboardEditPanel.tsx Edit-Modus (Widget-Filter/Zeitraum)
…/DashboardDrilldownDialog.tsx Drilldown je Kachel
…/DashboardMonthlySeriesChart.tsx, …/DashboardStageDistributionChart.tsx die zwei vorhandenen Diagramme
apps/web/app/routes/app.$tenant/dashboard.tsx Loader, SSE-Stream, Export

Fachlich ist das die Phase P11 (Modul M20): drei feste Rollen-Layouts (GF · Büro · Monteur) aus einer Widget-Registry, live über SSE, plus das Komfort-Delta aus P30 (Edit-Modus, Drilldown, CSV-/Report-Export, Realtime-Opt-out).

Wichtig: Dieser Stand ist ausdrücklich Interim-UI nach AD-28, der Dev baut aus ~/ui gegen ein stabiles View-Model, damit das Ticket nicht auf den finalen Screen wartet. Der Kommentarkopf von DashboardPage.tsx sagt es wörtlich: „Final Subframe optics = tracked design-nachzug (D-DASH / VD-P30)."

Genau diese Lücke füllt dieser Prototyp. Der Einbau ist der geplante Nachzug, kein Umbau gegen den Strom.


2. Gemeinsame Basis, und wo sie auseinanderläuft

Prototyp HiveGrid Cloud
Subframe-Projekt f023064a5ca0 f023064a5ca0: dasselbe
Bibliothek ui/, 86 Komponenten apps/web/app/ui/, Alias ~/ui/*, 92 Komponenten
Überschneidung 82 Komponenten gleich benannt dieselben 82
Diagramme Recharts ^2.15.4 Recharts ^2.15.3: dieselbe Bibliothek
Framework Next.js 16 React Router 7

Die vier Namensunterschiede: DialogFullscreen → FullscreenDialog, DrawerRight → Drawer, AddressDialog und BannerOffline existieren dort nicht. Cloud hat zusätzlich BulkActionBar, ConfirmDialog, DropdownMenu, ModalBlank, ResultDialog, BannerPermanent, ChatSprechblase.

Dass Komponentenbibliothek und Chart-Bibliothek übereinstimmen, ist der Grund, warum der Einbau realistisch ein Port ist und keine Neuimplementierung.


3. Was beim Einbau konkret anders wird

3.1 Daten kommen als View-Model-Prop: bereits umgesetzt

Das ist im Prototyp schon so gebaut. Jede Analyse-Seite ist eine reine Komponente:

export function UebersichtSeite({ vm }: { vm: VMState<UebersichtDaten> }) {
  if (vm.status !== "ready") return <SeitenZustand vm={vm} />;
  const d = vm.data;
  …
}

Die Verdrahtung sitzt in einem eigenen Container unter features/dashboard/routes/, die Berechnung in einem reinen Builder unter features/dashboard/view-models/:

view-models/uebersicht.vm.ts   baueUebersichtVM(daten, filter) → VMState<UebersichtDaten>
pages/UebersichtSeite.tsx      ({ vm }) → JSX          ← das ist der Teil, der portiert wird
routes/UebersichtRoute.tsx     Store + Builder + Seite ← das ist der Teil, der ersetzt wird
app/page.tsx                   rendert den Container

Beim Einbau tritt der Loader an die Stelle des Containers:

// apps/web/app/routes/app.$tenant/dashboard.tsx
export default function Route() {
  const { vm } = useLoaderData<LoaderData>();
  return <UebersichtSeite vm={vm} actions={{ onAbsprung }} />;
}

features/dashboard/view-models/index.ts spiegelt VMState wortgleich aus @hivegrid/view-models. Der Import wird getauscht, die Seiten bleiben unberührt. Die fünf Zustände (idle · loading · ready · empty · error) sind über SeitenZustand bereits ausgestaltet.

export type DashboardPageVM = VMState<DashboardPageData>;

type VMState<T> =
  | { status: "idle" }
  | { status: "loading"; data?: T }
  | { status: "ready"; data: T }
  | { status: "empty" }
  | { status: "error"; data?: T; error: { messageKey: string; code?: string } };

Fünf Zustände statt einem. Der Prototyp kennt nur „Daten da"; loading, empty und error sind je Seite zu ergänzen. Die Chart-Leerzustände (ChartLeer) decken davon nur einen Teil ab.

Was der Builder noch nicht kennt: DashboardPageData führt in der Cloud zusätzlich activeRole, layout, generatedAt, streamUrl, canCustomize, liveUpdatesEnabled, layoutSource und catalog. Das Dashboard ist dort rollen- und berechtigungsabhängig, diese Felder kommen beim Einbau dazu.

3.1a Warum der Prototyp auf Next.js bleibt

Die Frage liegt nahe, weil die Software auf React Router 7 läuft. Ein Umbau brächte aber nichts: Im gesamten Prototyp gibt es vier Next-spezifische Importe, alle in zwei Dateien,

Datei Import Schicksal beim Einbau
components/layout/AppShell.tsx next/link, next/navigation entfällt, die Cloud bringt Shell und Sidebar mit
app/layout.tsx next, next/font/google entfällt, Root-Layout gehört der Cloud

Portiert wird nicht die Anwendung, sondern der Ordner features/dashboard/{pages,components,view-models,utils}, und der enthält keine Framework-Bindung. React 19, Tailwind v4 und Recharts sind in beiden Repos dieselben. Ein Framework-Wechsel im Prototyp wäre Aufwand ohne Ertrag und würde die Gestaltungsarbeit nur verzögern.

3.1b Wo die Analyse in der Navigation landet: offen

Die Seitenleiste des Prototyps ist Gerüst, kein Vorschlag. Sie existiert nur, damit die Seiten einzeln aufrufbar sind, und entfällt beim Einbau (siehe 3.2). Wohin die fünf Analyse-Seiten in der echten Navigation gehören, ist noch nicht entschieden.

Der Stand in der Software: Die Seitenleiste hat sechs Gruppen, Start (Dashboard, Aufgaben) · Kunden · Projekte · Kommunikation · Organisation · Automatisierung. Eine Analyse-Gruppe gibt es nicht. Es gibt aber bereits zwei konkurrierende Muster:

Muster Beispiel Charakter
Rollen-Dashboard als Startseite /dashboard (P11/P30) Widgets, drei Rollen-Layouts, „wie ist meine Lage"
Analyse innerhalb der Fachdomäne leads/analytics: existiert bereits vertieft genau eine Domäne

Dieser Prototyp schlägt implizit ein drittes Muster vor: einen domänenübergreifenden Analysebereich mit gemeinsamem Zeitraum- und Dimensionsfilter.

Drei Optionen:

  1. Eigene Gruppe „Analyse" neben Kunden/Projekte/Kommunikation, mit den fünf Seiten darin. Dafür: Die Seiten teilen sich einen Filterzustand und eine Leseführung (Übersicht → Detail). Finanzen greift über Projekte, Rechnungen und Kontakte hinweg und passt in keine einzelne Domäne. Dagegen: eine siebte Gruppe in einer schon langen Seitenleiste.
  2. Verteilt in die Domänen: Finanzen unter Projekte, Kunden-Analyse unter Kunden, analog zu leads/analytics. Dafür: folgt dem bestehenden Muster, keine neue Gruppe. Dagegen: Der gemeinsame Zeitraumfilter zerfällt, die Übersichtsseite hat keinen Ort, und der Vergleich zwischen Domänen wird unmöglich.
  3. Alles ins bestehende /dashboard als zusätzliche Widgets. Dagegen: Das Rollen-Dashboard beantwortet „wie ist meine Lage", die Analyse „warum ist das so". Beides in eine Seite zu legen, macht aus dem Einstieg eine Halde.

Entschieden am 29.08.2026: Option 1, mit dem Namen „Analytics", der Prototyp setzt das um. Die Seitenleiste spiegelt jetzt die der Software (dieselbe Komponente, dieselben Gruppen); „Analytics" ist ein einzelner Menüpunkt neben „Dashboard", die fünf Seiten sind darin über Reiter erreichbar.

Ursprüngliche Empfehlung war der Name „Statistiken": so heißt der Breadcrumb im Prototyp bereits, und „Analyse" ist im Haus durch leads/analytics belegt. Das bestehende /dashboard bleibt Startseite; unsere Seite „Übersicht" braucht dann einen anderen Namen, sonst konkurrieren zwei Einstiegsseiten um dieselbe Rolle.

Vorher zu klären sind die Begriffe (Details in DATENMODELL.md):

Prototyp In der Software
„Übersicht" kollidiert mit der Startseite „Dashboard"
„Aufträge" keine Entität, eine Pipeline-View auf den Projekt-Kern (AD-20)
„Kunden" keine Entität, ein Status am Kontakt
„Team" thematisch unter Organisation/HR; Datenquelle erst in v2

Das ist eine Produkt- und Designentscheidung, keine Umsetzungsfrage. Sie gehört in die Runde mit dem Head of Design, nicht in den Einbau.

Nachtrag 29.08.2026: Die Frage hängt an einer größeren: „Analytics" und „Dashboard" sind zwei Features. Siehe SCOPE-ANALYTICS-DASHBOARD.md.

3.2 Kein eigenes App-Chrome

AppShell.tsx aus diesem Prototyp fällt beim Einbau weg. Die Cloud-Routen laufen bereits in der echten App-Shell mit Sidebar, Tenant-Layout und Breadcrumb (SubframeAppShell.tsx, AppSidebar.tsx). Screen-Komponenten dürfen dort ausdrücklich kein ~/ui/layouts/DefaultPageLayout rendern, das bringt eine eigene Beispiel-Sidebar mit und erzeugt eine doppelte Navigation. Stattdessen gilt PageShell / PageHeader / PageBody aus components/screens/shared/PageShell.tsx.

Unsere Seitenköpfe und die Filterleiste bleiben, die Rahmen-Navigation nicht.

3.3 Texte über i18n

Alle statischen Texte laufen über react-i18next (t("app.dashboard.…")). Dieser Prototyp hat deutsche Strings fest im JSX. Das ist beim Einbau mechanische Arbeit, aber flächendeckend, es betrifft jede Karte, jede Achsenbeschriftung und jeden Leerzustand.

Die deutschen Bezeichner im Code (umsatz, auftraege) bleiben davon unberührt und passen zur Cloud, deren UI ebenfalls deutsch ist (EN-Locale erst in P30).

3.4 Barrierefreiheit der Diagramme

In der Cloud sind Charts konsequent aria-hidden="true", und die umgebende Karte liefert eine Textzusammenfassung plus Datentabelle für Screenreader. Dieser Prototyp hat das nicht. Beim Einbau ist es Pflicht, das Repo fährt ein a11y-Lint-Baseline-Gate und axe-Tests je Primitive.

3.5 Stabile Oberflächen-IDs

Jede relevante Fläche trägt ein data-ui-id (ui.dashboard.widget.…), erfasst in docs/ui-inventory/surfaces.json. Tests und Agenten adressieren darüber. Unsere Widget-IDs aus dem WidgetContext sind der natürliche Anknüpfungspunkt, müssen aber auf das dortige Namensschema umgestellt werden.

3.6 Spacing passt bereits

.planning/INTERIM-UI-DESIGN-STANDARDS.md schreibt fest: Page-Padding 24, Card 16, Grid-Gap 16, Section-Gap 24, Field-Gap 16, Control-Höhe Medium 36, Input-Radius 4. Das deckt sich mit dem 8-px-System in DESIGN-SYSTEM.md Abschnitt 5: hier ist nichts anzupassen.


4. Was dieser Prototyp dem Zielsystem voraushat

Nicht alles fließt nur in eine Richtung. Drei Dinge fehlen dort heute:

Ein gemeinsames Chart-Theme. Die beiden vorhandenen Diagramme setzen Farben direkt im JSX (fill="#334155", fill="#cbd5e1"), jedes mit eigenem Gitter (strokeDasharray="3 3"), eigener Achsenbreite und eigenem Balkenradius. Es gibt keine geteilte Palette, keine Kategorien-Obergrenze und keine feste Farbzuordnung. features/dashboard/utils/chartTheme.ts ist genau das, was dort fehlt, und der Teil, der sich am ehesten unabhängig vom Rest übernehmen lässt.

Ausformulierte Diagramm-Regeln. DESIGN-SYSTEM.md hat in der Cloud keine Entsprechung. Die Standards dort regeln Layout, Controls und Zustände sehr genau, Datenvisualisierung dagegen gar nicht.

Fachliche Kennzahl-Definitionen. KPI-KATALOG.md mit Zeitbezug und Berechnung je KPI ist im Zielsystem so nicht vorhanden; die Widget-Registry beschreibt Kacheln, nicht deren betriebswirtschaftliche Definition.


5. Wer entwirft was, der Rest ist noch nicht fertig designt

HiveGrid Cloud ist nach dem Designer-First-Prinzip organisiert (.planning/DESIGNER-FIRST-PLAYBOOK.md). Der Ablauf ist verbindlich:

  1. Dev/Planung stellt je Phase einen Designer-Brief bereit, was das Modul tut und welche UI-Elemente vorkommen müssen, kein Layout.
  2. Der Designer entwirft die Screens in Subframe und darf Spec und UI/UX überschreiben: Anordnung und Layout sind eine Design-Entscheidung.
  3. Das Delta (geänderte Spec-Punkte, neue UX-Entscheidungen, Subframe-Link) wird in den Brief eingetragen.
  4. Der Dev setzt um und zieht Spec und Doku nach.

Es gibt 31 solcher Briefs (.planning/designer-briefs/P01…P34.md): Auth, CRM, Lead-Inbox, Projekt-Pipelines, Automation-Flow-Editor, Form-Builder, Plantafel, Kalender, Telefonie, HR, Billing, Customer-Portal, Help-Center. Für einen großen Teil davon steht der Delta-Block noch leer: Der finale Screen ist noch nicht entworfen, die Route läuft bis dahin auf Interim-UI.

Für die Einordnung dieses Prototyps heißt das dreierlei:

  • Das Dashboard ist ein Baustein unter vielen, nicht die Leitgestaltung der Anwendung. Es fügt sich in eine App-Shell und ein Design-System ein, die bereits stehen.
  • Was hier an Anordnung und Raster festgelegt ist, ist ein Vorschlag. Die Layout-Hoheit liegt beim Designer, der Brief zu P11 sagt ausdrücklich „Anordnung = Davids freie Hand". Verbindlich zu übergeben sind die Kennzahl-Definitionen, die Chart-Regeln und das Verhalten, nicht die Pixelanordnung.
  • Andere Bereiche der Anwendung sehen heute noch nicht final aus, weil sie entweder auf Interim-UI laufen oder noch beim Designer liegen. Ein Vergleich „unser Dashboard gegen den aktuellen Screen X" misst deshalb nicht zwangsläufig gegen den Zielzustand.

6. Wenn du dir das Zielsystem selbst ansehen willst

corepack enable && pnpm install
pnpm dev:services          # Postgres + Redis
pnpm dev:services:reset    # Wegwerf-DB inkl. Migrationen und Demo-Daten
pnpm dev:local

Tenant-App auf http://app.localhost:3000. Die lokalen Demo-Zugänge (Tenant „HiveGrid Demo SHK") stehen im README von HiveGrid Cloud unter „App starten", sie werden hier bewusst nicht wiederholt. Die Demo-Daten sind zunächst ausgeblendet und erscheinen über „Demo-Daten anzeigen" oder ?demo=show.

Der Weg zum Dashboard ist nach dem Login die erste Seite der Tenant-App.

Für einen schnellen Überblick ohne Setup: docs/ui-inventory/surface-map.md listet alle stabilen Oberflächen mit ihren Quelldateien, docs/route-inventory.md die Größenordnung des Routenbestands.