Umsetzungsplaene je Paket mit gemeinsamen Regeln (env.sh/check.sh, Gate-Schema, CSS-Reihenfolge, TP2-Pruefung vor jedem Paket) und den Schnittstellen aus P1. Gegen Spec und untereinander geprueft (zwei Pruefer, Korrekturrunde, Nachpruefung). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
35 KiB
WOMS „Weißes Design“ P1: Fundament – 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 P1 ist das ganze Ticketsystem weiß und lesbar:
- Das Menü ist eine Textliste.
- Das Login ist neu.
- Alle Dialoge sind weiß.
- Die neuen Bausteine stehen für P2 bis P9 bereit.
Die Innenlayouts der Seiten bleiben vorerst alt.
Architecture: src/styles/global.css bekommt fünf Blöcke:
- Tokens und Aliase
- Basis (Reset, Hilfsklassen, Links)
- Bausteine (Prototyp-Klassen)
- KOMPAT (Altklassen im neuen Look, bis P10)
- Bereichs-CSS (Finanzen, Rechtliches), bis auf Pflicht-Fixes unverändert
Gleichnamige Altdefinitionen werden vor dem Einfügen der Bausteine gelöscht. Die Komponenten unter src/components/ui/ behalten ihre Schnittstellen. Neu kommen Dialog, Stat, Logo und statusTone hinzu.
Tech Stack: React 18, react-router-dom 6, Vite 5, reines CSS. Tests mit node --test, Screenshots mit dem Werkzeug aus P0.
Spec: docs/superpowers/specs/2026-10-04-weisses-design-design.md, Abschnitte „Gestaltungsregeln“, „Design-Tokens“, „Bausteine“, „Übergangsschicht KOMPAT“ und Paket P1. Die Prototyp-Werte stehen in /root/reports/ticketsystem-design-2026-10-04/quelle/styles.css. Globale Regeln, Befehlsregeln (env.sh, check.sh) und gemeinsame Schnittstellen stehen in 2026-10-05-weisses-design-00-uebersicht.md.
Global Constraints
Es gelten die Regeln der Übersicht. Für P1 kommt hinzu:
- Jeder Run-Block beginnt mit
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh. Danach gelten$WT,$Wund$TMPDIR. - Werte für Tokens, Abstände, Größen und Schatten werden aus der Spec bzw. aus
quelle/styles.cssübernommen und nicht neu erfunden. - Nicht übernommen werden
html[data-accent],.proto*und.nav-gap. - Verhalten, Routen und Auth bleiben unverändert. Ausnahmen:
- Der Footer entfällt.
- Das Einklappen entfällt.
- Die Schublade unter 860 px kommt neu dazu.
- Seiten in
src/pages/*werden nur dort angefasst, wo dieser Plan es nennt:LoginPageProjectsPage: WurzelklasseAdminPage: WurzelelementServerpulsPage: Diagrammfarben
- Die Spec erlaubt keine neue
robots-Meta-Zeile.index.htmlbekommt nur das Favicon.
Review Focus
- Übersichtspunkt 2 (lange Inhalte am Handy):
overflow-xist im Gatep1für alle Ansichten scharf. - Übersichtspunkt 4 (Tastatur): Die Esc- und Sperrlogik des Dialogs prüft ein Lib-Test in Task 7.
- Altseiten: Jede Altseite bleibt mit KOMPAT lesbar. Das prüft das Gate
p1mitdark-surfaceundlow-contrast, auch für Verläufe. - Alt-Dialoge: Die zehn Alt-Dialoge müssen bei 390×700 und 1440×700 bis zum Speichern-Knopf erreichbar sein. Das prüft
submitReachablein jederdlg-*-Ansicht.
Task 0: Paketstart
- Step 1: Stand prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git merge-base --is-ancestor design-p0 HEAD && git log --oneline origin/test..origin/feature/terminplaner-tp2 -- src/styles src/components/ui src/App.jsx src/components/Navbar.jsx src/pages/LoginPage.jsx src/lib/navLinks.js src/lib/ticketStatus.js && git rebase origin/test && "$W/check.sh"
Expected:
-
Exit 0.
-
Die TP2-Zeile gibt nichts aus. Gibt sie etwas aus: stoppen und den Eigentümer fragen. Empfehlung: TP2 zuerst nach
testbringen. -
Step 2: Gate
p1um die Menü-Prüfung ergänzen
In $W/gates.mjs bekommt p1 den Eintrag scoped: { 'icon-svg': { views: '*', ignore: ['#inhalt *'] } }. Damit prüft icon-svg ab P1 Menü, Mobil-Leiste und Login auf allen Ansichten, den Seiteninhalt aber erst ab dem jeweiligen Paket.
Task 1: statusTone
Files:
- Modify:
src/lib/ticketStatus.js(neuer Export nachstatusGroup) - Test:
tests/unit/ticketStatus.test.mjs(neu)
Interfaces:
-
Consumes:
statusGroup(status)aus derselben Datei. Es liefert die Gruppen-ID odernull. -
Produces:
statusTone(status) → '' | 'blue' | 'orange' | 'violet' | 'green' | 'plain'. -
Step 1: Failing Test
const { statusTone } = await loadModule('src/lib/ticketStatus.js')
test('statusTone: Ton je gespeichertem Wert', () => {
for (const s of ['Open', '', undefined, null, 'Completed']) assert.equal(statusTone(s), '')
for (const s of ['Occupied', 'Assigned', 'Added Info', 'In Kontakt']) assert.equal(statusTone(s), 'blue')
for (const s of ['Awaiting', 'Halted']) assert.equal(statusTone(s), 'orange')
assert.equal(statusTone('In Test'), 'violet')
for (const s of ['Closed', 'Zugesagt']) assert.equal(statusTone(s), 'green')
for (const s of ['Cancelled', 'Aborted', 'Abgesagt']) assert.equal(statusTone(s), 'plain')
})
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/ticketStatus.test.mjs
Expected: FAIL, statusTone is not a function.
- Step 2: Implementieren
Zuordnung über statusGroup:
| Gruppe | Ton |
|---|---|
open |
'' |
working |
'blue' |
waiting |
'orange' |
review |
'violet' |
done |
'green' |
cancelled |
'plain' |
null |
'' |
statusClass bleibt bis P2.
- Step 3: Grün
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/ticketStatus.test.mjs && "$W/check.sh" --nur-tests
Expected: PASS, Exit 0.
- Step 4: Commit
git add src/lib/ticketStatus.js tests/unit/ticketStatus.test.mjs
git commit -m "Ticketstatus: statusTone fuer die neuen Badge-Toene" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 2: Tokens, Aliase, Basis, Schrift
Files:
- Modify:
src/styles/global.css- Zeilen 1-10 (
@font-face) löschen :root, alte Zeilen 18-71, ersetzenbody/Scrollbar/::selection, alte Zeilen 73-106, ersetzen- alte Hilfsregeln
.muted/.faint(um Zeile 1051) ersetzen
- Zeilen 1-10 (
- Modify:
src/pages/AdminPage.css(Zeilen 2-3,--admin-line*, löschen) - Delete:
src/assets/fonts/lato-regular.ttf,src/assets/fonts/OFL-Lato.txt - Modify (Werkzeug):
$W/views.mjsbekommt die Ansichtbasis-weiss
Interfaces:
-
Produces: alle Tokens und Aliase der Spec, dazu die Basis- und Hilfsklassen aus der Übersicht.
-
Step 1: Prüf-Ansicht (failing)
basis-weiss öffnet /tickets. Der Schritt prüft, dass getComputedStyle(document.body).backgroundColor === 'rgb(255, 255, 255)' und dass font-family mit -apple-system beginnt.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t2" --only basis-weiss --gate p0
Expected: Exit 1 mit step-failed.
-
Step 2:
:rootersetzen -
Den Token-Block der Spec wörtlich übernehmen.
-
Darunter folgt die Alias-Tabelle der Spec. Sie enthält
--admin-lineund--admin-line-strong. -
Die beiden Zeilen in
AdminPage.cssentfallen. -
Step 3: Basis setzen
Aus quelle/styles.css Zeilen 63-91 übernehmen. Zusätzlich gilt:
| Regel | Wert |
|---|---|
html |
color-scheme: light |
body |
font-family: var(--font); font-size: 14px; line-height: 20px; color: var(--text); background: var(--bg); -webkit-font-smoothing: antialiased, ohne overflow: hidden |
| Formularelemente | button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer } und input, select, textarea { font: inherit; color: inherit } |
a |
color: inherit; text-decoration: none |
a:not([class]) |
Unterstrich in --line-strong, text-underline-offset: 3px, beim Überfahren text-decoration-color: currentColor |
| Hilfsklassen | .num (tabular-nums), .muted (--text-2), .faint (--text-3), .small 13px, .xs 12/16, .strong 600, .nowrap |
.link, .link:hover, .link-danger, .link-danger:hover |
Werte aus dem Prototyp |
:focus-visible |
outline: 2px solid #111111; outline-offset: 2px |
:disabled |
opacity: .55; cursor: not-allowed |
[readonly] |
background: var(--bg-subtle) |
- Step 4: Schrift entfernen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git rm -q src/assets/fonts/lato-regular.ttf src/assets/fonts/OFL-Lato.txt && rg -n "lato|Lato" src
Expected: keine Treffer.
- Step 5: Grün
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t2" --only basis-weiss --gate p0
Expected: Exit 0.
- Step 6: Commit
git add src/styles/global.css src/pages/AdminPage.css
git commit -m "Design: weisse Tokens, Aliase, Basis und Hilfsklassen, Systemschrift" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 3: Bausteine-CSS
Files:
- Modify:
src/styles/global.css: Altdefinitionen gleichnamiger Klassen löschen, Block „Bausteine“ hinter der Basis anlegen
Interfaces:
-
Produces: alle Klassen aus der Übersicht („CSS-Klassen in
global.css“). -
Step 1: Gleichnamige Altdefinitionen löschen
Gelöscht werden die Regeln dieser Selektoren samt ihrer Varianten (Hover, Kinder, Media-Queries). Die Zeilenangaben beziehen sich auf den Stand 603d08c, gesucht wird nach dem Selektor:
| Selektor | Zeilen (603d08c) |
|---|---|
.btn und .btn:hover, ohne .btn-dark/.btn-teal/.btn-green (die gehen nach KOMPAT bzw. sterben in Task 8) |
ab 188 |
.table, .table th, .table td, .table td[rowspan] |
236-275 |
.overlay und .overlay-close (Neufassung in KOMPAT, Task 4) |
ab 563 |
.page |
867 |
.badge (Basis) |
909-915 |
.urgent-toggle |
971-976 |
.list-row |
997-1005 |
.toolbar |
1018 |
.seg |
1019-1024 |
.empty |
1028 |
.field |
1032 |
Der übrige alte Block „REDESIGN“ (796-1049) bleibt bis Task 4. Dazu gehören .ui-card*, .ui-btn*, .badge-*, .kpi*, .tcard*, .ui-table, .list, .ticket-tabs/.ticket-tab* und die Hilfsregeln .mt-*, .flex*, .gap-*, .grow, .wrap und .text-ellipsis.
- Step 2: Bausteine übernehmen
Aus quelle/styles.css werden diese Abschnitte übernommen:
- „Grundgerüst“ ohne
.nav-gap - „Seitenkopf“
- „Knöpfe“
- „Status-Marken“
- „Reiter“
- „Filterzeile“
- „Tabellen“
- „Kennzahlen / Schlüsselwerte“
- „Ticket-Kopf“
- „Listen“
- „Dialog“
- „Anmeldung“
Dazu kommen die Media-Queries 1100 und 860. Ausgeschlossen sind dort .proto*, .ws*, .week, .day* und .appt (sie kommen mit P2 und P3) sowie html[data-accent].
Zusätzlich:
| Regel | Wert |
|---|---|
.page section + section |
margin-top: 36px |
.nav-dot |
background: var(--nav-dot) |
.nav-dot.critical |
background: var(--danger) |
.dialog-wide |
max-width: 760px |
.msg |
13px |
.msg.err |
Farbe --red-fg |
.msg.ok |
Farbe --green-fg |
.msg.warn |
Farbe --orange-fg |
.loading |
padding: 56px 0; text-align: center; color: var(--text-2) |
.v.neg |
Farbe --red-fg |
.stat .sub |
font-size: 12px; line-height: 16px; color: var(--text-2) |
.badge.plain |
Farbe --text-2 |
.tab.active, .tab[aria-selected="true"] |
aktiver Reiter |
.seg button.on, .seg button[aria-pressed="true"] |
aktiver Teil |
.autocomplete-list |
background: var(--bg); box-shadow: var(--shadow-pop); border-radius: 8px |
.autocomplete-item.active, .autocomplete-item:hover |
background: var(--bg-hover) |
.datetime-pair |
zwei Felder nebeneinander, Abstand 8px, kein color-scheme: dark |
[aria-invalid="true"] und .is-invalid an .input, .select, .textarea, .form-control |
box-shadow: 0 0 0 1px var(--danger), 0 0 0 4px var(--danger-ring) |
- Step 3: Jede Basisregel genau einmal
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && for s in btn table overlay page badge urgent-toggle list-row toolbar seg empty field; do printf '%s ' "$s"; rg -c "^\.$s( |\{|,)" src/styles/global.css; done
Expected: Hinter jedem Namen steht 1.
- Step 4: Bauen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-build
Expected: Exit 0.
- Step 5: Commit
git add src/styles/global.css
git commit -m "Design: Bausteine aus dem Prototyp, gleichnamige Altregeln ersetzt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 4: KOMPAT und tote Klassen
Files:
- Create:
$W/css-klassen.mjs - Create:
docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md - Modify:
src/styles/global.css(Block „KOMPAT“, Legacy löschen)
Interfaces:
-
Produces:
- Der KOMPAT-Block nach der Spec-Tabelle „Übergangsschicht KOMPAT“. P10 entfernt ihn.
css-klassen.mjs <worktree> [--ohne-ausnahmen]gibt JSON aus:{ defined, used, dead, undefinedUsed }.
-
Step 1: Skript schreiben
„Benutzt“ ist eine Klasse, wenn eine dieser Bedingungen zutrifft:
- Sie steht als Wort in einem
className-Literal oder Template-String insrc/**/*.jsx. - Sie steht in einer Zeichenkette in
src/lib/*.jsodersrc/hooks/*.js. - Ein Template-Präfix deckt sie ab:
xxx-${…}gilt fürxxx-*. - Sie steht in der Ausnahmeliste:
fin-neg,fin-fixed-off,legal-tone-*,legal-version-*,badge-*,status-*,ticket-tab-active,ui-btn-*,side-dot-*,woms-chat,chat-*. Mit--ohne-ausnahmenentfällt diese Liste.
„Definiert“ ist eine Klasse, wenn sie in einem Selektor in global.css, chat.css, serverpuls.css, admin-areas.css oder pages/AdminPage.css steht.
- Step 2: Liste erzeugen und gegenprüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/css-klassen.mjs" "$WT" > "$TMPDIR/klassen.json"
Danach für jeden Kandidaten in dead: rg -w <name> src --glob '!*.css'. Ein Kandidat gilt nur bei 0 Treffern als tot. Die bestätigte Liste kommt mit Klassenname und definierender Datei:Zeile in 2026-10-05-weisses-design-p1-tote-klassen.md.
Expected: etwa 66 Namen. Liegt die Zahl unter 40 oder über 90, wird die Abweichung dort begründet.
- Step 3: Legacy löschen, KOMPAT anlegen
Gelöscht werden:
- die Regeln der bestätigten toten Klassen
- alle verbliebenen
!important .side*außer.side-countund.side-logo(die gehen nach KOMPAT).footer,.navbar*,.ticket-row*,.worksheet-expansion*,.slider,.drop-zone,.modern-card- die Legacy-Responsive-Regeln (alt 789-794)
- die Keyframes
slideDown,fadeInundslideIn .kpi*, weilKpiab Task 6Statrendert
Danach wird KOMPAT laut Spec-Tabelle angelegt, markiert mit /* ===== KOMPAT (bis P10) ===== */. Der Block enthält auch .page .page und .page .main-content, die Abstand und Breite neutralisieren.
- Step 4: Keine benutzte Klasse ohne Regel
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.undefinedUsed.join('\n'))"
Expected: Nur diese Namen tauchen auf:
-
p-4,btn-sm,status-filter,supporters-editor,timeline -
die Bootstrap-Namen aus
WorksheetList.jsx(heute schon wirkungslos) -
Step 5: Altseiten ansehen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t4" --gate p1; echo "exit $?"
Expected: step-failed (submitReachable) ist auf keiner dlg-*-Ansicht mehr gemeldet. Erlaubt sind nur noch Treffer dark-surface und low-contrast in Dateien aus Task 9.
- Step 6: Commit
git add src/styles/global.css docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md
git commit -m "Design: KOMPAT-Schicht fuer Altklassen, tote Regeln und !important entfernt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 5: Gerüst, Menü, Logo, Favicon
Files:
- Create:
src/components/Logo.jsx,public/favicon.svg(Kopie vonquelle/favicon.svg) - Modify:
src/App.jsxsrc/components/Navbar.jsxsrc/lib/navLinks.js(hot: trueam Chat-Unterpunkt)index.html(nur<link rel="icon" href="/favicon.svg" type="image/svg+xml">)src/styles/serverpuls.css(Zeilen 70-74.side-dot*löschen)src/pages/ProjectsPage.jsx(Wurzelmain-content→page)src/pages/AdminPage.jsx(<main className="page admin-page">→<div className="page admin-page">, zwei Stellen)
- Delete:
src/components/Footer.jsx,src/lib/sidebar.js,tests/unit/sidebar.test.mjs - Test:
tests/unit/navLinks.test.mjs - Modify (Werkzeug):
$W/views.mjsbekommt die Ansichtmenue-mobil
Interfaces:
-
Consumes: Klassen aus Task 3.
-
Produces:
Logo({ size = 24 })mitaria-hidden="true". Die Pfade kommen ausquelle/app.js, KonstanteLOGO.Sidebar({ onNavigate }).
-
Step 1: Test für
hot(failing)
In tests/unit/navLinks.test.mjs die Zeile assert.equal(kunden.children.find((c) => c.key === 'chat').hot, true) ergänzen. Die bestehenden deepEqual bleiben.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/navLinks.test.mjs
Expected: FAIL.
- Step 2:
navLinks.jsergänzen, Test grün
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/navLinks.test.mjs
Expected: PASS.
-
Step 3: Logo und Favicon anlegen
-
Step 4: Gerüst in
App.jsx
AppContent hält menuOpen und baut dieses Gerüst:
<div className={`shell${menuOpen ? ' menu-open' : ''}`}>
<Sidebar onNavigate={close} />
<div className="scrim" onClick={close} />
<div className="main">
<div className="mobile-bar">
<Link className="brand" to="/tickets"><Logo />WEBklar</Link>
<button type="button" className="btn btn-quiet" onClick={open} aria-expanded={menuOpen} aria-controls="menue">Menü</button>
</div>
<main id="inhalt"><AppRoutes /></main>
</div>
</div>
-
Ein Effekt auf
location.pathname(nur darauf) schließt die Schublade und ruftwindow.scrollTo(0, 0)auf. -
Ein Esc-Listener ist nur bei
menuOpenaktiv. -
Der Ladezustand von
ProtectedRouteist<div className="loading">Wird geladen …</div>. -
Step 5:
Navbar.jsxals Textliste
Aufbau: <aside className="sidebar" id="menue">, darin .brand (Logo und „WEBklar“), <nav className="nav"> mit .nav-item und .sub und am Ende .sidebar-foot.
| Element | Markup |
|---|---|
| Pausiert | <span className="nav-item paused" aria-disabled="true">Leads<span className="nav-count">pausiert</span></span> |
| Zähler | <span className={nav-count${child.hot ? ' hot' : ''}}> |
| Serverpuls | <span className={nav-dot${dot === 'critical' ? ' critical' : ''}} data-testid="sp-nav-dot" title=…>, nur wenn dot nicht 'ok' ist. Titeltexte wie heute. |
| Fuß | <span className="who text-ellipsis">{user.name || user.email}</span> und <button type="button" className="link" onClick={handleLogout}>Abmelden</button> |
Klicks auf Einträge rufen onNavigate() auf.
Entfernt werden:
@tabler-Imports undICONS- Einklappen und
startsCollapsed
Bleiben:
-
isActiveundisLinkActive -
das Serverpuls-Polling
-
useSidebarCounts -
Step 6: Altdateien löschen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git rm -q src/components/Footer.jsx src/lib/sidebar.js tests/unit/sidebar.test.mjs && rg -n "Footer|startsCollapsed|lib/sidebar" src tests
Expected: keine Treffer.
- Step 7: Ansicht
menue-mobil
Bei 390×844 läuft:
- Klick auf „Menü“:
.shell.menu-openist da. - Screenshot.
- Esc:
.menu-openist weg. - Menü erneut öffnen, Klick auf „Projekte“: Der Pfad ist
/projects, und das Menü ist zu.
- Step 8: Prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t5" --only tickets,kunden,serverpuls,menue-mobil --gate p1
Expected:
-
Exit 0.
-
Im Menü ist kein
svgaußer dem Logo. -
Step 9: Commit
git add src/App.jsx src/components/Navbar.jsx src/components/Logo.jsx src/lib/navLinks.js tests/unit/navLinks.test.mjs index.html public/favicon.svg src/styles/serverpuls.css src/pages/ProjectsPage.jsx src/pages/AdminPage.jsx
git commit -m "Design: Geruest mit Textmenue, Schublade fuers Handy, Logo; Footer und Einklappen entfallen" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 6: UI-Bausteine
Files:
- Create:
src/components/ui/tones.js,src/components/ui/Stat.jsx - Modify:
Button.jsx,Badge.jsx,Card.jsx,PageHeader.jsx,Tabs.jsx,EmptyState.jsx,Field.jsx,Kpi.jsx,StatusPill.jsx,index.js- nur Klasse
form-control→inputbzw.select:AutocompleteInput.jsx,DateTimeInput.jsx,DurationSelect.jsx
- Test:
tests/unit/uiTones.test.mjs
Interfaces:
-
Produces:
- die Signaturen aus der Übersicht
badgeToneClass(tone) → stringBUTTON_CLASSES
Beide liegen in
tones.js.Buttonsetzt keinen eigenen Standard-type. -
Step 1: Failing Test
const { badgeToneClass, BUTTON_CLASSES } = await loadModule('src/components/ui/tones.js')
test('badgeToneClass', () => {
for (const t of ['muted', 'grey', undefined, 'unbekannt']) assert.equal(badgeToneClass(t), 'badge')
assert.equal(badgeToneClass('info'), 'badge blue')
assert.equal(badgeToneClass('blue'), 'badge blue')
assert.equal(badgeToneClass('ok'), 'badge green')
assert.equal(badgeToneClass('warn'), 'badge orange')
assert.equal(badgeToneClass('danger'), 'badge red')
assert.equal(badgeToneClass('violet'), 'badge violet')
assert.equal(badgeToneClass('plain'), 'badge plain')
})
test('Button-Varianten', () => {
assert.deepEqual(BUTTON_CLASSES, { default: 'btn', ghost: 'btn', primary: 'btn btn-primary', quiet: 'btn btn-quiet', danger: 'link-danger' })
})
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/uiTones.test.mjs
Expected: FAIL.
-
Step 2:
tones.jsanlegen, Test grün -
Step 3: Komponenten umschreiben
| Komponente | Änderung |
|---|---|
Card |
ohne Titel und ohne Aktionen nur <section> |
PageHeader |
Brotkrumen als Link, wenn to gesetzt ist. Das letzte Element ist Text, das „/“ steht in <span className="faint">. |
Tabs |
active und aria-selected |
EmptyState |
ohne Inline-Styles |
Field |
Hinweis als .hint |
Kpi |
gibt Stat zurück |
StatusPill |
ohne pillBase |
- Step 4: Prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t6" --only tickets,ticket,kunde-overview,finanzen --gate p1
Expected: Exit 0. Die Status-Badges in tickets zeigen die neuen Töne.
- Step 5: Commit
git add src/components/ui tests/unit/uiTones.test.mjs
git commit -m "Design: UI-Bausteine rendern die neuen Klassen (Button, Badge, Card, Kopf, Reiter, Stat)" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 7: Dialog
Files:
- Create:
src/components/ui/Dialog.jsx,src/lib/dialogKeys.js - Modify:
src/components/ui/index.js,$W/views.mjs(Ansichtdlg-probe) - Test:
tests/unit/dialogKeys.test.mjs
Interfaces:
-
Consumes:
useDialogFocus(dialogRef)aussrc/hooks/useDialogFocus.js, unverändert. -
Produces:
Dialoglaut ÜbersichtshouldCloseOnKey({ key, defaultPrevented }, busy) → boolean
-
Step 1: Failing Test
const { shouldCloseOnKey } = await loadModule('src/lib/dialogKeys.js')
test('Esc schliesst nur ohne Sperre und ohne vorherige Behandlung', () => {
assert.equal(shouldCloseOnKey({ key: 'Escape', defaultPrevented: false }, false), true)
assert.equal(shouldCloseOnKey({ key: 'Escape', defaultPrevented: true }, false), false)
assert.equal(shouldCloseOnKey({ key: 'Escape', defaultPrevented: false }, true), false)
assert.equal(shouldCloseOnKey({ key: 'Enter', defaultPrevented: false }, false), false)
})
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/dialogKeys.test.mjs
Expected: FAIL.
-
Step 2: Implementieren, Test grün
-
Step 3:
Dialog.jsx
| Teil | Umsetzung |
|---|---|
| Esc | keydown-Listener auf document, prüft mit shouldCloseOnKey(e, busy) und ruft dann onClose() auf |
| Hintergrund | Klick ohne Wirkung |
| Box | role="dialog", aria-modal="true", aria-labelledby={titleId} (useId()), ref, tabIndex={-1} |
| Overlay | onKeyDown aus useDialogFocus |
× |
<button type="button" className="dialog-close" aria-label="Schließen" disabled={busy} onClick={onClose}>×</button> |
as="form" |
die Box ist <form onSubmit> ohne noValidate |
- Step 4:
dlg-probe
Die Ansicht öffnet /tickets und fügt per page.evaluate einen statischen Klon des Dialog-Markups ein: ein Titel, drei Felder und ein Fuß mit Absende-Knopf. Geprüft wird nur das CSS:
- Bei 390 px liegt die Box unten.
- Das Overlay hat Fenstergröße.
submitReachablegelingt bei 390×700.
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/shots.sh" p1 "$W/shots/p1-t7" --only dlg-probe --gate p1
Expected: Exit 0.
- Step 5: Commit
git add src/components/ui/Dialog.jsx src/components/ui/index.js src/lib/dialogKeys.js tests/unit/dialogKeys.test.mjs
git commit -m "Design: Dialog-Baustein (Esc, Sperre waehrend Speichern, Fokus, Bottom-Sheet)" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 8: Login
Files:
- Modify:
src/pages/LoginPage.jsx(nur Markup) - Delete:
src/components/LetterGlitch.jsx
Interfaces:
-
Consumes:
useAuth()mitlogin,mfaPending,sendCode,verifyCodeundcancelMfa, unverändertLogo- die Klassen
.login*,.field,.input,.code-input,.btn-primary.btn-blockund.msg
-
Step 1: Markup ersetzen
Grundaufbau: .login > .login-box > <Logo size={40} />.
Schritt E-Mail und Passwort
| Element | Inhalt |
|---|---|
| Überschrift | h1 „Anmelden“ |
| Unterzeile | .sub „Ticketsystem für das WEBklar-Team“ |
| Feld E-Mail | Label „E-Mail“, type="email", autoComplete="username", Platzhalter deine@email.com |
| Feld Passwort | Label „Passwort“, type="password", autoComplete="current-password", minLength={8} |
| Knopf | .btn.btn-primary.btn-block „Weiter“, beim Laden „Login läuft...“ |
| Fehler | .msg.err mit role="alert" |
Schritt Code
| Element | Inhalt |
|---|---|
| Überschrift | h1 „Code eingeben“ |
| Text | die beiden Bestandssätze wörtlich |
| Hinweis | notice als .msg.ok |
| Feld | #mfa-code mit className="input code-input", Label „Code aus der E-Mail“ |
| Knopf | „Anmelden“ bzw. „Prüfe…“ |
| Links | .login-links mit zwei button.link (type="button"): „Code erneut senden“ und „Abbrechen“ |
Ohne challengeId erscheint stattdessen „Code senden“ bzw. „Sende…“ und darunter „Abbrechen“.
Fuß: .login-foot „Webklar Ticket-Plattform · © {Jahr}“.
Bleibt unverändert: alle Handler und Zustände.
- Step 2:
LetterGlitchlöschen und prüfen
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git rm -q src/components/LetterGlitch.jsx && ! rg -n "LetterGlitch" src && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1-t8" --only login,login-code,login-code-senden --gate p1
Expected: Exit 0. Im Bild login-code-senden steht der Knopf „Code senden“.
- Step 3: Commit
git add src/pages/LoginPage.jsx
git commit -m "Design: neues Login (weiss, Logo, Code-Schritte), Glitch-Hintergrund entfernt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 9: Pflicht-Fixes gegen Unlesbares
Files:
- Create:
src/components/serverpuls/chartColors.js,$W/farben.mjs - Modify:
- CSS:
src/styles/chat.css,src/pages/AdminPage.css,src/styles/admin-areas.css,src/styles/serverpuls.css,src/styles/global.css(Bereich Finanzen und Rechtliches) - Projekt-Bausteine:
src/components/AssignedProjectCard.jsx(Zeilen 27, 82, 102),src/components/PreviewBlock.jsx,src/components/PreviewLinkButton.jsx,src/components/GiteaLinkButton.jsx,src/components/AnalyseRow.jsx(COLORS) - Arbeitsblätter:
src/components/CreateWorksheetModal.jsx(Zeilen 194, 262),src/components/WorksheetTimesModal.jsx(Zeile 143),src/components/WorksheetList.jsx(nur Farben, siehe Step 4) - Serverpuls:
src/components/serverpuls/Chart.jsx,src/pages/ServerpulsPage.jsx(Serienfarben) - Doku:
docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md(Abschnitt „Bewusst offen“)
- CSS:
Interfaces:
-
Produces:
CHARTlaut Übersicht.farben.mjs <worktree>listet je Treffer Datei:Zeile, Literal und Grund:kontrast<3(Text auf Weiß)dunkel-auf-akzentweiss(#fff,#ffffff,white,rgba(255,255,255,x)als Text- oder Randfarbe außerhalb von.btn-primaryund Elementen auf--accent)verlauf(linear-gradientin JSX oder CSS)
-
Step 1: Scan (failing)
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/farben.mjs" "$WT"
Expected: eine Liste mit Treffern aller vier Gründe, unter anderem aus WorksheetList.jsx.
- Step 2: Chat-Variablen
Unter .woms-chat in chat.css:
--chat-accent: var(--accent)--chat-accent-hover: var(--accent-hover)--chat-accent-soft: var(--accent-soft)--chat-accent-line: rgba(17,17,17,.14)--chat-accent-text: var(--accent)--chat-on-accent: #ffffff--chat-surface: var(--bg)--chat-line: var(--line-strong)--chat-muted: var(--text-2)
Weitere Regeln:
-
Rand der eigenen Blase:
var(--line). -
.woms-chat .chat-messages { background: var(--bg) }. -
.woms-chat .chat-composer-note,.woms-chat .chat-tray-item.is-error .chat-file-sizeund.woms-chat .chat-audio.is-error .chat-audio-timebekommencolor: var(--red-fg). -
.woms-chat .chat-composer-note.is-infobekommtcolor: var(--text-2). -
Step 3: Literale umstellen nach fester Zuordnung
| Literal | Token |
|---|---|
#a0aec0, #cbd5e0, #9aa7b4, #e2e8f0 (als Text) |
var(--text-2) |
#34d399, #6ee7b7, #10b981 (als Text) |
var(--green-fg) |
#f87171, #fca5a5, #fecaca, #ef4444 (als Text) |
var(--red-fg) |
#fbbf24, #f59e0b (als Text) |
var(--orange-fg) |
#818cf8, #9d3dfe |
var(--violet-fg) |
#3b82f6, #60a5fa |
var(--blue-fg) |
rgba(255,255,255,x) als Rand oder Linie |
var(--line) |
rgba(255,255,255,x) als Fläche |
entfällt bzw. wird var(--bg-subtle) |
#05251c, #04130d auf Akzent |
#ffffff |
rgba(30,41,59,x) und ähnliche dunkle Flächen |
var(--bg-subtle) |
.admin-primary-button bekommt color: #fff und beim Überfahren background: var(--accent-hover).
- Step 4:
WorksheetList.jsxminimal
Nur die Farben werden geändert:
- Verläufe und Weiß-Alphas gehen auf Tokens nach der Tabelle oben.
- Weiße Schrift auf farbigen Köpfen wird
var(--text)aufvar(--bg-subtle).
Struktur und Klassen bleiben. Den Umbau macht P2.
- Step 5: Diagrammfarben
chartColors.js wird angelegt. Chart.jsx nutzt CHART.axis, CHART.grid (nur horizontal), CHART.tick und als Standard-Serienfarbe CHART.line. ServerpulsPage setzt:
-
alle Serien
CHART.line -
Spitze
CHART.peakmitdash: [4, 4] -
Füllung
CHART.fill -
Step 6: Scan erneut
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/farben.mjs" "$WT"
Expected:
-
Kein Treffer
kontrast<3,dunkel-auf-akzentoderweiss. -
verlauf-Treffer nur dort, wo.btn-primaryoder ein Canvas sie braucht. -
Jeder Rest steht unter „Bewusst offen“ im Dokument mit Zielpaket und gemessenem Kontrast von mindestens 3:1.
-
Step 7: Commit
git add src/components/serverpuls/chartColors.js src/components/serverpuls/Chart.jsx src/pages/ServerpulsPage.jsx src/styles/chat.css src/pages/AdminPage.css src/styles/admin-areas.css src/styles/serverpuls.css src/styles/global.css src/components/AssignedProjectCard.jsx src/components/PreviewBlock.jsx src/components/PreviewLinkButton.jsx src/components/GiteaLinkButton.jsx src/components/AnalyseRow.jsx src/components/CreateWorksheetModal.jsx src/components/WorksheetTimesModal.jsx src/components/WorksheetList.jsx docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md
git commit -m "Design: Pflicht-Fixes gegen helle Schrift und dunkle Flaechen, Diagrammfarben, Chat-Variablen" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
Task 10: Gate P1, 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. Die Testzahl ist 312 − 3 (sidebar) + 1 (statusTone) + 2 (uiTones) + 1 (dialogKeys) = 313. Liegen neue Commits auf test, kann sie höher sein; die Zahl wird notiert.
- Step 2: Vollständiger Gate-Lauf
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p1 && "$W/shots.sh" p1 "$W/shots/p1" --gate p1
Expected: Exit 0 für alle Ansichten aus P0 plus basis-weiss, menue-mobil und dlg-probe. Alle dlg-* bestehen submitReachable bei 700 px Höhe.
- Step 3: Bundle-Größe
Die Werte aus der check.sh-Ausgabe werden mit P0 verglichen. Das CSS sollte kleiner sein, und die Schrift fehlt.
- Step 4: Code-Review (sonnet)
Der Diff 603d08c..HEAD (inklusive P0) wird gegen die Spec geprüft, Abschnitte:
- „Gestaltungsregeln“
- „Bausteine“
- „KOMPAT“
- Pakete P0 und P1
Wichtige Befunde werden behoben. Danach kommt der Rebase aus Step 1 noch einmal und Step 2 als Kurzlauf mit --only tickets,login.
- Step 5: Tag und Übergabe
Run: source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && git tag design-p1 && git log --oneline origin/test..design-p1 && git rev-parse design-p1
Übergabe an den Eigentümer:
-
Screenshots aus
$W/shots/p1(Login, Tickets, Kunde, Projekte, Finanzen, Serverpuls, ein Alt-Dialog, Menü mobil) -
Hinweis zu den neuen Statusfarben für das Team
-
Push-Zeile
git -C /home/webklar/apps/ticket.webklar.com/dev-design push origin 'design-p1^{commit}:refs/heads/test' -
Rücknahme:
git revert --no-commit 603d08c..design-p1, Commit und Push durch den Eigentümer -
Step 6: 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'stimmt mitdist/index.htmldes Tags überein. -
Ein lesender Sichttest im Chrome des Eigentümers: Login-Seite und Ticketliste.