29 KiB
WOMS „Weißes Design“ P9: Serverpuls – Umsetzungsplan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Nach P9 ist Serverpuls hell und kastenlos. Der Kopf trägt ein Text-Badge statt eines Emojis, Warnungen sind Listenzeilen mit Stufen-Badge, die Kacheln sind .stats mit Sparkline. Deltas zeigen sich als Textfarbe, Umschalter sind .seg, Panels sind h2.section, die Projekttabelle ist eine .table. Die Diagramme nutzen die Farben aus chartColors.js. Alle data-testid bleiben.
Architecture:
- Drei reine Helfer in
src/lib/serverpulsFormat.jsmit Tests:deltaDir,deltaSign,levelTone. - Bausteine aus P1:
Stat,Badge(badgeToneClassausui/tones.js),PageHeader,.stats,.list-row,.seg,.table,.msg,.toolbar,.input.search. serverpuls.csswird neu geschrieben (74 → rund 70 Zeilen).Chart.jsxundSparkline.jsxbleiben unverändert, weil P1 die Diagrammfarben schon umgestellt hat. Dasselbe prüft Task 6.- Abfragen, 60-Sekunden-Takt, Neuladen bei Sichtbarkeit,
reqId-Schutz, Sortierlogik und Zeitachsen bleiben unverändert.
Tech Stack: React 18, uPlot (Canvas), reines CSS. Tests mit node --test, Screenshot-Werkzeug aus P0.
Spec: docs/superpowers/specs/2026-10-04-weisses-design-design.md, Abschnitte „Gestaltungsregeln“, „Design-Tokens“ (Diagrammfarben), „Bausteine“ (Kennzahlen, Umschalter, Tabelle, Liste, Badge, Meldungen, Laden) und Paket P9. Anhang 2026-10-04-weisses-design-umbaukarte.md: Abschnitt 5 (P9) und 7.1. Globale Regeln und Schnittstellen: 2026-10-05-weisses-design-00-uebersicht.md.
Global Constraints
Es gelten die Regeln der Übersicht. Für P9 kommt hinzu:
- Jeder Run-Block beginnt mit
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh. Danach gelten$WT(Worktree, Arbeitsverzeichnis),$W(Werkzeug) und$TMPDIR. Tests und Build werden nur über"$W/check.sh"ausgewertet, Browser-Skripte laufen nur über"$W/shots.sh". - Ausgangspunkt ist das Tag
design-p8, alle Diff-Prüfungen vergleichen gegendesign-p8. - CSS-Reihenfolge:
main.jsximportiertAppvorglobal.css, also lädtserverpuls.cssvorglobal.css, und bei gleicher Spezifität gewinntglobal.css. Jede Regel inserverpuls.css, die eine Global-Klasse überstimmt (.stats,.list-row,.msg,.table,.seg), hat höhere Spezifität (0,2,0, z. B..stats.sp-tiles,.sp-page .msg) und nie!important. - Abstände zwischen aufeinanderfolgenden Abschnitten kommen von
.page section + section { margin-top: 36px }aus P1. P9 baut dafür keine eigenen Regeln:.sp-panelund.stats.sp-tilessetzen keinen Außenabstand nach oben. Eigene Abstände gibt es nur innerhalb der Abschnitte (div-Container). - Die CSS-Tabellen dieses Plans nennen nur die Abweichungen vom Prototyp und von den Tokens. Was Basis (
*-Reset,button-Reset),.table,.stat,.list-rowund.segschon liefern, wird nicht wiederholt. - Canvas-Farben stehen nur in
chartColors.js. InServerpulsPage.jsx,Chart.jsx,AppsTable.jsxundSparkline.jsxgibt es kein Farbliteral. - Keine Icon-Importe, keine Emojis, keine Glyphen ▲ und ▼. Die Sortierzeichen ↑ und ↓ bleiben.
- Sichtbare Textänderungen: keine außer den Badge-Texten des Kopfes aus
LEVEL_TEXT. Alle Ladetexte („Lädt …“) und Meldungen bleiben wörtlich. - Keine neuen
style={{…}}.
Review Focus
Aus der Übersicht gehören drei Punkte zu P9:
- Punkt 2, lange Inhalte am Handy: Sechs Kacheln, Umschalter mit 6 und 5 Knöpfen und die Tabelle bei 390 px ohne waagerechtes Scrollen. Testdaten
serverpuls-lang: Projektname mit 60 Zeichen ohne Leerzeichen, Warnungstitel mit 90 Zeichen.overflow-xist seit dem Gatep1für alle Ansichten scharf, also auch im Gatep9. - Punkt 3, Teilausfall: Ansicht
serverpuls-ausfall. Die Übersicht antwortet 500,sp-errorerscheint, Diagramm und Tabelle bleiben nutzbar, die Kacheln zeigen „–“. - Punkt 4, nur Tastatur:
- Projektzeilen lassen sich über den Button in der ersten Zelle öffnen (
aria-pressed). - Sortierköpfe sind Buttons mit
aria-sortauf demth. - Die
.seg-Knöpfe tragenaria-pressed.
- Projektzeilen lassen sich über den Button in der ersten Zelle öffnen (
Zusätzlich gilt für P9:
- Checkliste der Bedienelemente, nichts darf fehlen: Metrik-Umschalter (6 Knöpfe), Zeitraum-Umschalter (5), Projektsuche, 6 Sortierköpfe (Projekt, Größe, Δ 7 T, Δ 30 T, CPU, RAM), Projektzeile (öffnet und schließt das Detail), Zeitraum-Umschalter im Detail (5).
- Die 20
data-testidim Serverpuls-Code bleiben identisch (Task 1 und 6). Ohne den Muster-Eintragsp-tile-${id}sind es die 19 der Spec. - Rot heißt gestiegen und Grün gesunken, das Vorzeichen steht weiter in der Zahl.
Task 1: Paketstart und Ausgangswerte
Files: keine Änderung.
Interfaces: keine.
- Step 1: Paketstart
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git merge-base --is-ancestor design-p8 HEAD && git rebase origin/test && "$W/check.sh" && git status --short
Expected: Exit 0, Rebase ohne Konflikt, # fail 0 und eine leere Statusliste. Endet merge-base mit Exit 1, liegt design-p8 nicht im Branch: stoppen und melden. Die Testzahl heißt im Folgenden N0, die Bundle-Größen aus der Ausgabe von check.sh werden notiert.
- Step 2: Abgleich mit TP2
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git log --oneline origin/test..feature/terminplaner-tp2 -- src/pages/ServerpulsPage.jsx src/components/serverpuls src/styles/serverpuls.css src/lib/serverpulsFormat.js src/styles/global.css
Expected: keine Ausgabe. Gibt es Treffer, stoppt der Agent vor Task 2, nennt dem Eigentümer die Commits und fragt nach. Er empfiehlt dabei, TP2 zuerst nach test zu bringen.
- Step 3: Referenzliste der Test-IDs anlegen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -o --no-filename 'testid=("sp-[a-z-]+"|\{`sp-tile-\$\{id\}`\})' src/pages/ServerpulsPage.jsx src/components/serverpuls | sort > "$W/p9-testids.before.txt" && wc -l < "$W/p9-testids.before.txt"
Expected: 20.
- Step 4: Voraussetzungen aus P1 und P2 prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && ls src/components/serverpuls/chartColors.js src/components/ui/Stat.jsx src/components/ui/tones.js src/lib/rowClick.js && rg -n "isRowActivation" src/lib/rowClick.js && rg -n -m 1 "CHART\." src/components/serverpuls/Chart.jsx src/pages/ServerpulsPage.jsx && rg -n "#[0-9a-fA-F]{3,8}\b|rgba?\(" src/components/serverpuls src/pages/ServerpulsPage.jsx --glob '!chartColors.js'
Expected: Die Dateien sind da, src/lib/rowClick.js (P2 Task 2) enthält isRowActivation(event), CHART. kommt in beiden Dateien vor, und die letzte Suche liefert keine Treffer (Exit 1). Fehlt rowClick.js, stoppt der Agent und meldet es, P9 baut keinen eigenen Zeilenklick-Helfer.
Task 2: Format-Helfer deltaDir, deltaSign, levelTone (TDD)
Files:
- Modify:
src/lib/serverpulsFormat.js(neue Exporte nachformatNumber, vor dem Abschnitt// --- Zeitachsen) - Test:
tests/unit/serverpulsFormat.test.mjs(Z. 5 Import, zwei neue Tests)
Interfaces:
-
Produces:
deltaDir(d) → 'up' | 'down' | 'flat'(flatbei Betrag unter1e-9, genau die Regel ausTile).deltaSign(dir) → '+' | '−' | ''(U+2212).levelTone(level) → 'ok' | 'warn' | 'danger' | 'muted'. Es sind die Ton-Namen vonBadge.
-
Bestehende Exporte bleiben unverändert.
-
Step 1: Failing Test schreiben
Die Destrukturierung in Z. 5 bekommt deltaDir, deltaSign, levelTone. Dazu:
test('deltaDir und deltaSign: Richtung und Vorzeichen der Kachel-Deltas', () => {
assert.deepEqual([deltaDir(0), deltaDir(5e-10), deltaDir(-5e-10)], ['flat', 'flat', 'flat'])
assert.equal(deltaDir(0.4), 'up')
assert.equal(deltaDir(-0.4), 'down')
assert.deepEqual([deltaSign('up'), deltaSign('down'), deltaSign('flat')], ['+', '−', ''])
})
test('levelTone: Badge-Ton je Stufe', () => {
assert.deepEqual(['ok', 'medium', 'critical'].map(levelTone), ['ok', 'warn', 'danger'])
assert.deepEqual([levelTone('low'), levelTone(undefined), levelTone('x')], ['muted', 'muted', 'muted'])
})
- Step 2: Test laufen lassen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/serverpulsFormat.test.mjs
Expected: FAIL, deltaDir is not a function.
- Step 3: Implementieren
Die drei Funktionen in src/lib/serverpulsFormat.js. Die Schwelle 1e-9 und das Zeichen U+2212 sind wie in Tile und formatDelta.
- Step 4: Test grün
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/serverpulsFormat.test.mjs && "$W/check.sh" --nur-tests
Expected: PASS, Exit 0, Testzahl N0 + 2, # fail 0.
- Step 5: Commit
git add src/lib/serverpulsFormat.js tests/unit/serverpulsFormat.test.mjs
git commit -m "Serverpuls: Richtung, Vorzeichen und Stufen-Ton als Format-Helfer mit Test" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 3: Werkzeug – Testdaten, Ansichten, Gate p9, Ausnahme für Sparklines
Files (alle unter $W/, kein Commit im Repo):
- Create:
fixtures/serverpuls-ok.mjs,fixtures/serverpuls-veraltet.mjs,fixtures/serverpuls-lang.mjs - Modify:
views.mjs,gates.mjs,checks.mjs
Interfaces:
-
Consumes:
createBackend,VIEWS,GATESaus P0 und die Konsolen-Ausnahme des Szenariosfehler(P0, in P8 Task 4 Step 3 erweitert). -
Produces: die Ansichten aus Step 2,
GATES.p9, die Ausnahmesvg.sp-sparkim Checkicon-svgund die Ausnahme für**/api/serverpuls/**im Szenariofehler. -
Step 1: Testdaten-Varianten anlegen
Alle erweitern standard.
-
serverpuls-ok: Übersicht mitlevel: 'ok'undalerts: []. -
serverpuls-veraltet:level: 'medium', eine Warnung,lastSamplevor 40 Minuten. -
serverpuls-lang:level: 'critical'mit drei Warnungen (critical,medium,low), davon eine mit 90-Zeichen-Titel. Zwölf Projektzeilen, eine mit 60-Zeichen-Namen ohne Leerzeichen. -
Step 2: Ansichten in
views.mjsanlegen oder anpassen
Der path ist /serverpuls. Die Schritte haben die Signatur steps(page, ctx), ctx.backend.calls listet die vom Backend beantworteten Requests. Geprüft wird mit throw new Error(…), das den Verstoß step-failed erzeugt.
| ID | Daten | Schritte |
|---|---|---|
serverpuls |
serverpuls-lang |
Warten, bis [data-testid="sp-chart"] ein canvas mit Breite über 0 trägt und sechs [data-testid^="sp-tile-"] da sind. |
serverpuls-ok |
serverpuls-ok |
Wie serverpuls. |
serverpuls-veraltet |
serverpuls-veraltet |
Wie serverpuls. |
serverpuls-projekt |
serverpuls-lang |
Fokus auf button.link der ersten [data-testid="sp-app-row"], Enter: sp-detail muss sichtbar sein und drei canvas enthalten. Fokus auf den Sortierkopf „Größe“ (th[data-sort="sizeBytes"] button), Enter: aria-sort muss ascending heißen. Klick auf „RAM“ in [data-testid="sp-metric-select"] (nicht auf den gleichnamigen Tabellenkopf), dann muss dieser Knopf aria-pressed="true" tragen. |
serverpuls-ausfall |
standard, Szenario fehler |
GET **/api/serverpuls/overview mit 500 { error: 'Test: Serverpuls ist nicht erreichbar.' } beantworten. sp-error muss sichtbar sein, das Diagramm gezeichnet und die Tabelle da. |
- Step 3: Gate festlegen
In gates.mjs kommt nach der Deklaration von GATES dazu. Das Gate p9 erbt Prüfungen und Ansichten von p8 (die p1-Prüfungen für alle Ansichten, step-failed, external-request und console-error immer) und schaltet icon-svg zusätzlich für die Ansichten von P9 und aller früheren Pakete ein:
const iconSvg = GATES.p8.scoped['icon-svg']
GATES.p9 = {
...GATES.p8,
scoped: {
...GATES.p8.scoped,
'icon-svg': {
...iconSvg,
views: [...iconSvg.views, 'serverpuls', 'serverpuls-ok', 'serverpuls-veraltet', 'serverpuls-projekt', 'serverpuls-ausfall'],
},
},
}
- Step 4: Sparklines vom Icon-Check ausnehmen
checks.mjs: Der Check icon-svg nimmt svg.sp-spark dauerhaft aus (wie .brand), nicht über ignore im Gate. Es sind Datengrafiken (Inline-SVG-Minikurven), keine Icons. Die Konsolen-Ausnahme des Szenarios fehler deckt auch die Meldungen zu **/api/serverpuls/** ab, falls sie das noch nicht tut.
- Step 5: Ausgangslauf
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9-vorher && "$W/shots.sh" p9-vorher "$W/shots/p9-vorher" --only serverpuls --gate p9
Expected: Exit 0. Der Stand nach P1 ist hell, und die Sparklines sind ausgenommen. Die Bilder dienen als Vergleich.
Task 4: Kopf, Warnungen, Kacheln, Umschalter, Panels
Files:
- Modify:
src/pages/ServerpulsPage.jsx(LEVEL_*Z. 31–32,TileZ. 79–100,PillsZ. 102–117,CleanupZ. 119–139, Markup Z. 254–331; Abfragen und Hooks Z. 141–239 bleiben) - Rewrite:
src/styles/serverpuls.css(ohne die Tabellenregeln, die bleiben bis Task 5)
Interfaces:
-
Consumes:
Stat({ label, value, sub, tone }),PageHeader,badgeToneClass(tone)aussrc/components/ui/tones.js,Badge,deltaDir,deltaSign,levelTone(Task 2),formatDelta. -
Produces: nichts für spätere Pakete.
-
Step 1: Kopf und Fehlerzeile
-
Fehler:
<div className="msg err" data-testid="sp-error" role="alert">. -
Kopf:
<section data-testid="sp-head">ohnesp-level-*. Die Kopfzeilediv.sp-head-topenthält:<span className={badgeToneClass(levelTone(level))} data-testid="sp-ampel" data-level={level}>{LEVEL_TEXT[level] || level}</span>.LEVEL_TEXTist die schon vorhandene, bisher ungenutzte Konstante („Alles ok“, „Warnungen“, „Critical“), das Emoji unddotentfallen.- die
<strong className="sp-headline">mit dem unveränderten Text undsp-age. Beiage.stalekommt zusätzlich die Klassesp-age-stale.
-
Ohne
overviewzeigt das Badgebadge plainmit „–“,data-levelbleibtok.
Entscheidung: Das Badge nennt die Stufe aus LEVEL_TEXT, die Überschrift bleibt wörtlich („Alles ok“, „Critical – 2 Warnungen“, „2 Warnungen“). Die Doppelung ist gewollt. Ohne Daten steht „–“ statt „Alles ok“, damit der Fehlerzustand nicht grün aussieht.
- Step 2: Warnungen
ul.sp-alerts[data-testid=sp-alerts] mit li.list-row.sp-alert[data-testid=sp-alert]:
-
Links
div.sp-alert-mainmit<Badge tone={levelTone(a.level)}>{LEVEL_LABEL[a.level] || a.level}</Badge>,span.sp-alert-titleundspan.sp-alert-value. -
Rechts
<span className="muted small nowrap">seit {formatSince(a.since)}</span>. -
Step 3: Kacheln, Umschalter, Panels, Aufräumbar
-
Kacheln:
<section className="stats sp-tiles" data-testid="sp-tiles">. Jede Kachel istdiv.sp-tile[data-testid="sp-tile-<id>"]mitStat label value sub,Sparkline width={120} height={32}und der Delta-Zeile.subistmodel?.sub || '\u00a0', damit die Sparklines einer Reihe fluchten.- Die Delta-Zeile ist
div.sp-tile-delta.sp-delta-{dir}mit{deltaSign(dir)}{model.fmtDelta(d)} ggü. gestern.dirkommt ausdeltaDir(d), die Glyphen ▲ und ▼ entfallen.
-
Pillsrendert<div className="seg" data-testid={testid}>mit<button type="button" className={active ? 'on' : undefined} aria-pressed={active}>. -
Panels:
<section className="sp-panel" data-testid="sp-chart-panel">mit<h2 className="section">Verlauf</h2>, darunterdiv.sp-controlsmit beidenPills, dann das Diagramm.sp-projectsundsp-cleanupfolgen demselben Muster.- „Größen von {Tag}“ steht als
<span className="muted small">inh2.sectionrechts. - Die Detail-Überschrift ist
<h3 className="sp-detail-title">, ihrePillsstehen indiv.sp-controls.
-
„Aufräumbar“:
div.stats.sp-cleanup-statsmit dreiStat(„Ungenutzte Images“, „Build-Cache“, „Gestoppte Container“), die Liste der gestoppten Container alsli.list-rowmit Name und<span className="num">-Größe, der Stand-Satz als<p className="muted small">. „Noch keine Messung.“ bekommt.muted. -
Alle
sp-muted,sp-smallwerdenmuted,small..sp-nodatableibt als Klasse für „Lädt …“ und „Für diesen Zeitraum …“.
Entscheidung: Die Panels sind <section data-testid> mit h2.section statt Card, weil Card kein data-testid weitergibt. Die Umschalter stehen unter der Überschrift, nicht darin, damit der Kopf auf dem Handy nicht überläuft.
- Step 4:
serverpuls.cssneu schreiben
Gelöscht werden .sp-page-Flex, alle Kästen, Rahmen und Literale, .sp-level-*, .sp-ampel, .sp-tile-label/-value/-sub, .sp-pill*, .sp-panel-head, .sp-cleanup-grid. Neu:
| Regel | Wert |
|---|---|
.sp-page .msg |
margin: 0 0 16px |
.sp-head-top |
display: flex; align-items: center; gap: 12px; flex-wrap: wrap |
.sp-headline |
font-size: 16px; line-height: 24px; font-weight: 600 |
.sp-age |
margin-left: auto; font-size: 13px; color: var(--text-2) |
.sp-age-stale |
color: var(--orange-fg); font-weight: 500 |
.sp-alerts |
list-style: none; margin: 12px 0 0; padding: 0 |
.sp-alert-main |
display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-width: 0 |
.sp-alert-title |
font-weight: 500; overflow-wrap: anywhere |
.sp-alert-value |
color: var(--text-2) |
.stats.sp-tiles |
display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 24px 32px (ohne margin) |
.sp-tile |
min-width: 0 |
.sp-tile .sub |
min-height: 16px (Größe und Farbe kommen von .stat .sub) |
.sp-spark |
display: block; max-width: 100%; margin-top: 6px |
.sp-tile-delta |
font-size: 12px; line-height: 16px; margin-top: 4px |
.sp-delta-up / -down / -flat |
color: var(--red-fg) / var(--green-fg) / var(--text-2) |
.sp-panel |
min-width: 0 (ohne margin) |
.sp-controls |
display: flex; flex-wrap: wrap; gap: 8px 16px; margin-bottom: 12px |
.sp-controls .seg |
flex-wrap: wrap |
.sp-chart |
width: 100%; min-height: 200px |
.sp-chart .u-legend |
font-size: 13px; color: var(--text-2) |
.sp-nodata |
padding: 40px 0; text-align: center; color: var(--text-2) |
.sp-detail |
margin-top: 28px (ein div im Panel, keine section) |
.sp-detail-title |
margin: 0 0 8px; font-size: 15px; line-height: 22px; font-weight: 600; overflow-wrap: anywhere |
.sp-detail-charts |
display: grid; grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr)); gap: 24px |
.sp-chart-title |
font-size: 13px; color: var(--text-2); margin-bottom: 4px |
.sp-cleanup-list |
list-style: none; margin: 12px 0; padding: 0 |
≤ 1100 px .stats.sp-tiles |
grid-template-columns: repeat(3, minmax(0, 1fr)) |
≤ 860 px .stats.sp-tiles |
grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 24px |
≤ 860 px .sp-age |
margin-left: 0 |
≤ 860 px .sp-page .sp-cleanup-stats |
grid-template-columns: repeat(2, minmax(0, 1fr)) |
Den Abstand zwischen Kopf, Kacheln und Panels liefert .page section + section aus P1. .stats.sp-tiles und .sp-panel setzen deshalb keinen oberen Außenabstand. Ein margin auf .stats.sp-tiles würde den globalen Abstand wegen der höheren Spezifität überstimmen.
- Step 5: Bauen und prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9 && "$W/shots.sh" p9 "$W/shots/p9-t4" --only serverpuls,serverpuls-ok,serverpuls-veraltet,serverpuls-ausfall --gate p9
Expected: PASS. In den Bildern gilt:
-
Keine Kästen um Kopf, Kacheln und Panels.
-
Das Badge trägt „Critical“ (rot), „Warnungen“ (orange) bzw. „Alles ok“ (grün). Veraltete Daten stehen als oranger Text.
-
Warnungen sind Zeilen mit Haarlinien und Stufen-Badge (Critical rot, Medium orange, Low grau).
-
Die Kacheln stehen bei 1440 px in sechs Spalten, bei 390 px in zwei. Deltas sind rot oder grün ohne Pfeil.
-
Der Umschalter ist grau mit weißem aktivem Teil und bricht bei 390 px um.
-
Das Diagramm hat eine schwarze Linie, die Spitze ist grau gestrichelt, es gibt nur horizontale Rasterlinien, und die Legende ist 13 px grau.
-
Kopf, Kacheln und Panels haben überall denselben Abstand (36 px aus
.page section + section). -
Step 6: Commit
git add src/pages/ServerpulsPage.jsx src/styles/serverpuls.css
git commit -m "Design: Serverpuls-Kopf mit Text-Badge, Warnungen als Zeilen, Kacheln als Kennzahlen" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 5: Projekttabelle
Files:
- Modify:
src/components/serverpuls/AppsTable.jsx(Spaltenliste Z. 5–12,DeltaZ. 14–18, Markup Z. 42–89; Sortier- und Filterlogik Z. 20–40 bleibt) - Modify:
src/styles/serverpuls.css(Tabellenregeln.sp-searchbis.sp-deltaersetzen)
Interfaces:
-
Consumes:
.table,tr.row,.toolbar,.input.search,.hide-sm,.num,.right(P1),isRowActivation(event)aussrc/lib/rowClick.js(P2 Task 2, Prüfung in Task 1),formatBytes,formatDelta,formatPct,Sparkline. -
Produces:
AppsTable({ rows, selectedId, onSelect })behält seine Props. -
Step 1: Markup umbauen
-
Die Wurzel
div.sp-apps[data-testid=sp-apps]bleibt. Die Suche steht in<div className="toolbar">als<input className="input search" type="search" data-testid="sp-apps-search" placeholder="Projekt suchen …">. -
<table className="table">ohne.sp-table-wrap. Die Spaltenliste bekommt je Eintragnum(Größe, Δ 7 T, Δ 30 T, CPU, RAM) undhide(Δ 30 T, CPU und die Spalte „30 Tage“). Diese Spalten tragenright numbzw.hide-smaufthundtd. -
Sortierkopf:
<th data-sort={c.key} aria-sort={…}>mit<button type="button" className="sp-sort" onClick={() => toggle(c.key)}>{c.label}<span aria-hidden="true">{' ↑' | ' ↓' | ''}</span></button>.aria-sortistascendingbzw.descendingam aktiven Kopf, sonst fehlt es.- Die Zeichen ↑ und ↓ bleiben wie bisher.
-
Zeile:
<tr className={`row${selected ? ' sp-row-active' : ''}`} data-testid="sp-app-row" data-app-id={r.id}>.- Der Zeilenklick ruft
onSelect(selectedId === r.id ? null : r.id), aber nur wennisRowActivation(e)wahr ist. - Die erste Zelle ist
<td className="sp-name"><button type="button" className="link" aria-pressed={selected} onClick={() => onSelect(selectedId === r.id ? null : r.id)}>{r.name}</button></td>mit demselben Aufruf. Der Button braucht ihn, weilisRowActivationKlicks aufbuttonausfiltert.
- Der Zeilenklick ruft
-
Deltarendert<span className={`sp-delta sp-delta-${d.dir}`}>{d.text}</span>ohne Pfeil. Das Vorzeichen steckt ind.text. -
Die Leerzeile bleibt (
colSpan={7}, „Keine Projekte gefunden.“, Klassesp-empty).
Entscheidung: Die Zeilen folgen der Tabellenregel der Spec. Der Button in der ersten Zelle trägt die Tastaturbedienung, der Zeilenklick bleibt für die Maus. Unter 860 px bleiben Projekt, Größe, Δ 7 T und RAM.
- Step 2: Tabellen-CSS ersetzen
Gelöscht werden .sp-search, .sp-table-wrap, .sp-table*, .sp-sortable, .sp-row, .sp-row:hover, .sp-delta. Neu:
| Regel | Wert |
|---|---|
.sp-sort |
display: block; width: 100%; text-align: inherit; white-space: nowrap (Knopf-Reset und Innenabstand 0 kommen aus der Basis) |
.sp-name |
overflow-wrap: anywhere |
.sp-name .link |
text-align: left; overflow-wrap: anywhere |
.sp-page .table tr.sp-row-active td |
background: var(--bg-subtle) |
.sp-page .table tr.sp-row-active td:first-child / :last-child |
box-shadow: -12px 0 0 var(--bg-subtle) / 12px 0 0 var(--bg-subtle) |
.sp-empty |
text-align: center; color: var(--text-2) |
.sp-delta |
font-variant-numeric: tabular-nums |
- Step 3: Bauen und prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9 && "$W/shots.sh" p9 "$W/shots/p9-t5" --only serverpuls,serverpuls-projekt --gate p9
Expected: PASS, das heißt:
-
Die Tastaturschritte laufen durch.
-
Die Tabelle hat nur Haarlinien, Zahlen stehen rechts, die ausgewählte Zeile ist
--bg-subtle. -
Deltas sind rot, grün oder grau ohne Pfeil. Das Detail zeigt drei Diagramme in Schwarz.
-
Bei 390 px sind vier Spalten da und der lange Projektname bricht um.
-
Step 4: Commit
git add src/components/serverpuls/AppsTable.jsx src/styles/serverpuls.css
git commit -m "Design: Serverpuls-Projekttabelle (Sortierkoepfe und Zeilen als Buttons, Deltas als Farbe)" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 6: Gate P9, Review, Tag
- Step 1: Rebase
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git rebase origin/test && "$W/check.sh"
Expected: Exit 0, Rebase ohne Konflikt, # fail 0. Die Testzahl ist N0 + 2. Liegen neue Commits auf test, kann sie höher sein, die Zahl wird notiert. So zeigen die Bilder der folgenden Schritte den Stand, der getaggt wird.
- Step 2: Vollständiger Gate-Lauf
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9 && "$W/shots.sh" p9 "$W/shots/p9" --gate p9
Expected: Exit 0. Das Gate p9 prüft alle Ansichten mit den p1-Prüfungen (overflow-x, dark-surface, low-contrast) und icon-svg für die Ansichten von P2 bis P9. Die fünf P9-Ansichten haben Bilder bei 1440 und 390 px ohne Verstöße.
- Step 3: Test-IDs, Farben, unveränderte Logik
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -o --no-filename 'testid=("sp-[a-z-]+"|\{`sp-tile-\$\{id\}`\})' src/pages/ServerpulsPage.jsx src/components/serverpuls | sort | diff - "$W/p9-testids.before.txt"
Expected: keine Ausgabe, also dieselben 20 Einträge.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "react-icons|@tabler|style=\{|#[0-9a-fA-F]{3,8}\b|rgba?\(|!important|▲|▼|🔴|🟠|🟢" src/pages/ServerpulsPage.jsx src/styles/serverpuls.css src/components/serverpuls --glob '!chartColors.js'
Expected: keine Treffer.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git diff design-p8 -- src/pages/ServerpulsPage.jsx | rg '^[-+].*(setInterval|60000|visibilit|reqId|serverpulsApi)'; git diff --stat design-p8 -- src/components/serverpuls/Chart.jsx src/components/serverpuls/Sparkline.jsx
Expected: beide Ausgaben leer, weil Takt, Abfragen, Chart.jsx und Sparkline.jsx unverändert sind.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/css-klassen.mjs" "$WT" | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.dead.filter(n=>/^sp-/.test(n)).concat(j.undefinedUsed.filter(n=>/^sp-/.test(n))).join('\n'))"
Expected: leer, also keine tote und keine undefinierte sp-*-Klasse.
- Step 4: Bundle-Größe
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-build
Expected: Exit 0, CSS kleiner als bei Task 1. Die Werte werden notiert.
- Step 5: Code-Review (sonnet)
Geprüft wird der Diff design-p8..HEAD gegen die Spec-Abschnitte „Diagrammfarben“, „Bausteine“ (Kennzahlen, Umschalter, Tabelle, Liste, Badge, Meldungen) und Paket P9. Wichtige Befunde werden behoben. Danach kommen Step 1 (Rebase) noch einmal und Step 2 als Kurzlauf mit --only serverpuls,serverpuls-projekt. Schwerpunkte:
-
Die Test-IDs und Abfragen sind unverändert.
-
Der Fehlerzustand zeigt kein grünes „Alles ok“.
-
Das Vorzeichen steht weiter in jeder Delta-Zahl.
-
Die Tastaturbedienung funktioniert (Zeilen, Sortierköpfe, Umschalter).
-
Step 6: Tag und Übergabe
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && git tag design-p9 && git log --oneline origin/test..design-p9 && git rev-parse design-p9
Der Eigentümer bekommt:
-
die Screenshots aus
$W/shots/p9(Unterordner1440x900und390x844; Auswahl:serverpuls,serverpuls-ok,serverpuls-projekt,serverpuls-ausfall) -
den Hinweis, dass das Kopf-Badge „Alles ok“ und die Überschrift „Alles ok“ doppelt stehen (Entscheidung aus Task 4), falls er die Doppelung streichen will
-
die Push-Zeile
git -C /home/webklar/apps/ticket.webklar.com/dev-design push origin 'design-p9^{commit}:refs/heads/test' -
die Rücknahme
git revert --no-commit design-p8..design-p9, Commit und Push durch den Eigentümer (gilt nur, solange P9 das jüngste Paket auftestist) -
Step 7: Nach dem Push (erst, wenn der Eigentümer gepusht hat)
-
Im Log von
webklar-ticket-buildsteht „Deployment completed successfully“. -
curl -s https://ticket.webklar.com/ | grep -o 'assets/index-[^"]*\.js'entsprichtdist/index.htmldes Tags. -
Ein lesender Sichttest im Chrome des Eigentümers: Serverpuls mit Diagramm und Projekttabelle. Der Menüpunkt zeigt weiter den Punkt
sp-nav-dot, wenn es Warnungen gibt.