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>
680 lines
51 KiB
Markdown
680 lines
51 KiB
Markdown
# WOMS „Weißes Design“ P10: Aufräumen – 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 P10 gibt es keine Übergangsschicht mehr. `react-icons` und `@tabler/icons-react` sind deinstalliert, die KOMPAT-Regeln, die alten Token-Aliase und alle toten Klassen sind gelöscht, `previewEnv.dotColor` ist entfernt. Sichtbar ändert sich nichts, das Bundle wird kleiner. Die Umleitung `/tickets?woid=N` auf `/tickets/N` bleibt.
|
||
|
||
**Architecture:**
|
||
- Es wird nur gelöscht, umbenannt oder auf vorhandene Bausteine umgestellt. Die Bilder von `design-p9` sind die Referenz, ein Pixelvergleich (`vergleich.mjs`, gestartet über `run-browser.sh`) beweist nach jedem Löschschritt, dass nichts kippt.
|
||
- Reihenfolge nach Risiko: Pakete, `dotColor`, Token-Aliase (reine Umbenennung), KOMPAT, tote Klassen, Inline-Styles und Regelprüfung, Gate und Tag.
|
||
- Der Wächtertest `tests/unit/hygiene.test.mjs` hält die Ziele fest (drei Tests, je einer in Task 2, 4 und 5).
|
||
- Die Ergebnisdatei `docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md` sammelt die Belege.
|
||
|
||
**Tech Stack:** wie P1. Node 24 (`readdirSync` mit `recursive`), npm 11, ripgrep 13 ohne PCRE2 (keine PCRE2-Option, keine Lookarounds).
|
||
|
||
**Spec:** `docs/superpowers/specs/2026-10-04-weisses-design-design.md`, Abschnitte „Gestaltungsregeln“, „Design-Tokens“ (Alias-Tabelle), „Übergangsschicht KOMPAT“, „Ticket als eigene Seite / Route und Links“, „Was gleich bleibt“, „Abnahme“ und Zeile P10. Dateidetails im Anhang `…-umbaukarte.md`, Abschnitt 5 (P10), 2.2, 2.3, 4 (D) und 7. Globale Regeln, Befehlsregeln (`env.sh`, `check.sh`, `run-browser.sh`) und Schnittstellen: `2026-10-05-weisses-design-00-uebersicht.md`.
|
||
|
||
## Global Constraints
|
||
|
||
Jeder Run-Block beginnt mit `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&`. Danach gelten `$WT` (Worktree `/home/webklar/apps/ticket.webklar.com/dev-design`, Arbeitsverzeichnis), `$W` (Werkzeug) und `$TMPDIR` (Scratchpad). Tests und Build laufen nur über `"$W/check.sh"`, Browser-Skripte nur über `"$W/shots.sh"` oder `"$W/run-browser.sh"`. Suche nur mit `rg` oder `git grep`, nie mit dem Shell-`grep` auf Dateien.
|
||
|
||
Es gelten die Regeln der Übersicht. Für P10 kommt hinzu:
|
||
|
||
- Voraussetzung sind die Tags `design-p0` bis `design-p9`, alle Diff-Prüfungen vergleichen gegen `design-p9`. Erlaubt ist nur Löschen, Umbenennen und Umstellen auf vorhandene Bausteine, keine neuen Funktionen, Klassen, Texte oder Tokens. Ausnahmen: Wächtertest, Ergebnisdatei, das Werkzeug außerhalb des Repos und, nur falls sie fehlt, die Deklaration `font-variant-numeric: tabular-nums` an `.num`, `.stat .v` und `.fin-amount` (Task 7 Step 4). Neue Ansichten braucht P10 nicht, das Gate läuft über alle bestehenden.
|
||
- Nicht angefasst werden zusätzlich: die `?woid=`-Umleitung (`woidRedirectTarget` in `lib/ticketListUrl.js`, `<Navigate replace>` in `TicketsPage.jsx`), der Token-Block der Spec und die Klassen-Hooks aus „Was gleich bleibt“ (`data-testid`, `data-label`, `data-storage-done`, `data-hidden-hits`).
|
||
- Klassensuche token-genau mit `(^|[^A-Za-z0-9_-])NAME([^A-Za-z0-9_-]|$)`. `rg -w` reicht nicht, weil `-` als Wortgrenze gilt und `card` sonst `fin-card` trifft.
|
||
- `git add` mit ausdrücklichen Pfaden. Wo ein Schritt viele Dateien ändert, läuft vorher `git diff --name-only`, und `git add` bekommt genau diese geprüfte Liste.
|
||
- **Entscheidung:** Pixelinvariante. Das Aussehen der Bilder von `design-p9` gilt, jede Abweichung ist ein Fehler und wird behoben. Ausgenommen sind nur Ansichten mit Rauschen (relative Zeiten wie „vor 5 Minuten“), das ein zweiter Lauf von `design-p9` selbst zeigt.
|
||
- **Entscheidung:** Stoppregel für Icons. Liefert `rg "react-icons|@tabler" src` einen Treffer, stammt er aus einem früheren Paket oder aus Commits, die der Rebase von `origin/test` mitbrachte. P10 behebt ihn nach der Ersetzungsregel der Spec (Icon-Knopf wird Textknopf oder Textlink, Zeichen „ד „←“ „→“) in einem eigenen Commit vor Task 2 und nennt ihn in der Ergebnisdatei.
|
||
- **Entscheidung:** Die Tokens des Spec-Blocks bleiben, auch ein ungenutztes. Nur die Aliase der Spec-Tabelle fallen, `--sp-1…6` bleiben. `Button` behält die Prop `size` in der Signatur (Spec „Knöpfe“), Aufrufe mit `size="sm"` verschwinden, weil sie nichts bewirken.
|
||
- **Entscheidung:** Farbliterale in JSX sind nur in `src/components/Logo.jsx` (Markenzeichen, `#111` und `#fff` wie `public/favicon.svg`) und `src/components/serverpuls/chartColors.js` erlaubt. Inline-`<svg>` bleibt nur in `Logo.jsx` und `Sparkline.jsx`. Der Check `icon-svg` nimmt `svg.sp-spark` (P9) und `.woms-chat .chat-composer *` (P0) in `checks.mjs` aus, dazu das Gate alles unter `.woms-chat` (`ignore`, P6). P10 fügt keine Ausnahme hinzu.
|
||
- **Entscheidung:** Beim Umstellen gelten die Regeln „Bausteine benutzen“ der Übersicht und die CSS-Reihenfolge: In jedem `<Dialog as="form">` trägt jeder Knopf außer dem Absenden-Knopf `type="button"`, ein `Card` ohne Titel und Aktionen rendert kein `h2`, und Bereichs-CSS (`chat.css`, `serverpuls.css`, `pages/AdminPage.css`) lädt vor `global.css`. Überstimmt eine globale Regel es nach dem Löschen nicht mehr, braucht der Bereichs-Selektor eine höhere Spezifität, nie `!important`.
|
||
- **Entscheidung:** Die Ergebnisdatei hat sieben Abschnitte: 1 Token-Aliase, 2 KOMPAT-Inventur, 3 Tote Klassen, 4 Inline-Styles, 5 Regelprüfung und Invarianten, 6 Bundle, 7 Offene Punkte. Task 4 legt sie mit allen Überschriften an, jeder Task nimmt seinen Abschnitt in seinen Commit auf.
|
||
|
||
## Review Focus
|
||
|
||
Aus der Übersicht gehört P10 kein Punkt allein. Alle fünf laufen aber als Ansichten im Gate `p10` mit (`ticket-altdaten*`, `*-lang*`, `fehler-*`, `tasten-*`, `ticket-viel`, `tickets-suche`) und müssen unverändert bleiben. P10 verantwortet sechs eigene Prüfungen:
|
||
|
||
1. **Nichts Sichtbares ändert sich.** Pixelvergleich `design-p9` gegen P10 über alle Ansichten in allen Viewports (Standard 1440×900 und 390×844, bei `dlg-*` auch 1440×700 und 390×700), keine abweichende Ansicht außerhalb des Rauschens (Task 4, 5, 6 und 8).
|
||
2. **Keine noch gebrauchte Regel geht verloren.** Jede KOMPAT-Klasse hat eine Inventurzeile mit Nutzerzahl, jeder Restnutzer wird vor dem Löschen umgestellt (Task 5). Kein `var(--…)` zeigt ins Leere, `undefinedUsed` ist leer (Task 4).
|
||
3. **Die Icon-Pakete fehlen nirgends.** `rg` meldet 0 Treffer, der Build ist grün, kein `console-error` in irgendeiner Ansicht (ein fehlender Import wäre zur Laufzeit ein `pageerror`), das Lock passt zu `package.json` (Task 2).
|
||
4. **Die `?woid=`-Umleitung bleibt.** Ansicht `alt-link` im Gate, Test `woidRedirectTarget` aus P2 grün, `TicketsPage.jsx` und `ticketListUrl.js` unverändert (Task 8).
|
||
5. **Die Spec-Invarianten halten:** alle `data-testid`, die Zahl der `window.confirm`, Hooks und Lib-Logik nur wie in den Paketplänen geändert (Task 7 Step 5, Task 8 Review).
|
||
6. **Die übergreifenden Gestaltungsregeln gelten:** höchstens ein `.btn-primary` je `.page-head` (Spec-Regel 4, Check `max-primary` im Gate, Task 1 Step 6 und Task 8) und `tabular-nums` an Zahlen und Beträgen (Spec-Regel 6, `rg` in Task 7 Step 4).
|
||
|
||
---
|
||
|
||
### Task 1: Ausgangslage, Referenzbilder, Werkzeug
|
||
|
||
**Files** (alle unter `$W/`, kein Commit im Repo):
|
||
- Create: `vergleich.mjs`, `token-check.mjs`
|
||
- Modify: `css-klassen.mjs` (Flag `--ohne-ausnahmen`), `checks.mjs` (Check `max-primary`), `gates.mjs` (Gate `p10`)
|
||
|
||
**Interfaces:**
|
||
- Consumes: Tag `design-p9`, `build.sh`, `shots.sh`, `run-browser.sh`, `check.sh`, `css-klassen.mjs`, `farben.mjs`, `GATES.p9` (P0 bis P9).
|
||
- Produces:
|
||
- `"$W/run-browser.sh" "$W/vergleich.mjs" <A> <B> [--rauschen <A2>] [--out <Ordner>]` → JSON `{ geprueft, anders: [{ view, viewport, diffPixels, bbox }], rauschen: [view], fehlt: [view] }`. Exit 1, wenn `anders` oder `fehlt` nicht leer ist. A, B und A2 sind Ausgabeordner von `shots.sh` (`<w>x<h>/<id>.png`, z. B. `1440x900/tickets.png` und `390x844/tickets.png`).
|
||
- `node "$W/token-check.mjs" <worktree> [--fix]` → JSON `{ legacy: [{ name, ersatz, file, line, art }], undefinedUsed: [{ name, file, line }], mitFallback: [{ name, file, line }], definedUnused: [name] }`. Exit 1, wenn `legacy` oder `undefinedUsed` nicht leer ist.
|
||
- `css-klassen.mjs --ohne-ausnahmen`: ignoriert die Ausnahmeliste und gibt zusätzlich `nurAusnahme: [name]` aus, die Klassen, die nur durch die Liste als benutzt gelten.
|
||
- Check `max-primary` in `checks.mjs`: Verstoß `{ check: 'max-primary', selector: '.page-head', detail }` für jedes sichtbare `.page-head` mit mehr als einem sichtbaren `.btn-primary`.
|
||
- `GATES.p10` nach dem Schema der Übersicht (Step 6).
|
||
|
||
- [ ] **Step 1: Paketstart und Stand prüfen**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git fetch origin && git merge-base --is-ancestor design-p9 HEAD && git rebase origin/test && "$W/check.sh"
|
||
git log --oneline origin/test..origin/feature/terminplaner-tp2 -- src package.json package-lock.json tests
|
||
git tag --list 'design-p*'; git log --oneline design-p9..origin/test; git status --short
|
||
```
|
||
Expected:
|
||
- Erste Zeile: `design-p9` ist Vorfahre (sonst Exit 1: stoppen und melden, der Rebase schrieb die Pakete um), der Rebase läuft ohne Konflikt, `check.sh` endet mit Exit 0, `# fail 0`, `# pass` ist `N9` (notieren).
|
||
- Zweite Zeile (Abgleich mit `feature/terminplaner-tp2`, P10 berührt fast alle Dateien unter `src`): leer. Gibt sie etwas aus, stoppt der Agent und fragt den Eigentümer. Er empfiehlt dabei, TP2 zuerst nach `test` zu bringen.
|
||
- Tags `design-p0` bis `design-p9`, `git log` und `git status` leer. Kommen fremde Commits mit, werden ihre Dateien in den folgenden Tasks wie alle anderen geprüft.
|
||
|
||
- [ ] **Step 2: Voraussetzungen im Werkzeug**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
rg -n "GATES\.p9|p1:" "$W/gates.mjs"; rg -n "ignore" "$W/gates.mjs"; rg -n "sp-spark" "$W/checks.mjs"
|
||
ls "$W/check.sh" "$W/run-browser.sh" "$W/css-klassen.mjs" "$W/farben.mjs" "$W/build.sh" "$W/shots.sh"
|
||
```
|
||
Expected: Gates `p1` und `p9`, im `ignore` nur `.woms-chat` (P6, `.ticket-projects` strich P5), Ausnahme `svg.sp-spark` und alle sechs Dateien sind da. Fehlt etwas, wird gestoppt und gemeldet.
|
||
|
||
- [ ] **Step 3: Ausgangswerte des Bundles festhalten**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git log design-p0 --format=%B | rg "Ausgangswerte" &&
|
||
"$W/check.sh" --nur-build &&
|
||
{ find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.ttf' \) -printf '%s %p\n'; for f in dist/assets/*.js dist/assets/*.css; do echo "$f gzip=$(gzip -9 -c "$f" | wc -c)"; done; wc -l src/styles/*.css src/pages/*.css; } | tee "$W/p10-baseline-p9.txt"
|
||
```
|
||
Expected: die P0-Zeile `Ausgangswerte: <Testzahl>, JS <x> B, CSS <y> B` (Gegenprobe der Umbaukarte: JS 680.818 B, CSS 64.433 B, Lato 96.184 B, 2.079 CSS-Zeilen), Build grün, keine `.ttf` in `dist`, alle Zahlen in `$W/p10-baseline-p9.txt`.
|
||
|
||
- [ ] **Step 4: Referenzbilder und Rauschmaß**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p9-ref && "$W/shots.sh" p9-ref "$W/shots/p9-ref" --gate p9 && "$W/shots.sh" p9-ref "$W/shots/p9-ref2" --gate p9 && ls "$W/shots/p9-ref/1440x900" | wc -l`
|
||
Expected: beide Läufe Exit 0, je Ansicht ein Bild je Viewport (`1440x900` und `390x844`, bei `dlg-*` zusätzlich `1440x700` und `390x700`). Die Zahl der Ansichten ist die Sollzahl aller späteren Läufe (notieren).
|
||
|
||
- [ ] **Step 5: `vergleich.mjs` schreiben und prüfen**
|
||
|
||
Umsetzung:
|
||
- Das Skript startet Chromium selbst (Ladeweise wie `shots.mjs`) und läuft deshalb nur über `run-browser.sh`.
|
||
- Die PNGs werden in Playwright-Chromium (`about:blank`) per `createImageBitmap` und Canvas dekodiert und pixelweise verglichen. Eine andere Bildgröße ist `anders` und nennt beide Größen. `bbox` ist der kleinste Rahmen um alle abweichenden Pixel.
|
||
- `--out` bekommt je abweichender Ansicht ein Bild unter `<w>x<h>/<id>.png`, abweichende Pixel rot.
|
||
- Eine Ansicht mit Abweichung zwischen A und A2 zählt als `rauschen`, außer die Abweichung zwischen A und B reicht über deren `bbox` hinaus. Dann ist sie `anders`.
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
cp -r "$W/shots/p9-ref" "$TMPDIR/probe" && cp "$TMPDIR/probe/1440x900/tickets.png" "$TMPDIR/probe/1440x900/kunden.png"
|
||
"$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$TMPDIR/probe"; echo "exit $?"
|
||
"$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p9-ref2"; echo "exit $?"
|
||
```
|
||
Expected: Der erste Aufruf nennt genau `kunden` bei 1440×900 als `anders`, Exit 1. Der zweite endet mit Exit 0 oder nennt wenige Rausch-Ansichten. Jede wird einmal angesehen und in `$W/p10-rauschen.txt` notiert.
|
||
|
||
- [ ] **Step 6: `token-check.mjs`, Flag, Check `max-primary` und Gate**
|
||
|
||
Umsetzung von `token-check.mjs`:
|
||
- Es liest `src/**/*.{css,jsx,js}` und schreibt nur dort. Definiert ist ein Name durch `--name:` in CSS oder den Schlüssel `'--name'` in JSX-Objekten, benutzt durch `var(--name`.
|
||
- `legacy` enthält jede Nutzung und jede Definition eines Alias-Namens der Tabelle in Task 4 (`art` ist `nutzung` oder `definition`, `ersatz` der neue Name oder der Wert `4px` bzw. `none`).
|
||
- `undefinedUsed` sind benutzte, nirgends definierte Namen ohne Rückfallwert, mit Rückfallwert landen sie in `mitFallback`.
|
||
- `--fix` schreibt nur die `nutzung`-Einträge um (`var(--alt)` und `var(--alt, …)`), `--sidebar-w-collapsed` nie.
|
||
|
||
Dazu kommen:
|
||
- das Flag in `css-klassen.mjs`,
|
||
- der Check `max-primary` in `checks.mjs` (Spec, Gestaltungsregel 4: höchstens ein `.btn-primary` je Seitenkopf), mit `detail` `<n> .btn-primary`,
|
||
- `GATES.p10` in `gates.mjs`. P10 hat keine eigenen Ansichten, `icon-svg` gilt deshalb für alle (`'*'` ist der Präfix-Platzhalter für alle Ansichten, wie in P2), mit dem `ignore` aus `p9` unverändert. `step-failed`, `external-request` und `console-error` sind wie in jedem Gate aktiv.
|
||
|
||
```js
|
||
const iconSvg = GATES.p9.scoped['icon-svg']
|
||
GATES.p10 = {
|
||
...GATES.p9,
|
||
checks: [...GATES.p9.checks, 'max-primary'],
|
||
scoped: { ...GATES.p9.scoped, 'icon-svg': { ...iconSvg, views: ['*'] } },
|
||
}
|
||
```
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
mkdir -p "$TMPDIR/tc/src" && printf 'a{color:var(--nope);border:1px solid var(--border)}' > "$TMPDIR/tc/src/x.css"
|
||
node "$W/token-check.mjs" "$TMPDIR/tc"; echo "exit $?"
|
||
node "$W/token-check.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.legacy.length, j.undefinedUsed.length)"
|
||
node "$W/css-klassen.mjs" . --ohne-ausnahmen | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.dead.length, j.nurAusnahme.length)"
|
||
mkdir -p "$TMPDIR/probe-primary" && printf '<!doctype html><meta charset="utf-8"><title>Probe</title><div class="page-head"><h1>Test</h1><button class="btn btn-primary">A</button><button class="btn btn-primary">B</button></div>' > "$TMPDIR/probe-primary/index.html"
|
||
"$W/shots.sh" probe "$TMPDIR/probe-primary-out" --static "$TMPDIR/probe-primary" --only tickets --gate p10; echo "exit $?"
|
||
rg -o "max-primary" "$TMPDIR/probe-primary-out/report.json" | wc -l
|
||
```
|
||
Expected:
|
||
- Der erste Aufruf endet mit Exit 1, `undefinedUsed` nennt `--nope`, `legacy` nennt `--border` mit `ersatz` `--line`.
|
||
- Der zweite zeigt eine Zahl über 0 für `legacy` (die Alias-Definitionen stehen noch) und 0 für `undefinedUsed`.
|
||
- Der dritte nennt zwei Zahlen, sie werden notiert.
|
||
- Die Probe mit zwei Primärknöpfen in einem `.page-head` endet mit Exit 1, die letzte Zeile nennt eine Zahl über 0 (der Check `max-primary` schlägt an).
|
||
|
||
- [ ] **Step 7: Gate `p10` gegen `design-p9`**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/shots.sh" p9-ref "$W/shots/p9-ref-p10" --gate p10; echo "exit $?"`
|
||
Expected: Exit 0 (die Bilder dieses Laufs werden nicht gebraucht). Ein Treffer `icon-svg` folgt der Stoppregel für Icons. Ein Treffer `max-primary` ist ein Fehler eines früheren Pakets: Der Agent stoppt und meldet ihn dem Eigentümer, weil der überzählige Knopf das Aussehen ändern würde.
|
||
|
||
### Task 2: Icon-Pakete entfernen
|
||
|
||
**Files:**
|
||
- Create: `tests/unit/hygiene.test.mjs`
|
||
- Modify: `package.json` (Zeilen 6 und 11), `package-lock.json`
|
||
|
||
**Interfaces:**
|
||
- Consumes: nichts. Voraussetzung ist `rg "react-icons|@tabler" src` = 0.
|
||
- Produces: ein Lock ohne `@tabler/icons-react`, `@tabler/icons` und `react-icons`, dazu `hygiene.test.mjs` mit den Helfern `files`, `read`, `offenders(re, only)`, auf denen Task 4 und 5 aufbauen.
|
||
|
||
- [ ] **Step 1: Failing Test schreiben**
|
||
|
||
```js
|
||
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readFileSync, readdirSync } from 'node:fs'
|
||
import path from 'node:path'
|
||
import { fileURLToPath } from 'node:url'
|
||
|
||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
||
const files = readdirSync(path.join(root, 'src'), { recursive: true })
|
||
.filter((f) => /\.(jsx?|css)$/.test(f))
|
||
.map((f) => path.join('src', f))
|
||
const read = (rel) => readFileSync(path.join(root, rel), 'utf8')
|
||
const offenders = (re, only = /./) => files.filter((f) => only.test(f) && re.test(read(f)))
|
||
|
||
test('Icon-Pakete sind weder Abhängigkeit noch Import', () => {
|
||
const pkg = JSON.parse(read('package.json'))
|
||
for (const n of ['react-icons', '@tabler/icons-react']) assert.equal(pkg.dependencies[n], undefined, n)
|
||
assert.deepEqual(offenders(/react-icons|@tabler/), [])
|
||
})
|
||
```
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs`
|
||
Expected: FAIL (`package.json` führt beide Pakete).
|
||
|
||
- [ ] **Step 2: Beweisen, dass nichts mehr importiert**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "react-icons|@tabler" src`
|
||
Expected: keine Ausgabe. Bei einem Treffer gilt die Stoppregel der Global Constraints.
|
||
|
||
- [ ] **Step 3: Deinstallieren**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && systemd-run --scope -q -p MemoryMax=1500M -p MemorySwapMax=0 npm uninstall react-icons @tabler/icons-react --no-audit --no-fund`
|
||
Expected: Exit 0.
|
||
|
||
- [ ] **Step 4: Lock und Index prüfen**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git status --short; git diff package.json | rg "^[-+] "; rg -c "tabler|react-icons" package.json package-lock.json; git diff --numstat package-lock.json
|
||
npm ls react-icons @tabler/icons-react 2>&1 | rg "empty"; npm ci --dry-run --no-audit --no-fund; echo "exit $?"
|
||
```
|
||
Expected:
|
||
- `git status` zeigt genau `M package-lock.json`, `M package.json` und `?? tests/unit/hygiene.test.mjs`, keine `D`-Zeile (`node_modules` ist nicht getrackt).
|
||
- Der Diff von `package.json` hat genau zwei `-`-Zeilen, `rg -c` gibt nichts aus.
|
||
- `numstat` zeigt 0 hinzugefügte Zeilen. Stehen dort wenige, sind es höchstens geänderte Flags (`"peer"`, `"dev"`), und jede `+`-Zeile wird angesehen.
|
||
- `npm ls` meldet `(empty)`, `npm ci --dry-run` endet mit Exit 0.
|
||
|
||
- [ ] **Step 5: Tests und Build**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh"`
|
||
Expected: Exit 0, `# fail 0`, `# pass` = `N9 + 1`, Build grün.
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add package.json package-lock.json tests/unit/hygiene.test.mjs
|
||
git commit -m "Aufraeumen: react-icons und @tabler/icons-react deinstalliert (src ohne Icon-Importe), Waechtertest" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 3: `dotColor` und Icon-Kommentare
|
||
|
||
**Files:**
|
||
- Modify: `src/lib/previewEnv.js` (Zeile 1 und Zeilen 15–18 laut Ausgangsstand), `tests/unit/previewEnv.test.mjs` (Zeile 5 und der Test `dotColor`, Zeilen 21–29)
|
||
- Modify: `src/lib/navLinks.js` (Zeile 1), `tests/unit/navLinks.test.mjs` (Zeile 5)
|
||
|
||
**Interfaces:**
|
||
- Consumes: `isValidEnvName`, `buildEnvPayload`, `isDevPreview`, `envValueTooLong`, `MAX_ENV_VARS` aus `previewEnv.js`, unverändert.
|
||
- Produces: `previewEnv.js` ohne `dotColor` und `DOT_COLORS`.
|
||
|
||
- [ ] **Step 1: Beweisen, dass `dotColor` unbenutzt ist**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "dotColor|DOT_COLORS" src tests`
|
||
Expected: Treffer nur in `src/lib/previewEnv.js` und `tests/unit/previewEnv.test.mjs` (P5 hat `PreviewBlock` und `ServicesPage` umgestellt). Weitere Treffer sind ein Fehler eines früheren Pakets.
|
||
|
||
- [ ] **Step 2: Test zuerst anpassen**
|
||
|
||
Der Test `dotColor` und der Name im `loadModule`-Destrukturieren entfallen.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/previewEnv.test.mjs`
|
||
Expected: PASS mit 4 Tests (`isValidEnvName`, `buildEnvPayload`, `isDevPreview`, `envValueTooLong`).
|
||
|
||
- [ ] **Step 3: Funktion löschen**
|
||
|
||
`DOT_COLORS` und `dotColor` fallen, der Kopfkommentar heißt „(Variablen, Dev-Erkennung)“.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/previewEnv.test.mjs; rg -n "dotColor|DOT_COLORS|#10b981|#f59e0b|#a0aec0" src tests`
|
||
Expected: PASS, keine Treffer.
|
||
|
||
- [ ] **Step 4: Icon-Kommentare**
|
||
|
||
- `src/lib/navLinks.js` Zeile 1 wird `// Eintraege der Sidebar als reine Daten (unter Node testbar); Navbar.jsx rendert sie als Textliste.` Der zweite Kommentarsatz zu Unterpunkten und `count` bleibt.
|
||
- `tests/unit/navLinks.test.mjs` Zeile 5 wird `// Sidebar: Eintraege als reine Daten (Navbar.jsx rendert sie als Textliste)`.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n -i "(^|[^a-z])icons?([^a-z]|$)" src tests --glob '!*.css' --glob '!hygiene.test.mjs'`
|
||
Expected: keine Treffer, höchstens Kommentare zum fremden Chat-Baustein in `src/components/chat` und `src/lib/loadChatComposer.js`. Jeder andere Treffer wird umformuliert. „favicon“ und der Wächtertest zählen nicht.
|
||
|
||
- [ ] **Step 5: Test**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-tests`
|
||
Expected: Exit 0, `# fail 0`, `# pass` = `N9` (hygiene +1, `dotColor` −1).
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add src/lib/previewEnv.js tests/unit/previewEnv.test.mjs src/lib/navLinks.js tests/unit/navLinks.test.mjs
|
||
git commit -m "Aufraeumen: previewEnv.dotColor samt Test entfernt, Icon-Kommentare in navLinks angepasst" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 4: Token-Aliase abbauen
|
||
|
||
**Files:**
|
||
- Modify: `src/styles/global.css` (Alias-Block in `:root`), alle Dateien unter `src/` mit alten Namen (Liste aus Step 3)
|
||
- Create: `docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md` (Überschriften 1 bis 7, Abschnitt 1 gefüllt)
|
||
- Test: `tests/unit/hygiene.test.mjs` (zweiter Test)
|
||
|
||
**Interfaces:**
|
||
- Consumes: `$W/token-check.mjs` (Task 1) und die Alias-Tabelle der Spec:
|
||
|
||
| Alter Name | Neu |
|
||
|---|---|
|
||
| `--surface-1`, `--surface-3`, `--surface`, `--dark-bg`, `--dark-card-bg` | `--bg` |
|
||
| `--surface-2`, `--surface-hover` | `--bg-hover` |
|
||
| `--border`, `--gray-700`, `--admin-line` | `--line` |
|
||
| `--border-strong`, `--admin-line-strong` | `--line-strong` |
|
||
| `--border-accent` | `--accent-ring` |
|
||
| `--text-muted`, `--text-faint`, `--gray-800` | `--text-2` |
|
||
| `--dark-text`, `--gray-900` | `--text` |
|
||
| `--accent-2`, `--green-secondary` | `--accent-hover` |
|
||
| `--green-primary` | `--accent` |
|
||
| `--info`, `--warn`, `--ok` | `--blue-fg`, `--orange-fg`, `--green-fg` |
|
||
| `--r-sm`, `--r-md`, `--r-lg`, `--r-pill` | `--radius`, `--radius-lg`, `--radius-lg`, Wert `4px` |
|
||
| `--shadow-1`, `--shadow-2`, `--shadow-3` | `none`, `--shadow-btn`, `--shadow-pop` |
|
||
| `--sidebar-w-collapsed` | entfällt, kein Nutzer erlaubt |
|
||
|
||
- Produces: `:root` ohne Aliase, `token-check` meldet `legacy` und `undefinedUsed` leer.
|
||
|
||
- [ ] **Step 1: Failing Test ergänzen**
|
||
|
||
```js
|
||
const LEGACY = ['surface-1', 'surface-2', 'surface-3', 'surface-hover', 'surface', 'dark-bg', 'dark-card-bg', 'border', 'border-strong', 'border-accent',
|
||
'gray-700', 'gray-800', 'gray-900', 'admin-line', 'admin-line-strong', 'text-muted', 'text-faint', 'dark-text', 'accent-2', 'green-secondary',
|
||
'green-primary', 'info', 'warn', 'ok', 'r-sm', 'r-md', 'r-lg', 'r-pill', 'shadow-1', 'shadow-2', 'shadow-3', 'sidebar-w-collapsed']
|
||
test('keine alten Token-Namen mehr (Aliase sind gelöscht)', () => {
|
||
const re = new RegExp(`(^|[^A-Za-z0-9-])--(${LEGACY.join('|')})([^A-Za-z0-9-]|$)`)
|
||
assert.deepEqual(offenders(re), [])
|
||
})
|
||
```
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs`
|
||
Expected: FAIL im neuen Test.
|
||
|
||
- [ ] **Step 2: Bestandsaufnahme**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
node "$W/token-check.mjs" . > "$TMPDIR/token-vorher.json"; node -e "const j=JSON.parse(require('fs').readFileSync(process.argv[1]));const c={};for(const e of j.legacy)c[e.name+' '+e.art]=(c[e.name+' '+e.art]||0)+1;console.log(c)" "$TMPDIR/token-vorher.json"
|
||
```
|
||
Expected: Zahl der Nutzungen und Definitionen je Alias. Sie kommt in Abschnitt 1 der Ergebnisdatei (Spalten: alter Name, Nutzungen vorher, ersetzt durch).
|
||
|
||
- [ ] **Step 3: Nutzungen umbenennen**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/token-check.mjs" . --fix; git diff --name-only`
|
||
Expected: Es ändern sich nur `.css`, `.jsx` und `.js` unter `src/`. Das ist eine reine Umbenennung, der Wert jedes Tokens bleibt gleich.
|
||
|
||
- [ ] **Step 4: Alias-Block löschen**
|
||
|
||
In `global.css` fallen der Alias-Block hinter dem Token-Block samt Kommentar und jede übrige Definition eines Alias-Namens, auch außerhalb von `:root`.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs && node "$W/token-check.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.legacy.length, j.undefinedUsed.length, j.mitFallback.length)"`
|
||
Expected: PASS und `0 0` plus eine Zahl für `mitFallback`. Jeder Eintrag dort wird angesehen: Der Rückfallwert fällt, wenn das Token existiert, sonst steht der Eintrag in Abschnitt 7.
|
||
|
||
- [ ] **Step 5: Bauen, Gate, Pixelvergleich**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t4" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t4" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t4-diff"`
|
||
Expected: Gate Exit 0, Vergleich Exit 0. Weicht eine Ansicht ab, hat `--fix` einen Namen falsch ersetzt oder eine Definition lag in einer Datei, die das Skript nicht liest. Das wird behoben.
|
||
|
||
- [ ] **Step 6: Ergebnisdatei und Commit**
|
||
|
||
Die Ergebnisdatei wird mit den Überschriften 1 bis 7 angelegt, Abschnitt 1 bekommt die Tabelle aus Step 2.
|
||
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git diff --name-only
|
||
git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md tests/unit/hygiene.test.mjs <die geprüften Dateien aus der Liste oben>
|
||
git commit -m "Aufraeumen: Token-Aliase der Altnamen durch die neuen Tokens ersetzt und geloescht" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 5: KOMPAT-Block entfernen
|
||
|
||
**Files:**
|
||
- Modify: `src/styles/global.css` (Block `/* ===== KOMPAT (bis P10) ===== */` und der Gliederungskommentar am Dateianfang), Dateien mit Restnutzern (Liste aus Step 3)
|
||
- Modify: Ergebnisdatei Abschnitt 2
|
||
- Test: `tests/unit/hygiene.test.mjs` (dritter Test)
|
||
|
||
**Interfaces:**
|
||
- Consumes: die Bausteine aus P1 (`.btn`, `.btn-primary`, `.btn-quiet`, `.link`, `.link-danger`, `.badge`, `.field`, `.input`, `.select`, `.textarea`, `.msg`, `.muted`, `.dialog`, `.overlay`, `.seg button.on`) und `Dialog`, `Card`, `Badge`, `StatusPill`.
|
||
- Produces: `global.css` ohne KOMPAT. Kein Selektor der Spec-Tabelle „Übergangsschicht KOMPAT“ ist übrig, `.page` bleibt als Wurzelklasse der Seiten.
|
||
|
||
- [ ] **Step 1: Failing Test ergänzen**
|
||
|
||
```js
|
||
test('keine Übergangsschicht und kein !important im CSS', () => {
|
||
assert.deepEqual(offenders(/KOMPAT|!important/, /\.css$/), [])
|
||
})
|
||
```
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node --test tests/unit/hygiene.test.mjs`
|
||
Expected: FAIL im neuen Test.
|
||
|
||
- [ ] **Step 2: Grenzen und Inventur**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
read A B < <(awk '/KOMPAT \(bis P10\)/{a=NR; next} a && /^\/\* (=====|---)/{print a+1, NR-1; f=1; exit} END{if(a&&!f)print a+1, NR}' src/styles/global.css); echo "KOMPAT $A-$B"
|
||
sed -n "${A},${B}p" src/styles/global.css | rg -o "\.[a-z][a-z0-9_-]*" | sort -u | sed 's/^\.//' | while read c; do echo "$(rg -l "(^|[^A-Za-z0-9_-])${c}([^A-Za-z0-9_-]|$)" src --glob '!*.css' | wc -l) $c"; done | sort -n | tee "$TMPDIR/kompat-inventur.txt"
|
||
```
|
||
Expected:
|
||
- Der Block endet an der nächsten Kopfzeile `/* =====` oder `/* ---`, sonst am Dateiende.
|
||
- Die Inventur hat 0 Nutzer für jede Klasse der Tabelle in Step 3. Bekannte Ausnahmen: `overlay` (nur `src/components/ui/Dialog.jsx`), `row` (nur an `<tr>`) und Klassen, die auch ein neuer Baustein trägt (`btn`, `badge`, `field`, `link`). Deren Regel wandert nach Step 4 in Block 3.
|
||
- Die Liste kommt als Tabelle (Klasse, Nutzer, Entscheidung) in Abschnitt 2 der Ergebnisdatei.
|
||
|
||
- [ ] **Step 3: Restnutzer finden und umstellen**
|
||
|
||
| KOMPAT-Zeile der Spec | Gesuchte Namen | Ersatz |
|
||
|---|---|---|
|
||
| `.ui-card*` | `ui-card` | `Card` (ohne Titel und Aktionen rendert es kein `h2`) oder `<section>` mit `h2.section` |
|
||
| `.ui-btn*` | `ui-btn`, `-primary`, `-ghost`, `-danger`, `-sm`, Muster `ui-btn-${…}` | `btn`, `btn btn-primary`, `link-danger`, Zeilenaktion `link` |
|
||
| `.form-group`, `.form-label`, `.form-control` | dieselben drei | `field`, Label im `.field`, `input`, `select`, `textarea` |
|
||
| `.badge-*`, `.status-*`, `.priority-*` | `badge-` und `status-` mit `muted`, `info`, `ok`, `warn`, `danger`, `open`, `working`, `awaiting`, `assigned`, `closed`; `priority-critical`; Muster `badge-${…}`, `status-${…}` | `Badge`, `StatusPill` |
|
||
| `.overlay` (Altform), `.overlay-content`, `.overlay-close` | `overlay-content`, `overlay-close`, `overlay` außerhalb von `Dialog.jsx`, `fin-dialog` (760 px, laut P7 tot) | `Dialog` |
|
||
| `.seg button.active` | kein festes Muster: jedes `seg` in JSX ansehen | Knopf mit `on` und `aria-pressed` |
|
||
| `.bg-red`, `.text-white`, `.text-grey`, `.text-red` | dieselben vier | `msg err` bzw. `muted` |
|
||
| `.side-count`, `.side-logo` | dieselben zwei | schon entfernt: `.side-logo` in P4, `.side-count` in P6. Ein Treffer ist ein Rest und wird entfernt |
|
||
| `.btn-dark`, `.btn-teal` | dazu `btn-green` | `btn btn-primary` |
|
||
| `.card*`, `.row`, `.col*`, `.dropdown*` | `card`, `card-header`, `card-body`, `col`, `col-6`, `dropdown*`, `row` außerhalb von `<tr>` | entfallen |
|
||
| `.spinner` | `spinner` | Text „Wird geladen …“ |
|
||
| `.page .page`, `.page .main-content` | `main-content` | entfällt (Step 5) |
|
||
| Links in Bestandsklassen | `fin-link`, `credit-cols`, `area-rows`. Die Klasse `legal-files` bleibt (P8), nur die Regel `.legal-files a` fällt. | Klasse `link` am `<a>`, sonst die Regel in den Block des Nutzers |
|
||
|
||
In jedem `<Dialog as="form">`, das dabei entsteht oder angefasst wird, trägt jeder Knopf außer dem Absenden-Knopf `type="button"`.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n '(^|[^A-Za-z0-9_-])(ui-(card|btn)|form-(group|label|control)|(badge|status)-(muted|info|ok|warn|danger|open|working|awaiting|assigned|closed)|priority-critical|overlay-(content|close)|fin-dialog|bg-red|text-(white|grey|red)|side-(count|logo)|btn-(dark|teal|green)|spinner|dropdown[a-z-]*|card|card-header|card-body|col|col-6|main-content|fin-link|credit-cols|area-rows)([^A-Za-z0-9_-]|$)' src --glob '!*.css'; rg -n '(badge|status|ui-btn)-\$\{' src; rg -n 'className="[^"]*(^|[^A-Za-z0-9_-])row([^A-Za-z0-9_-]|")' src | rg -v '<tr'`
|
||
Expected: keine Treffer. Ein Treffer in einem Kommentar wird umformuliert, jeder Code-Treffer nach der Tabelle umgestellt, eine Gruppe je Commit (Meldung „Aufraeumen: Restnutzer von <Gruppe> auf <Baustein> umgestellt“).
|
||
|
||
- [ ] **Step 4: Regeln, die ein Baustein noch braucht**
|
||
|
||
Entscheidung: Das Aussehen der Bilder von `design-p9` gilt. Eine KOMPAT-Regel, deren Selektor auch einen neuen Baustein trifft, wird nicht gelöscht. Ihre Deklarationen gehören dann an den Baustein in Block 3, nur die alten Selektoren fallen. Bekannter Fall ist `.overlay`, die Hülle von `Dialog`:
|
||
- Ist die KOMPAT-Zeile für die Altform ein eigener Selektor (`overlay-content`, `:has(…)`), fällt sie weg.
|
||
- Hat sie die Basisregel `.overlay` selbst verändert (`overflow-y: auto`, Abstand 24/16 px), gelten die Werte, die die Bilder von `design-p9` für `Dialog` zeigen, und bleiben in der Basisregel.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "^\.(overlay|dialog)\b" src/styles/global.css`
|
||
Expected: eine Basisregel `.overlay` mit der Mobilregel bei 860 px, ohne Verweis auf `overlay-content`.
|
||
|
||
- [ ] **Step 5: Block löschen, Verschachtelung statisch beweisen**
|
||
|
||
Der Block samt Marker fällt, der Gliederungskommentar nennt danach vier Blöcke statt fünf.
|
||
|
||
Entscheidung: `.page` bleibt als Wurzelklasse jeder Seite. Gelöscht werden nur die Verschachtelungsregel `.page .page, .page .main-content` und die alte `.main-content`-Regel.
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
node --test tests/unit/hygiene.test.mjs
|
||
rg -n "KOMPAT|main-content" src
|
||
rg -n 'className=\{?["`]([^"`]* )?page([ "`}]|$)' src --glob '*.jsx' | rg -v '^src/pages/'
|
||
rg -n '<[A-Za-z]+Page\b' src --glob '!App.jsx'
|
||
```
|
||
Expected: PASS und drei leere Ausgaben. Es gibt also kein `KOMPAT` und kein `main-content` mehr, die Klasse `page` steht nur in `src/pages/*.jsx` (der Treffer-Filter erfasst nur Klassenstellen, keine Props wie `page` in `Pager`), und nur `App.jsx` rendert `*Page`-Komponenten. Eine Seite in einer Seite ist damit ausgeschlossen. Ein Treffer, der nur ein Wort im Kommentar ist, wird umformuliert.
|
||
|
||
- [ ] **Step 6: Bauen, Gate, Pixelvergleich**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t5" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t5" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t5-diff"`
|
||
Expected: Gate Exit 0, Vergleich Exit 0. Auch alle Alt-Dialoge (`dlg-*`), die `.seg`-Ansichten (`finanzen`, `serverpuls`) und Links bleiben unverändert. Weicht eine Ansicht ab, wird das Diff-Bild angesehen. Es gibt zwei Ursachen:
|
||
- Die gelöschte Regel gehört an die Stelle ihres Bausteins (Step 4).
|
||
- Bereichs-CSS (`chat.css`, `serverpuls.css`, `pages/AdminPage.css`) lädt vor `global.css` und wurde bisher von KOMPAT überstimmt. Der Bereichs-Selektor bekommt dann eine höhere Spezifität, nie `!important`.
|
||
|
||
- [ ] **Step 7: Commit**
|
||
|
||
Abschnitt 2 der Ergebnisdatei ist gefüllt.
|
||
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git diff --name-only
|
||
git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md tests/unit/hygiene.test.mjs src/styles/global.css <weitere geprüfte Dateien>
|
||
git commit -m "Aufraeumen: KOMPAT-Block, .page-Verschachtelungsregel und Altklassen entfernt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 6: Tote Klassen und Keyframes
|
||
|
||
**Files:**
|
||
- Modify: `src/styles/*.css`, `src/pages/*.css`, JSX-Dateien mit Klassen ohne Regel, Ergebnisdatei Abschnitt 3, `$W/css-klassen.mjs` (Ausnahmeliste)
|
||
- Delete: CSS-Dateien ohne verbleibende Regel samt Importzeilen
|
||
|
||
**Interfaces:**
|
||
- Consumes: `css-klassen.mjs` mit `--ohne-ausnahmen` (Task 1).
|
||
- Produces: `dead` und `undefinedUsed` sind leer, die Ausnahmeliste enthält nur Namen mit belegter Konstruktionsstelle.
|
||
|
||
- [ ] **Step 1: Liste erzeugen**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
node "$W/css-klassen.mjs" . --ohne-ausnahmen > "$TMPDIR/klassen-p10.json"; node -e "const j=JSON.parse(require('fs').readFileSync(process.argv[1]));for(const k of ['dead','undefinedUsed','nurAusnahme'])console.log(k, j[k].length+':', j[k].join(' '))" "$TMPDIR/klassen-p10.json"
|
||
```
|
||
Expected: drei Zeilen mit Namen. `dead` enthält zunächst auch die Namen aus `nurAusnahme`.
|
||
|
||
- [ ] **Step 2: Gegenprobe und Löschen**
|
||
|
||
Für jeden Namen aus `dead`, der nicht in `nurAusnahme` steht:
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "(^|[^A-Za-z0-9_-])NAME([^A-Za-z0-9_-]|$)" src --glob '!*.css'`
|
||
Expected: keine Treffer. Dann fällt jede Regel mit diesem Namen in der definierenden Datei, in einer Selektorliste nur der Name.
|
||
|
||
Für jeden Namen aus `nurAusnahme` bekommt Abschnitt 3 der Ergebnisdatei eine Zeile mit der Stelle, die ihn baut: ein Template-Präfix wie `fin-fixed-${`, eine Zeichenkette in `lib/*.js` oder der Fremd-Composer bei `chat-*`. Ohne Beleg gilt die Klasse als tot und fällt.
|
||
|
||
- [ ] **Step 3: Klassen ohne Regel, `size`, Keyframes**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
rg -n 'size="sm"' src; rg -n '(^|[^A-Za-z0-9_-])(btn-sm|p-4|status-filter|supporters-editor|timeline)([^A-Za-z0-9_-]|$)' src --glob '!*.css'
|
||
rg -o "@keyframes [A-Za-z0-9_-]+" src --glob '*.css' | sed 's/.*@keyframes //' | sort -u | while read k; do rg -q "animation[^;]*(^|[^A-Za-z0-9_-])${k}([^A-Za-z0-9_-]|;)" src --glob '*.css' || echo "TOT $k"; done
|
||
```
|
||
Expected: alle drei Ausgaben leer. Treffer der ersten beiden Befehle werden aus dem JSX entfernt (die Klassen haben keine Regel, `size` bewirkt nichts). Ein toter Keyframe fällt samt Regel. Zu erwarten ist `spin`, wenn `.spin` (Notiz aus P8) und `.spinner` keinen Aufrufer mehr haben.
|
||
|
||
- [ ] **Step 4: Leere Dateien, Ausnahmeliste, Schriftordner**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && wc -l src/styles/*.css src/pages/*.css; rg -n "admin-areas" src index.html; ls src/assets 2>&1 | head -1; rg -n -i "assets/fonts|lato" src index.html`
|
||
Expected:
|
||
- Eine CSS-Datei ohne Regel wird mit `git rm` gelöscht, ihre `import`-Zeilen verschwinden (`rg -l "<Dateiname>" src`). `admin-areas.css` hat P6 schon gelöscht, ein Treffer von `rg -n "admin-areas" src index.html` ist ein Rest und wird entfernt.
|
||
- `src/assets` existiert nicht, das letzte `rg` hat keine Treffer.
|
||
- Die Ausnahmeliste in `$W/css-klassen.mjs` enthält nur noch die Namen mit Beleg aus Step 2. `badge-*`, `status-*`, `ticket-tab-active`, `ui-btn-*` und `side-dot-*` fallen.
|
||
|
||
- [ ] **Step 5: Prüfen**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && node "$W/css-klassen.mjs" . | node -e "const j=JSON.parse(require('fs').readFileSync(0));console.log(j.dead.length, j.undefinedUsed.length)" && "$W/check.sh" && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10-t6" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10-t6" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-t6-diff"`
|
||
Expected: `0 0`, `check.sh` Exit 0 mit `# fail 0` und `# pass` = `N9 + 2`, Gate Exit 0, Vergleich Exit 0.
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
Abschnitt 3 der Ergebnisdatei hat die Tabelle: Klasse, definierende Datei, Beleg oder „gelöscht“.
|
||
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git status --short
|
||
git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md <die geprüften Dateien>
|
||
git commit -m "Aufraeumen: tote Klassen, Keyframes und leere CSS-Dateien geloescht, Klassen ohne Regel aus dem JSX entfernt" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 7: Inline-Styles, Regelprüfung, Invarianten
|
||
|
||
**Files:**
|
||
- Modify: JSX-Dateien mit Inline-Styles ohne Laufzeitwert (Ersatz sind vorhandene Klassen, neue kommen nicht dazu), Ergebnisdatei Abschnitte 4, 5 und 7
|
||
|
||
**Interfaces:**
|
||
- Consumes: `$W/farben.mjs` (P1) und der Abschnitt „Bewusst offen“ in `docs/superpowers/plans/2026-10-05-weisses-design-p1-tote-klassen.md`.
|
||
- Produces: eine begründete Liste aller `style=`-Stellen und die Regelprüfung der Spec als belegte Liste.
|
||
|
||
- [ ] **Step 1: Inline-Styles nur noch für Laufzeitwerte**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -nU "style=\{\{(\s*[A-Za-z]+:\s*('[^']*'|\"[^\"]*\"|-?[0-9]+(\.[0-9]+)?)\s*,?)+\s*\}\}" src --glob '*.jsx'`
|
||
Expected: keine Treffer. Das Muster findet jedes Objekt, dessen Werte alle feste Zahlen oder Zeichenketten sind. Jeder Treffer wird durch eine vorhandene Klasse ersetzt.
|
||
|
||
- [ ] **Step 2: Rest begründen**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n "style=\{" src --glob '*.jsx'`
|
||
Expected: wenige Zeilen. Abschnitt 4 der Ergebnisdatei bekommt je Zeile Datei:Zeile, Ausdruck und Begründung. Erlaubt sind ein aus Daten oder Messung berechneter Wert (Breite in Prozent, Höhe, Spaltenzahl) und das Durchreichen der `style`-Prop in `Badge.jsx`. Feste Abstände, Farben, Schrift, Flex und Größen sind nicht erlaubt, solche Stellen werden umgestellt, und Step 1 beginnt von vorn.
|
||
|
||
- [ ] **Step 3: Farben**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && rg -n '#[0-9a-fA-F]{3,8}\b|rgba?\(|hsla?\(' src --glob '*.jsx' --glob '*.js'; node "$W/farben.mjs" .`
|
||
Expected:
|
||
- Der `rg` nennt nur `src/components/Logo.jsx` und `src/components/serverpuls/chartColors.js`.
|
||
- `farben.mjs` listet kein Literal unter 3:1 auf Weiß, keine dunkle Schrift auf `--accent` und kein Weiß-Alpha.
|
||
- Jede Zeile des Abschnitts „Bewusst offen“ in `p1-tote-klassen.md` ist erledigt. Hat sie das Zielpaket P10, wird sie hier behoben und in Abschnitt 5 genannt.
|
||
|
||
- [ ] **Step 4: Regelprüfung der Spec**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
rg -n "!important" src # 1
|
||
rg -n -e "gradient\(" -e "backdrop-filter" -e "filter: *blur" src --glob '*.css' # 2
|
||
rg -n "text-transform" src --glob '*.css' # 3
|
||
rg -n "font-weight: *(800|900)" src # 4
|
||
rg -n -e "Lato" -e "@font-face" src index.html # 5
|
||
rg -n "font-family" src --glob '*.css' # 6
|
||
rg -n -e "color-scheme" -e "data-theme" -e "data-accent" src index.html # 7
|
||
rg -no -e "@media[^{]*" -e "@container[^{]*" src --glob '*.css' # 8
|
||
rg -n "<svg" src --glob '*.jsx' # 9
|
||
rg -n -e "Kpi" -e "kpi" src # 10
|
||
rg -n -e "<title>" -e 'rel="icon"' index.html # 11
|
||
for s in '\.num' '\.stat \.v' '\.fin-amount'; do printf '%s: ' "$s"; rg -l -U "$s([^A-Za-z0-9_{}-][^{}]*)?\{[^}]*tabular-nums" src --glob '*.css' | tr '\n' ' '; echo; done # 12
|
||
```
|
||
Expected:
|
||
- 1, 4, 5 und 10: leer.
|
||
- 2: höchstens eine Zeile, der Chevron von `.select`. 3: eine Zeile, die Wochentage `.wd` im Planboard.
|
||
- 6: nur `var(--font)` und der Monospace-Stapel (`ui-monospace`). 7: nur `color-scheme: light`.
|
||
- 8: nur `max-width: 1100px` und `860px`, bei `@container` 560, 640 und 860 px, dazu `prefers-reduced-motion`. Zugelassen ist außerdem der eine Block `max-width: 640px` in `src/styles/chat.css`: Er setzt im Eingabefeld des fremden Portal-Composers wieder `font-size: 16px` (gegen das iOS-Zoomen, P6) und ist die WOMS-eigene Überschreibung des Composers.
|
||
- 9: nur `Logo.jsx` und `Sparkline.jsx`. 11: `Webklar WOMS 2.0` und die Zeile für `/favicon.svg`.
|
||
- 12 (Spec-Regel 6, Zahlen und Beträge): drei Zeilen, jede nennt mindestens `src/styles/global.css`. Fehlt bei einem Selektor die Datei, trägt seine Regel kein `font-variant-numeric: tabular-nums`. P10 ergänzt dann genau diese Deklaration an der bestehenden Regel. Das ist die einzige erlaubte Abweichung von der Pixelinvariante. Die Ansichten, die dadurch im Vergleich von Task 8 abweichen, stehen mit Begründung in Abschnitt 5.
|
||
- Spec-Regel 4 (höchstens ein schwarzer Knopf je Seitenkopf) prüft kein `rg`, sondern der Check `max-primary` im Gate `p10` (Task 1 Step 6, Lauf in Task 8 Step 2).
|
||
|
||
Seitenbreakpoints außerhalb von 860 und 1100 px werden auf diese Werte gezogen (Spec, Regel 7), ausgenommen der 640-px-Block in `chat.css`. Jede andere Abweichung steht mit Begründung in Abschnitt 7. Befehl, Ausgabe und Urteil jeder Zeile stehen in Abschnitt 5.
|
||
|
||
- [ ] **Step 5: Invarianten gegen `design-p0`**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
git grep -ho 'data-testid=[^ >]*' design-p0 -- src | sort -u > "$TMPDIR/ti-p0.txt"
|
||
rg -oN --no-filename 'data-testid=[^ >]*' src | sort -u > "$TMPDIR/ti-jetzt.txt"
|
||
diff "$TMPDIR/ti-p0.txt" "$TMPDIR/ti-jetzt.txt" | rg '^<'
|
||
echo "confirm: $(git grep -h 'window\.confirm' design-p0 -- src | wc -l) -> $(rg --no-filename 'window\.confirm' src | wc -l)"
|
||
git diff --name-status design-p0..HEAD -- src/hooks src/lib
|
||
```
|
||
Expected:
|
||
- Das `diff` zeigt keine `<`-Zeile, es ging keine `data-testid` verloren. Neue (`>`) sind erlaubt und werden genannt.
|
||
- Die Zahl der `window.confirm` ist gleich.
|
||
- In `src/hooks` steht nur `M useWorkorders.js` plus die neuen `useWorkorder.js`, `useTicketCounts.js`, `useTicketMinutes.js`. In `src/lib` stehen nur `D sidebar.js`, neue Dateien (darunter `rowClick.js` aus P2) und `M` für `ticketStatus.js`, `navLinks.js`, `previewEnv.js`, `serverpulsFormat.js`, `creditFormat.js`, `offerFormat.js`, `storageFormat.js`, `projectList.js`, `leads.js`. Jede andere `M`- oder `D`-Zeile ist ein Befund.
|
||
|
||
Die Ausgaben stehen in Abschnitt 5.
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" --nur-tests && git status --short`
|
||
Expected: Exit 0, `# fail 0`, `# pass` = `N9 + 2`, nur die erwarteten Änderungen.
|
||
|
||
```bash
|
||
git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md <die geprüften Dateien aus Step 1 bis 4>
|
||
git commit -m "Aufraeumen: Inline-Styles nur noch fuer Laufzeitwerte, Regelpruefung und Invarianten dokumentiert" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
### Task 8: Gate P10, Bundle, Review, Tag
|
||
|
||
- [ ] **Step 1: Rebase**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git fetch origin && git merge-base --is-ancestor design-p9 HEAD && git rebase origin/test && "$W/check.sh"`
|
||
Expected: `design-p9` ist Vorfahre, der Rebase läuft ohne Konflikt, Exit 0 mit `# fail 0` und `# pass` = `N9 + 2`. Gate, Bilder und Review beziehen sich damit auf den Stand, der getaggt wird.
|
||
|
||
- [ ] **Step 2: Vollständiger Lauf und Pixelvergleich**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/build.sh" "$WT" p10 && "$W/shots.sh" p10 "$W/shots/p10" --gate p10 && "$W/run-browser.sh" "$W/vergleich.mjs" "$W/shots/p9-ref" "$W/shots/p10" --rauschen "$W/shots/p9-ref2" --out "$W/shots/p10-diff"`
|
||
Expected:
|
||
- Das Gate `p10` endet mit Exit 0. Über alle Ansichten, auch die der Review-Focus-Punkte 1 bis 5 der Übersicht, gibt es keine Verstöße gegen `external-request`, `console-error`, `dark-surface`, `low-contrast`, `overflow-x`, `icon-svg` (außer unter `.woms-chat`), `max-primary` und `step-failed`.
|
||
- Der Vergleich endet mit Exit 0, `fehlt` ist leer, die Zahl der Ansichten gleicht der Sollzahl aus Task 1 Step 4. Rausch-Ansichten stehen in `$W/p10-rauschen.txt`.
|
||
- Die Ansicht `alt-link` hat keinen Verstoß. Ihr Schritt prüft, dass `/tickets?woid=100131&status=done` auf `/tickets/100131` endet.
|
||
|
||
- [ ] **Step 3: Bundle-Größe**
|
||
|
||
Run:
|
||
```bash
|
||
source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh &&
|
||
"$W/check.sh" --nur-build &&
|
||
{ find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.ttf' \) -printf '%s %p\n'; for f in dist/assets/*.js dist/assets/*.css; do echo "$f gzip=$(gzip -9 -c "$f" | wc -c)"; done; wc -l src/styles/*.css src/pages/*.css; } | tee "$W/p10-baseline-p10.txt"
|
||
```
|
||
Expected:
|
||
- Abschnitt 6 der Ergebnisdatei bekommt eine Tabelle mit den Zeilen JS in Byte, JS gzip, CSS in Byte, CSS gzip, Schrift in Byte, CSS-Zeilen und Testzahl und den Spalten P0, `design-p9`, P10. Die P0-Werte stammen aus der Commit-Zeile `Ausgangswerte` (Gegenprobe: Umbaukarte), die P9-Werte aus `$W/p10-baseline-p9.txt`.
|
||
- CSS und CSS-Zeilen sind kleiner als bei `design-p9`, JS ist nicht größer. Gegenüber P0 fehlen 96.184 B Schrift. Werte, die gegenüber P0 wachsen, stehen in Abschnitt 7.
|
||
|
||
- [ ] **Step 4: Ergebnisdatei abschließen**
|
||
|
||
Abschnitt 7 (Offene Punkte) ist gefüllt, auch wenn er nur „keine“ sagt.
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && git status --short`
|
||
Expected: nur `M docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md`.
|
||
|
||
```bash
|
||
git add docs/superpowers/plans/2026-10-05-weisses-design-p10-ergebnisse.md
|
||
git commit -m "Aufraeumen: Ergebnisdatei mit Bundle-Vergleich und offenen Punkten" -m "Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
|
||
```
|
||
|
||
- [ ] **Step 5: Code-Review (sonnet)**
|
||
|
||
Geprüft wird der Diff `design-p9..HEAD` gegen die Spec-Abschnitte „Übergangsschicht KOMPAT“, „Gestaltungsregeln“ und „Was gleich bleibt“, dazu liest der Prüfer die Ergebnisdatei. Schwerpunkte:
|
||
- Der Diff enthält nur Löschungen, Umbenennungen und Umstellungen auf vorhandene Bausteine, keine neuen Texte, Klassen oder Tokens außer dem Wächtertest.
|
||
- Zehn Stichproben aus Abschnitt 2 (KOMPAT) und 3 (tote Klassen): Die Klasse hat per `rg` keinen Nutzer, ihre Regel ist weg.
|
||
- `package.json` und Lock haben genau `@tabler/icons-react`, `@tabler/icons` und `react-icons` verloren.
|
||
- `git diff design-p9 -- src/pages/TicketsPage.jsx src/lib/ticketListUrl.js` ist leer oder enthält nur Kommentare, `woidRedirectTarget` ist erhalten.
|
||
- Jede Begründung in Abschnitt 4 stimmt, die Invarianten aus Abschnitt 5 sind erfüllt.
|
||
|
||
Wichtige Befunde werden behoben, danach laufen Step 1 bis 3 erneut. Kleinigkeiten kommen in Abschnitt 7.
|
||
|
||
- [ ] **Step 6: Tag und Übergabe**
|
||
|
||
Run: `source /root/reports/ticketsystem-design-2026-10-04/werkzeug/env.sh && "$W/check.sh" && git tag design-p10 && git log --oneline origin/test..design-p10 && git rev-parse design-p10`
|
||
Expected: Exit 0, Tag gesetzt. Brachte der Rebase in Step 1 neue Commits mit, liefen Gate und Vergleich bereits auf dem rebaseten Stand.
|
||
|
||
Der Eigentümer bekommt:
|
||
- den Bericht des Pixelvergleichs („0 abweichende Ansichten von <Zahl>“) und die Screenshots aus `$W/shots/p10/1440x900` und `$W/shots/p10/390x844` (Auswahl: `login`, `tickets`, `ticket`, `kunde-overview`, `projekte`, `finanzen`, `dlg-rechnung-kunde`, `serverpuls`, ein Alt-Dialog)
|
||
- die Bundle-Tabelle aus Abschnitt 6 der Ergebnisdatei
|
||
- den Hinweis, dass sichtbar nichts Neues erscheint, der Link `/tickets?woid=N` aus Portal-Mails weiter funktioniert und die offenen Punkte in Abschnitt 7 stehen
|
||
- den Hinweis, dass damit alle Pakete ausgeliefert sind und Worktree `dev-design` samt Branch `feature/design-weiss` danach entfernt werden können, wenn er das will
|
||
- die Push-Zeile `git -C /home/webklar/apps/ticket.webklar.com/dev-design push origin 'design-p10^{commit}:refs/heads/test'`
|
||
- die Rücknahme `git revert --no-commit design-p9..design-p10` (Commit und Push auf `test` durch den Eigentümer, gilt nur solange P10 das jüngste Paket ist)
|
||
|
||
- [ ] **Step 7: Nach dem Push (erst, wenn der Eigentümer gepusht hat)**
|
||
|
||
- Im Log von `webklar-ticket-build` steht „Deployment completed successfully“. Dort läuft `npm install` mit dem neuen Lock durch.
|
||
- `curl -s https://ticket.webklar.com/ | grep -o 'assets/index-[^"]*\.js'` entspricht `dist/index.html` des Tags.
|
||
- `curl -s -o /dev/null -w '%{http_code}' 'https://ticket.webklar.com/tickets?woid=1'` liefert 200 (Seiten-Fallback).
|
||
- Ein lesender Sichttest im Chrome des Eigentümers, ohne Schreibaktion: Ein alter Link `/tickets?woid=<N>` mit einer echten Nummer landet auf `/tickets/<N>`. Ticketliste, ein Ticket, das Menü mit dem Serverpuls-Punkt und ein Dialog (öffnen, mit Esc schließen) sehen aus wie vor dem Push, und die Konsole zeigt keinen Fehler.
|