Der Tooltip legte sich ueber die Ringmitte: "Klima & Lueftung 268,0 T€" und
"GESAMT 2,27 Mio. €" uebereinander, beides unlesbar. Ein Ring von 168 px hat
keinen Platz fuer ein schwebendes Feld daneben, egal wohin man es schiebt.
Der Tooltip faellt deshalb ganz weg. Beim Ueberfahren zeigt die Mitte das
beruehrte Segment mit Name, Wert und Anteil, im Ruhezustand weiter den
Gesamtwert. Die Flaeche ist ohnehin belegt und die einzige, die gross genug
ist; ausserdem wiederholte der Tooltip nur, was die Legende daneben schon
zeigt. Das ist auch die Carbon-Loesung.
Damit das Ueberfahren des Rings selbst wirkt (bisher setzte nur die Legende
den Zustand), liegen die Handler jetzt auch am Pie.
Zur Breite der Beschriftung: erst am Container bemessen, dann an der Hoehe,
beides falsch. Der Ring ist so gross wie die **kleinere** der beiden Seiten.
Jetzt begrenzt min() beide. Der Wert ist nachgemessen statt geschaetzt: Bei
200 px Ringhoehe ist der Innenkreis 124 px breit und "KLIMA & LÜFTUNG" in
einer Zeile 109 px. Das passt rechnerisch und sieht trotzdem gedraengt aus,
weil der Innenkreis ein Kreis ist und die Beschriftung ueber der Mittellinie
steht, wo er schmaler wird. Bei 48 % bricht der Name auf zwei Zeilen um und
bekommt Luft.
Das Abblenden der uebrigen Segmente bleibt. Im Trichter war dasselbe Mittel
falsch, hier ist es richtig, und der Unterschied steht als Kommentar dabei:
Dort kodiert die Balkenlaenge eine Menge, und Deckkraft liest sich als
"weniger". Hier kodiert die Farbe nur eine Kategorie.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
"Sebastian Yilmaz" entstand nicht durch eine Namensauswahl, sondern durch die
Bauart: Vor- und Nachnamen lagen in zwei Listen und wurden ueber Index
kombiniert. Bei 24 x 24 Moeglichkeiten entstehen dabei zwangslaeufig Paare,
die nicht zusammengehoeren.
Jetzt eine Liste ganzer Namen. Aus "Sebastian Yilmaz" wird "Mehmet Yılmaz",
dazu "Emre Demir" als zweiter tuerkischer Name. Feste Paare kosten nichts und
koennen den Fehler nicht wiederholen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Eintrag "Vorjahr" hatte erst ein Kaestchen mit gestricheltem Rand (auf
10 px nur noch Eckstriche), dann ein gestricheltes Linienstueck. Beides war
zu viel Aufwand fuer eine Auskunft, die die Farbe schon gibt.
Jetzt derselbe abgerundete Marker wie beim aktuellen Zeitraum, in Grau. Die
Reihe liest sich ruhiger, weil alle Eintraege dieselbe Form haben.
Die Eigenschaft `gestrichelt` faellt damit weg, in der Legende und an ihren
vier Aufrufstellen. Eine Eigenschaft, die nichts mehr aendert, waere sonst
beim Einbau mitgewandert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Eintrag "Vorjahr" war ein 10 px grosses Kaestchen mit gestricheltem Rand.
Auf zehn Pixel bleiben von einem gestrichelten Rechteck ein paar Eckstriche
uebrig; das sah aus wie ein Zeichenfehler.
Es stimmte auch inhaltlich nicht: Im Diagramm ist die Vergleichsreihe keine
Flaeche, sondern eine Linie. Ein Marker, der etwas anderes zeigt als die
Reihe, die er benennt, ist genau die Art Kleinigkeit, die eine Legende
nutzlos macht.
Jetzt ein gestricheltes Linienstueck als SVG, mit derselben Staerke und
demselben Muster wie die Reihe im Chart (1,5 px, 4/4). Gefuellte Reihen
behalten ihren Punkt. Die Werte stehen als Konstante neben dem Marker mit dem
Hinweis, dass sie zu AreaVerlauf.tsx passen muessen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
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
Zwoelf Monatsnamen brauchen rund 340 px. In einer Drittelkarte bei 1400 px
sind knapp 300 da — "Aug", "Sep" und "Okt" standen ohne Luecke aneinander und
lasen sich als ein Wort.
Die Ursache war eine Schwelle, die nur die Datenmenge kannte: Erst ab mehr als
zwoelf Punkten wurde ueberhaupt ausgeduennt. Genau zwoelf Monate lagen darunter
und wurden alle gezeichnet, egal wie schmal die Karte war.
Jetzt zwei Stufen, und die zweite haengt an der Breite statt an der Menge:
Ueber zwoelf Werten weiterhin fest jede n-te Beschriftung — das ist eine
Entscheidung ueber die Reihe und darf nicht vom Bildschirm abhaengen. Darunter
entscheidet Recharts zur Laufzeit (preserveStartEnd mit minTickGap) und laesst
weg, was nicht passt, haelt dabei aber die erste und letzte Beschriftung; ohne
die waere der Zeitraum nicht mehr ablesbar.
Ergebnis: bei 1920 px stehen alle zwoelf Monate mit Luft, bei 1400 px zeigt
dieselbe Karte Jan, Maer, Mai, Jul, Sep, Dez. Diagramme mit wenigen Punkten
(fuenf Kalenderwochen im Auftragseingang) bleiben unveraendert vollstaendig.
Die Regel liegt jetzt als achsenIntervall() in chartTheme.ts, weil sie zwei
Diagramme betrifft. Der Zeitverlauf hatte den Fall schon behoben, das
Saeulendiagramm nicht — genau so laeuft so etwas auseinander.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Zwei Aenderungen an der Ansprache.
"Guten Tag, [Vorname]" statt eines erfundenen Namens. Ein fester Name sieht in
einer Abnahme aus wie ein fest verdrahteter Wert, und irgendwann fragt jemand,
warum dort immer derselbe steht. Die Klammern sagen, was an der Stelle
eingesetzt wird; beim Einbau kommt der Wert aus der Sitzung.
Und die Anwendung duzt: "2 Punkte brauchen heute deine Aufmerksamkeit."
Vor der Aenderung geprueft, ob es weitere Siez-Formen gibt — es war genau
diese eine Stelle, einmal im View-Model und einmal in der Bausteingalerie.
Halb geduzt liest sich schlechter als durchgehend gesiezt, deshalb steht die
Ansprache jetzt als Regel in DESIGN-SYSTEM.md, zusammen mit dem Hinweis, dass
beim Einbau im Zweifel die Ansprache von HiveGrid Vorrang hat.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Nach dem Oeffnen der Schublade lag ein blauer Rahmen um "Dashboard", nach dem
Schliessen um den Hamburger — bis man woanders hinklickte. Der Ring hat einen
praktischen Grund, aber nur fuer die Tastatur: Er zeigt, wo man gerade steht.
Nach einem Mausklick weiss man das ohnehin.
Ursache war unser eigener Fokus-Sprung, nicht die CSS-Regel. Die benutzt
laengst :focus-visible. Setzt aber ein Skript den Fokus — Fokusfalle beim
Oeffnen, Rueckgabe an den Ausloeser beim Schliessen —, wertet Chrome das wie
Tastaturbedienung und zeigt den Ring trotzdem.
Drei Aenderungen:
- Beim Oeffnen bekommt der Dialograhmen den Fokus statt des ersten Links. Das
ist ohnehin das uebliche Vorgehen fuer einen Dialog; die Sprachausgabe liest
den Dialog an, der erste Tabulatorschritt landet auf dem ersten Link.
- Elemente mit tabindex="-1" bekommen keinen Ring mehr. Sie sind aus der
Tabulatorreihenfolge heraus und werden nur per Skript fokussiert — ein Ring
um den ganzen Schubladenrahmen waere dort Laerm.
- AppShell schreibt die zuletzt benutzte Eingabeart als data-eingabe an das
Wurzelelement. Solange sie "zeiger" ist, entfaellt der Ring an Knoepfen und
Links. Eingabefelder sind ausgenommen, dort gehoert er zum Zustand "hier
wird gerade geschrieben". Der erste Tastendruck schaltet ihn ueberall zurueck.
Dabei ist eine Luecke in der Fokusfalle aufgefallen und behoben: Mit dem Fokus
auf dem Rahmen lief Umschalt+Tab aus dem Dialog heraus, weil die Falle nur den
ersten Link als Umkehrpunkt kannte. Der Rahmen steht im Dokument vor seinen
Kindern und gehoert dazu — sonst waere die Zusage von aria-modal gebrochen.
Nachgemessen statt begutachtet, alle Faelle:
Maus offen → Rahmen, kein Ring
Maus zu → Hamburger, kein Ring
Tastatur offen → Rahmen, kein Ring
Tastatur erstes → "Dashboard", RING
Tastatur rueckwaerts → "Komponenten", RING (Falle haelt)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Begruessungsbildschirm hatte einen Abschnitt "Kommt noch" mit drei leeren
Kacheln. Das ist der falsche Ort: Wer sich morgens anmeldet, will seine Lage
sehen und nicht lesen, was spaeter einmal kommt. Ein Dashboard ist kein Ort
fuer Ankuendigungen.
Die Verabredung bleibt vollstaendig erhalten, nur an Stellen, wo sie hingehoert
— alle drei fuer den Einbau gedacht:
1. RESERVIERTE_BEREICHE in view-models/dashboard.vm.ts, jetzt exportiert: die
Kacheln als Datensatz mit Titel, Widget-Domaene und Quell-Feature.
2. Ein markierter Kommentarblock in pages/DashboardSeite.tsx an genau der
Stelle im Raster, an die sie gehoeren — mit den konkreten Werten
(<Widget breite={4}> mit start 0, 4 und 8) und dem Hinweis, dass das Raster
dafuer nicht angefasst werden muss.
3. Die Bausteingalerie unter /komponenten, neuer Abschnitt "Reservierte
Kacheln" — dort sind alle drei gestaltet zu sehen, aus derselben Konstante
gerendert statt abgeschrieben.
docs/SCOPE-ANALYTICS-DASHBOARD.md nennt die drei Stellen jetzt ausdruecklich
unter "Wo die spaeteren Bereiche stehen", damit beim Port niemand sucht.
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
Sie war als "Referenz fuer den Einbau" ausgeschildert. Das trifft es nicht:
Wer den Prototyp einbaut, liest Code und Doku und kann sich keine gerenderte
Seite ansehen — die Datei-Pfade und DESIGN-SYSTEM.md tun diese Arbeit
ohnehin. Nuetzlich ist die Seite fuer die Abstimmung mit Menschen: Auf den
Analyse-Seiten sieht man von jedem Baustein immer nur den Zustand, den die
Daten gerade hergeben.
Neu ausgeschildert, und die fehlenden Zustaende ergaenzt:
- Seitenzustaende (laedt / leer / Fehler). In HiveGrid sind alle fuenf
VMState-Zustaende Pflicht, im Prototyp ist keiner davon je zu sehen, weil
die Demo-Daten immer liefern. Gestaltet werden muessen sie trotzdem —
"laedt", "nichts gefunden" und "kaputt" sind drei verschiedene Aussagen.
- Dashboard-Kacheln: Begruessung, WidgetKachel, reservierte Kachel. Das
Dashboard benutzt nicht ChartCard, sondern einen eigenen Rahmen; bisher war
der in der Galerie gar nicht vertreten.
Zwei Fehler dabei gefunden und behoben:
- Die Regelliste nannte noch den dunklen Tooltip (#393939). Seit Carbon v11
ist er hell (#ffffff auf #161616); im Code war das laengst umgestellt, auf
dieser Seite nicht. Eine Referenzseite, die eine ueberholte Regel behauptet,
ist schlimmer als keine.
- Die Abschnittstexte beginnen mit einem Dateipfad, und ein Pfad ist ein Wort
ohne Trennstelle. Bei 375 px lief
"features/dashboard/components/layout/SeitenZustand.tsx" neun Pixel ueber
den Rand — von verify:layout gefunden.
Die Regel zu den Kartenhoehen aus dem letzten Commit steht jetzt auch hier.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Rueckbau des letzten Commits, soweit er zu weit ging. Er hat alle
Diagrammzeilen gestreckt; richtig ist das nur dort, wo die Karten von Natur
aus aehnlich hoch sind.
Gemessen bei 1680 px, Hoehenunterschied innerhalb einer Zeile:
Trichter | Auslastung (Liste | Liste) 0 px / 0 px
Zahlungseingang | Bestand (Chart | Chart) 0 px / 0 px
Zahlungseingang | Gewerk (Chart | Liste) 147 px / 315 px
Vorgaenge Status | Gewerk (Chart | Liste) 190 px / 358 px
(volle Daten / duenne Daten)
Der Grund steckt in der Liste: Eine Balkenliste hat keine Mindesthoehe. Fuenf
Kategorien ergeben 280 px, eine einzige 112 px — daneben liegt ein
Zeitverlauf unveraendert bei 427 px, weil seine Diagrammflaeche fest ist.
Diese Zeile zu strecken heisst, eine Karte mit einem Balken auf 427 px
aufzublasen. Das ist schlimmer als die Luecke, die es vermeiden soll:
Weissraum auf der Seite liest sich als "hier ist gerade wenig", eine riesige
Karte mit einem Balken darin als Fehler.
items-start kehrt deshalb auf allen Zeilen zurueck, in denen ein Diagramm mit
fester Hoehe neben einer Liste steht. Gestreckt bleibt, wo beide Karten
dieselbe Bauart haben — Trichter neben Auslastung.
Das senkrechte Zentrieren im Kartenkoerper bleibt: Auf oben buendigen Zeilen
ist es wirkungslos, auf den gestreckten verteilt es den Ueberschuss oben und
unten statt ihn unten abzuladen. Das war die Verbesserung am Trichter.
Auf dem Dashboard bleibt die Zeile aus Zeitverlauf und Balkenliste gestreckt.
Derselbe Massstab, anderes Ergebnis: Dort gibt es keinen Filter, die Liste hat
immer ihre fuenf Gewerke, und es bleiben rund 90 px. Der Filter ist der
Unterschied, nicht die Kachel.
DESIGN-SYSTEM.md traegt jetzt die Regel mit den Messwerten statt der zu
weit gefassten Fassung von vorhin.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Aus dem Sparring: Bei duenner Datenlage riss die oben buendige Ausrichtung
Loecher in die Seite. Nachgemessen auf /analytics mit Zeitraum "heute" und
Gewerk "Heizung": "Umsatz nach Gewerk" 112 px neben "Zahlungseingang im
Zeitverlauf" 427 px — 315 px Seitenhintergrund dazwischen. Das liest sich
nicht als "wenig Daten", sondern als "etwas ist kaputt".
Zwei Aenderungen, beide klein:
- Der Kartenkoerper zentriert seinen Inhalt senkrecht. Der Ueberschuss geht
je zur Haelfte nach oben und unten, statt unten abgeladen zu werden. Eine
Stelle in ChartCard und eine in WidgetKachel — nicht in fuenf Diagrammen.
- items-start faellt auf den Zeilen, die ausschliesslich Diagrammkarten
tragen. Die Zeile mit den beiden Tabellen auf der Kundenseite bleibt oben
buendig: Eine Tabelle hat ein natuerliches Ende und eine eigene
Blaetterleiste, Strecken schiebt die nur nach unten.
Die Karten bleiben dynamisch — keine feste Hoehe, mehr Inhalt laesst die
Karte und mit ihr die Zeile weiter wachsen.
Die Leere verschwindet nicht, sie zieht aus dem Seitenhintergrund in die
Karte. Das ist der Unterschied zwischen einem Raster mit Luecken und einer
Karte, in der gerade wenig steht.
Nachgemessen nach der Aenderung: 427/427, 389/389 auf /analytics,
372/372 und 423/423 auf /dashboard. Dabei ist nebenbei die Leerflaeche unter
dem Vertriebstrichter verschwunden, die vorher auffiel.
In DESIGN-SYSTEM.md als Regel festgehalten.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Aus dem Sparring, alle drei auch in Analytics wirksam.
1. Vertriebstrichter: Zeilen-Hervorhebung statt Ausgrauen der uebrigen Balken.
Bisher setzte das Ueberfahren einer Zeile alle anderen Balken auf 45 %
Deckkraft. Das war aus drei Gruenden falsch: Es liess fuenf von sechs
Balken verblassen und las sich dadurch wie eine Auswahl statt wie ein
Ueberfahren; es war in sich widerspruechlich, weil die Balken verblassten
und die Namen daneben schwarz blieben; und Deckkraft traegt in diesem
Diagramm bereits Bedeutung — der Balken kodiert einen Anteil, ihn heller zu
machen heisst dort "weniger" und nicht "gerade nicht beruehrt".
Jetzt bekommt die beruehrte Zeile einen Untergrund, die uebrigen bleiben
unveraendert. Derselbe Untergrund wie in der Handlungsbedarf-Liste und in
den Tabellen. Die Spur des aktiven Balkens wird weiss: neutral-50 und
neutral-100 liegen nur fuenf Stufen auseinander, grau auf grau haette dem
Balken den Bezugsrahmen genommen.
2. KPI-Karten einer Reihe auf gleiche Hoehe.
Die Umsatzkarte war hoeher als ihre drei Nachbarn, weil sie als einzige
eine Trendzeile mit Verlaufskurve traegt. Auf dem Dashboard steht zwischen
Rasterzelle und Karte ein Link, und der reichte die Streckung des Rasters
nicht durch. h-full auf der Karte.
3. Handlungsbedarf: Hover-Flaeche greift ueber den Inhalt hinaus.
Der Untergrund endete hart am Pfeil — bei zwei Spalten besonders sichtbar,
weil daneben 32 px Spaltenabstand ungefaerbt blieben. Jetzt acht Pixel
Ueberstand und runde Ecken.
Dabei mitgenommen: Der Trennstrich sass unten und brauchte eine Ausnahme
fuer "die letzte Zeile" — die es bei zwei Spalten zweimal gibt. Die rechte
Spalte behielt dadurch einen Strich, unter dem nichts mehr kam. Oben
liegend ist die Ausnahme die erste Zeile jeder Spalte, und die steht immer
an derselben Stelle, unabhaengig von der Anzahl der Eintraege.
tsc, lint, build und verify:layout laufen sauber; Hover-Zustaende und
Kartenhoehen nachgemessen statt begutachtet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
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
Der Prototyp war auf Schreibtischbreiten gebaut. Bei 375 px lief die Seite um
306 px seitlich über, und dem Inhalt blieben 135 px, weil die Seitenleiste ihre
vollen 240 px behielt.
Seitenleiste (an HiveGrid abgeglichen, nicht erfunden):
- Unterhalb 768 px faehrt sie als Schublade ueber den Inhalt. Derselbe
Breakpoint, den die Software als MOBILE_BREAKPOINT fuehrt.
- Hamburger links in der Kopfzeile, FeatherMenu, 32x32, md:hidden, vor dem
Breadcrumb — wie SubframeAppShell ihn rendert.
- Abdeckung dahinter, Escape schliesst, Fokus wandert beim Oeffnen auf den
ersten Eintrag und kehrt beim Schliessen zum Ausloeser zurueck.
- Fokusfalle mit Tab und Umschalt+Tab: Der Rahmen traegt role=dialog und
aria-modal, ohne Falle waere das gegenueber einem Screenreader unwahr.
- Der Einklapp-Knopf ist unterhalb md ausgeblendet. Er ragt bauartbedingt
17 px nach rechts heraus und blieb sonst als angeschnittener, wirkungsloser
Rest bei x = -16 am Bildrand stehen — der gemeldete Fehler.
Inhalte: Raster einspaltig ab 375 px, Seitenkopf mit Aktionen unter dem Titel
und Icon-only, Zeitraum-Segment und Reiterstreifen waagerecht scrollend statt
umbrechend (ein Segment ueber zwei Zeilen liest sich als zwei Steuerelemente),
Filter-Panel auf volle Zeilenbreite, Tabellen mit eigenem Scrollbereich.
Zwei abgeschnittene Fehler mitbehoben, die der Prueferer nicht sieht:
- KPI-Label lief bei 1280 px um 5 px aus seinem Kasten; bricht jetzt um. Die
Karte wird dadurch eine Zeile hoeher — der Preis fuer eine vollstaendig
lesbare Beschriftung.
- Randmarken der Auslastungsachse ragten je rund 10 px ueber die Spur. In sehr
schmalen Karten entfaellt die Achse ganz; dort bleibt nur rund 40 px Spur,
auf der selbst zwei Marken aneinanderstossen.
verify-layout deckt jetzt 375-1920 px ab (vorher ab 1024) und meldet zusaetzlich
Seitenueberlauf: ein waagerechter Scrollbalken auf Dokumentebene ist immer ein
Fehler, nie ein Kompromiss. 7 Seiten x 9 Breiten gruen.
Ab 1024 px ist der abgenommene Stand unveraendert — numerisch geprueft ueber die
Bounding-Boxen aller Karten, Raster, Tabellen und Kopfelemente.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Klarstellung, damit beim Port keine globalen Regeln aus diesem Repo in die
Software wandern.
Verbindlich ist aus diesem Repo nur das Analytics-Eigene und das Fachliche:
Kennzahl-Definitionen, Diagrammregeln, Verhalten — und die Navigationsstruktur
als Verabredung (zwei Einträge in der Seitenleiste, Analytics mit innerer
Leiste).
Nicht verbindlich ist alles Globale: Schrift, Schriftgrößen, Abstände, Farben,
Radien, Control-Höhen, App-Shell, Kopfzeile, i18n, Formatierung. Das kommt
ausschließlich aus HiveGrid. Dass dieser Prototyp dieselbe Schrift, dieselbe
Seitenleisten-Komponente und dieselben Token benutzt, dient allein der
Lesbarkeit neben der Software — es ist keine Vorlage, an der sich die Software
auszurichten hätte. Weicht ein Wert hier von HiveGrid ab, ist der Wert hier
falsch.
Ebenso festgehalten, was Gerüst ist und wegfällt: AppShell, unsere Kopie der
Seitenleiste, PageHeader, die Kopfzeile, die Routen unter app/ und die
Dashboard-Platzhalterseite. Der Nachbau der inneren Leiste wird nicht portiert;
in HiveGrid entsteht sie über das dortige SidebarIconsLayout.
Vermerkt in ZIELSYSTEM.md (neuer Abschnitt 0 mit Zuständigkeitstabelle), im
Kopf von HANDOVER.md und README.md, bei der Struktur in NAVIGATION.md, als
Vorbemerkung zu den bewussten Abweichungen in LEITPLANKEN.md — und als
Kommentarblock in AppShell.tsx und AnalyticsInnerNav.tsx, weil beim Port oft
zuerst der Code gelesen wird.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Knopf ragt bauartbedingt 17 px aus der Seitenleiste in die Inhaltsfläche
hinein. Dort wurde seine rechte Hälfte verdeckt — er sah abgeschnitten aus und
war auf diesem Teil nicht anklickbar.
Nicht abgeschnitten, sondern überdeckt: Gemessen war overflow überall visible,
aber das oberste Element an der Knopfmitte war die Inhaltsspalte. Ursache ist
ein Stapelkontext — 'position: sticky' erzeugt einen eigenen, wodurch das
z-index:40 des Knopfes darin gefangen bleibt. Der Rahmen selbst hatte
z-index:auto, also malte die später im Dokument stehende Inhaltsspalte darüber.
Behoben mit z-50 am Sidebar-Rahmen; die Software setzt an derselben Stelle
ebenfalls z-50. Nachgemessen: Am rechten Rand ist jetzt der Knopf selbst das
oberste Element, und ein Klick genau dort schaltet um.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Menüpunkt 'Dashboard' löste bisher nur einen Toast aus. Ein
Navigationseintrag, der nirgendwohin führt, lässt den Leser im Unklaren, ob
etwas fehlt oder etwas kaputt ist.
Jetzt führt er auf /dashboard: ein Leerzustand nach dem Hausmuster
(ui/components/EmptyState), der benennt, warum hier nichts steht, was später
hinkommt (drei Rollen-Layouts, Widgets teils aus Analytics, teils nicht — offene
HR-Anträge, Aufgaben, Termine) und wo der Zuschnitt dokumentiert ist. Mit einem
Weg zurück nach Analytics.
Dabei:
- EmptyState aus der Cloud-Fassung nachgezogen; unsere Kopie hatte den
action-Slot noch nicht.
- PageHeader bekommt 'standardAktionen': Auf einer leeren Seite gibt es nichts
zu aktualisieren oder zu exportieren, also stehen dort auch keine
Schaltflächen dafür.
- Die Variante 'software' in NavZiel entfällt — jeder Eintrag führt jetzt auf
eine echte Seite, der Toast-Zweig in der AppShell war damit toter Code.
- verify-layout deckt /dashboard mit ab (jetzt 7 Seiten x 7 Breiten).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Abwägung an der Quelle statt nach Gefühl. Das Zielsystem nutzt beide Muster,
aber für verschiedene Aufgaben:
- Innere Leiste (SidebarIconsLayout, 17 Aufrufstellen): Arbeitsbereiche mit
Geschwisterseiten — Leads, Termine, HR, Einstellungen.
- Reiter (Tabs): Abschnitte innerhalb EINER Seite — Formular-Editor,
Chat-Dateien, Projekt-Teilbereiche, Übergabe-Dialog.
Analytics mit fünf Analyse-Seiten ist der erste Fall, strukturell dasselbe wie
Leads mit acht. Drei Gründe:
1. Kohärenz: dieselbe Bedienung an derselben Stelle wie in Leads.
2. Der Platzeinwand trägt nicht. Die Leiste ist eine 32 px schmale Icon-Spalte
und klappt erst bei Zeigerkontakt oder Tastaturfokus auf 191 px aus,
verzögert (300 ms auf, 350 ms zu), damit sie beim Überstreichen nicht
aufspringt. Die Breite brauchen die Analyse-Seiten mit ihren fünfspaltigen
Kennzahlenreihen.
3. Reiter sind dort der Rückfall, nicht die Wahl: SidebarIconsLayout zeigt
unterhalb sm selbst eine Reiterleiste. Auf dem Schreibtisch Reiter zu nehmen
hieße, die Handy-Notlösung zur Hauptform zu machen. Der Nachbau übernimmt
diesen Rückfall mit.
Nachgemessen: 32 px eingeklappt, 191 px bei Zeigerkontakt, aktiver Eintrag
hervorgehoben, aria-current gesetzt. verify-layout weiterhin grün.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Zwei Korrekturen aus dem Review.
1. Die Seitenleiste zeigte die komplette Software-Navigation nach. Falsch:
Kontakte, Leads, Pipelines, Postfach, Termine und Einstellungen stehen dort
bereits, der Prototyp verdoppelt sie nur. Jetzt stehen in der Leiste
ausschließlich unsere beiden Features — Dashboard (eigenes Feature, hier
nicht enthalten) und Analytics — plus die Bausteingalerie im sekundären
Bereich, die zum Prototyp und nicht zum Produkt gehört.
2. Die Schrift stimmte nicht. Die Software nutzt Instrument Sans, selbst
gehostet als variable Schrift. Der Prototyp lud Inter über next/font,
während ui/theme.css für sämtliche Subframe-Typo-Token bereits
'Instrument Sans' verlangte — die Schrift war aber nie geladen und fiel auf
die Systemschrift zurück. Ergebnis waren zwei verschiedene Schriften auf
einer Seite, keine davon die der Software.
Jetzt liegen dieselben woff2-Dateien unter public/fonts/, mit denselben
@font-face-Regeln und derselben Alias-Zuordnung für Komponenten, die noch
direkt auf Inter verweisen. next/font entfällt.
Der Layout-Prüfer lief nach dem Schriftwechsel erneut durch: andere Metrik,
andere Textbreiten — weiterhin keine Kollisionen über 6 Seiten × 7 Breiten.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Der Prototyp hatte eine eigene Seitenleiste mit den fünf Analyse-Seiten als
Menüpunkten. Die Software hat eine andere Navigation, in der Analytics noch gar
nicht vorkommt. Beides zusammen ergab kein Bild davon, wo die Analyse später
sitzt.
Jetzt:
- Die Seitenleiste spiegelt die von HiveGrid Cloud — dieselbe Komponente
(SidebarWithSections aus der Cloud-Fassung portiert, inkl. der dortigen
lokalen Fixes: Collapse-Breite, verdrahteter Toggle, Logo-Slot, Hover-Sweep),
dieselben Gruppen, dieselbe Reihenfolge, dasselbe Logo.
- 'Analytics' ist ein einzelner Menüpunkt, gleichrangig neben 'Dashboard'.
- Die fünf Analyse-Seiten sind darin über Reiter erreichbar, nicht als
Unterpunkte in der Navigation. Zwei Navigationsebenen für dieselbe Sache
würden nur konkurrieren. Die Reiter folgen dem Hausmuster aus
SettingsHubShell (Link um Tabs.Item), damit jeder Reiter eine echte Adresse
hat und mittelklickbar bleibt.
- Routen: /analytics, /analytics/finanzen, /auftraege, /kunden, /team.
'/' leitet auf /analytics; das Dashboard liegt in der Software unter '/'.
- Alle übrigen Einträge sind Kontext: Sie zeigen den Ort in der fertigen
Anwendung und melden beim Klick, dass sie zur Software gehören.
Kopfzeile und Filterleiste sind aus den fünf Seiten in die Analytics-Hülle
gewandert — sie sind für alle gleich, und der Filterzustand gilt bereichsweit.
Nebenbei: @radix-ui/react-slot war eine Phantom-Dependency (nur transitiv über
@subframe/core vorhanden, vom portierten IconButton direkt importiert) und ist
jetzt deklariert. verify-layout prüfte noch die alten Routen und lief damit auf
404-Seiten, die naturgemäß keine Kollisionen haben — Routen korrigiert und eine
Absicherung ergänzt, die bei Statuscode >= 400 abbricht.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Gemeldeter Fehler: In der Ringlegende klebten Bezeichnung und Wert aneinander
("Gestellt189,1 T€"). Ursache war eine eigene Regression — beim Beheben der
abgeschnittenen Legendennamen war das truncate entfallen, ohne Ersatz. Damit
schrumpft die Namensspalte durch min-w-0 + grow auf null Breite, und der Text
läuft sichtbar über seinen Kasten hinaus:
1280 px Kastenbreite 0 px, Text 43 px darüber hinaus
1440 px Kastenbreite 25 px, Text 18 px darüber hinaus
1600 px unauffällig
Genau deshalb war es auf den Screenshots nicht zu sehen: Der Fehler tritt nur in
bestimmten Fensterbreiten auf.
Neu: scripts/verify-layout.mjs + npm run verify:layout. Lädt alle sechs Seiten in
sieben Breiten (1024–1920) und misst jede Textzeile über Range.getClientRects.
Gemessen wird auf Textzeilen, nicht auf Elementkästen — sonst melden benachbarte
Tabellenzellen mit Innenabstand falsch positiv. Mindestabstand 8 px = Carbon
$spacing-03. Der Lauf fand 110 Fehler; alle behoben:
- Ringlegende: Container-Query statt fester Zweispaltigkeit. Legende sitzt rechts
vom Ring, wenn Platz ist, sonst darunter — Carbon: "positioned to the right of
the chart when space is plentiful". Namen brechen um statt überzulaufen.
- Auslastungs-Achse: Beschriftungsdichte staffelt sich über drei Container-Stufen,
vorher überlappten die Zahlen in schmalen Karten um bis zu 16 px.
- Handlungsbedarf und Kennzahl-Labels: break-words statt Überlauf.
- Kartentitel und -untertitel: break-words, weil Dateipfade keine Leerzeichen
zum Umbrechen haben.
Dokumentiert als DESIGN-SYSTEM.md §9 mit Begründung, warum das ein gemessener
Prüfer sein muss und keine Sichtprüfung.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
Recherche an der Quelle statt an der Dokumentation. Zwei Ergebnisse:
1. Carbon regelt Datenvisualisierung nur teilweise. Farben, Gitter, Achsen,
Tooltip und Tickanzahl sind verbindlich festgelegt — Paddings, Margins und
Dashboard-Raster dagegen NICHT. Die Carbon-Seiten zu Chart-Anatomie und
Dashboards tragen ausdrücklich den Hinweis "this guidance is a work in
progress" und enthalten keine Zahlenwerte. Unsere Abstandswerte stammen
deshalb aus der Carbon-Spacing-Skala und der Planung mit dem Branchenpartner,
nicht aus der Data-Viz-Norm. Das steht jetzt so in DESIGN-SYSTEM.md §0.
2. Eine echte Abweichung gefunden: Der Tooltip ist seit Carbon v11 hell
(--cds-layer-02 #ffffff auf --cds-text-primary #161616, abgesetzt allein
durch den Schatten). Unser Theme führte den dunklen v10-Stand (#393939) und
berief sich dabei auf das ausgelieferte Stylesheet — die Angabe war veraltet.
Korrigiert.
Neu:
- docs/carbon-referenz.json — kanonische Werte mit Quelle, Version und
Prüfdatum, gezogen aus @carbon/charts 1.23.0 styles.min.css und
configuration.ts. Bewusste Abweichungen (Balkenbreite 48 statt 16, feste
Kategoriefarben statt n-Serien-Paletten) sind dort begründet.
- scripts/verify-carbon.mjs + npm run verify:carbon — gleicht chartTheme.ts
gegen die Referenz ab und bricht bei Drift ab.
- docs/PRUEFFRAGEN.md — Prüffragen für die Gestaltungsabnahme mit
nachprüfbarem Ja/Nein, plus Leseliste (FT Visual Vocabulary, IBCS,
Cleveland & McGill, Few, Datawrapper Academy).
Die 14er-Palette wurde gegen die CSS-Variablen --cds-charts-14-1-* geprüft und
stimmt exakt; ebenso Gitter #e0e0e0, Achse #8d8d8d und Achsentext #525252.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
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
UI/UX-Prototyp der Analytics-Dashboards in HiveGrid, fachlich auf einen
SHK-/Handwerksbetrieb zugeschnitten. Ziel ist die Übergabe an die Entwicklung,
nicht der Produktivbetrieb.
Inhalt: sechs Seiten (Übersicht, Finanzen, Aufträge, Kunden, Team, Komponenten),
26 KPIs, neun Chart-Bausteine, Filtersystem mit seitenabhängiger Relevanz und ein
deterministischer Demo-Datensatz (420 Kunden, 1.900 Aufträge, Stichtag 30.07.2026).
Drei Quellen sind zusammengeführt: die fachliche Planung mit dem Branchenpartner
(Januar 2026), die Subframe-Komponentenbibliothek aus dem HiveGrid-Pitch und
IBM Carbon Data Visualization für die Diagrammregeln. Herkunft und bewusste
Abweichungen stehen in docs/HERKUNFT.md.
Dokumentation: README, HANDOVER (was echte Logik braucht), docs/DESIGN-SYSTEM,
KPI-KATALOG, DATENMODELL, NAVIGATION, HERKUNFT, ZIELSYSTEM (Einbauort in
HiveGrid Cloud) und LEITPLANKEN (welche Cloud-Screens als Vorbild taugen).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX