# 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: 1. Tokens und Aliase 2. Basis (Reset, Hilfsklassen, Links) 3. Bausteine (Prototyp-Klassen) 4. KOMPAT (Altklassen im neuen Look, bis P10) 5. 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`, `$W` und `$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: - `LoginPage` - `ProjectsPage`: Wurzelklasse - `AdminPage`: Wurzelelement - `ServerpulsPage`: Diagrammfarben - Die Spec erlaubt keine neue `robots`-Meta-Zeile. `index.html` bekommt nur das Favicon. ## Review Focus - **Übersichtspunkt 2 (lange Inhalte am Handy):** `overflow-x` ist im Gate `p1` fü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 `p1` mit `dark-surface` und `low-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 `submitReachable` in jeder `dlg-*`-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..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 `test` bringen. ### Task 1: `statusTone` **Files:** - Modify: `src/lib/ticketStatus.js` (neuer Export nach `statusGroup`) - Test: `tests/unit/ticketStatus.test.mjs` (neu) **Interfaces:** - Consumes: `statusGroup(status)` aus derselben Datei. Es liefert die Gruppen-ID oder `null`. - Produces: `statusTone(status) → '' | 'blue' | 'orange' | 'violet' | 'green' | 'plain'`. - [ ] **Step 1: Failing Test** ```js 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** ```bash 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 " ``` ### Task 2: Tokens, Aliase, Basis, Schrift **Files:** - Modify: `src/styles/global.css` - Zeilen 1-10 (`@font-face`) löschen - `:root`, alte Zeilen 18-71, ersetzen - `body`/Scrollbar/`::selection`, alte Zeilen 73-106, ersetzen - alte Hilfsregeln `.muted`/`.faint` (um Zeile 1051) ersetzen - 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.mjs` bekommt die Ansicht `basis-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: `:root` ersetzen** - Den Token-Block der Spec wörtlich übernehmen. - Darunter folgt die Alias-Tabelle der Spec. Sie enthält `--admin-line` und `--admin-line-strong`. - Die beiden Zeilen in `AdminPage.css` entfallen. - [ ] **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** ```bash 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 " ``` ### 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** ```bash 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 " ``` ### 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 [--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 in `src/**/*.jsx`. - Sie steht in einer Zeichenkette in `src/lib/*.js` oder `src/hooks/*.js`. - Ein Template-Präfix deckt sie ab: `xxx-${…}` gilt für `xxx-*`. - 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-ausnahmen` entfä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 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-count` und `.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`, `fadeIn` und `slideIn` - `.kpi*`, weil `Kpi` ab Task 6 `Stat` rendert 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** ```bash 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 " ``` ### Task 5: Gerüst, Menü, Logo, Favicon **Files:** - Create: `src/components/Logo.jsx`, `public/favicon.svg` (Kopie von `quelle/favicon.svg`) - Modify: - `src/App.jsx` - `src/components/Navbar.jsx` - `src/lib/navLinks.js` (`hot: true` am Chat-Unterpunkt) - `index.html` (nur ``) - `src/styles/serverpuls.css` (Zeilen 70-74 `.side-dot*` löschen) - `src/pages/ProjectsPage.jsx` (Wurzel `main-content` → `page`) - `src/pages/AdminPage.jsx` (`
` → `
`, 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.mjs` bekommt die Ansicht `menue-mobil` **Interfaces:** - Consumes: Klassen aus Task 3. - Produces: - `Logo({ size = 24 })` mit `aria-hidden="true"`. Die Pfade kommen aus `quelle/app.js`, Konstante `LOGO`. - `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.js` ergä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: ```jsx
WEBklar
``` - Ein Effekt auf `location.pathname` (nur darauf) schließt die Schublade und ruft `window.scrollTo(0, 0)` auf. - Ein Esc-Listener ist nur bei `menuOpen` aktiv. - Der Ladezustand von `ProtectedRoute` ist `
Wird geladen …
`. - [ ] **Step 5: `Navbar.jsx` als Textliste** Aufbau: `