docs(quick-260921-bi2): Lint-Rueckstand 2923 -> 465, Akte und Verifikation
Tessera CI/CD / Lint & Type Check (push) Successful in 51s
Tessera CI/CD / Tests (push) Successful in 1m5s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 5m24s
Tessera CI/CD / Build & Publish Images (push) Successful in 4m15s

Zusammenfassung, Verifikation und STATE.md zum Quick-Vorgang 260921-bi2.

Kernbefund: Biomes als "safe" eingestufte Korrektur style/useImportType
zerstoert in apps/api die NestJS-Abhaengigkeitsspritze — das erzeugte
__metadata("design:paramtypes", [...]) kollabiert zu [Function, ...] und
die API startet nicht mehr, waehrend tsc gruen bleibt und alle 1124
API-Tests gruen bleiben (kein Test ruft createTestingModule auf).
Deshalb ein zweiter, auf apps/api/** begrenzter overrides-Eintrag.

Nachweis fuer "kein Verhaltenswechsel" ist nicht die Testsuite, sondern
ein sha256 ueber alle 593 erzeugten __metadata-Zeilen (6e1583f1...),
vor und nach dem Umbau identisch. Dazu Klicktest am laufenden System
mit den echten Abbildern: API healthy, Abbrechen legt nichts an,
Speichern legt an, ADMIN sieht auf der SUPER_ADMIN-Zeile nur Details,
abgewiesene Server-Antworten erscheinen sichtbar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
2026-09-21 10:02:44 +02:00
parent 97a6836444
commit c001a081c2
3 changed files with 556 additions and 5 deletions
+6 -5
View File
@@ -4,10 +4,10 @@ milestone: v1.2
current_phase: 18
current_phase_name: desktop-client-fertigstellen
status: verified
stopped_at: "WINDOWS #35 und #36 abgeschlossen und verifiziert (7 Commits, alle Gatter gruen); nicht gepusht — Push und CI-Lauf stehen noch aus"
last_updated: "2026-09-21T05:45:00.000Z"
stopped_at: "WINDOWS #35, #36 und der Lint-Rueckstand abgeschlossen und verifiziert (inkl. Klicktest am laufenden System); Push und CI-Lauf fuer das Image stehen an. CI-Lauf 388 war rot durch einen Absturz des Gitea-Runners (act_runner v0.6.1, panic: close of closed channel) — Lint/Type-Check/Tests waren darin gruen, nur der Desktop-Job starb, dadurch wurde Build & Publish Images uebersprungen."
last_updated: "2026-09-21T08:10:00.000Z"
last_activity: 2026-09-21
last_activity_desc: Quick 260921-9ie und 260921-a1d — WINDOWS #35 (Biome lauffaehig, Lint-Tor scharf) und #36 (Benutzerverwaltung meldet 403 sichtbar, keine Aktionsknoepfe auf SUPER_ADMIN-Zeilen fuer ADMIN) geschlossen und verifiziert
last_activity_desc: Quick 260921-9ie, 260921-a1d und 260921-bi2 — Biome lauffaehig und Lint-Tor scharf, Benutzerverwaltung meldet abgewiesene Aktionen sichtbar, Lint-Rueckstand 2923 → 465; alle drei verifiziert, der letzte zusaetzlich per Klicktest am laufenden System
state_head: 4d485432c003a6caf68f6d85aff7de0bd27794e2
progress:
total_phases: 18
@@ -31,7 +31,7 @@ See: .planning/PROJECT.md (updated 2026-07-17)
Phase: 18 (desktop-client-fertigstellen) — COMPLETE (2026-09-17, Verifikation passed, Windows-Bedienprobe bestanden)
Plan: 6 of 6
Status: Alle 18 Phasen abgeschlossen; Version 1.2.0 freigegeben. Kein laufender Meilenstein. Nach 1.2.0 auf main (Beta): Bildmarke in Akzentfarbe, CI-Desktop-Skip, Favoriten-Symbol/-Sortierung, Desktop-Server-Adresse, Update in der App (signiert), Versionszeile auf der Setup-Seite — alles verifiziert und auf VM/CI nachgewiesen
Last activity: 2026-09-21 - Quick 260921-a1d (WINDOWS #36): Benutzerverwaltung meldet abgewiesene Server-Antworten sichtbar (drei Stellen), ADMIN bekommt in der SUPER_ADMIN-Zeile keine Aktionsknoepfe mehr; apps/api unangetastet, Web-Tests 66/459 gruen
Last activity: 2026-09-21 - Quick 260921-bi2: Lint-Rueckstand 2923 → 465 Warnungen abgebaut (Konfiguration, maschinelle Fixes, toter Code, 155 Handkorrekturen Barrierefreiheit); Beinahe-Schaden abgewendet — Biomes als sicher eingestufte useImportType-Korrektur haette die NestJS-Abhaengigkeitsspritze zerstoert, unbemerkt von tsc und 1124 gruenen Tests
Progress: [██████████] 99%
@@ -446,6 +446,7 @@ Gerettet aus `.continue-here.md`. Relevant fuer die noch offenen Live-Tests.
| fast | **Desktop-Client: Setup-Seite zeigt Version und Stand der App** („Tessera-App 1.2.0 · Stand a6d1a64"; ohne Stempel nur Version) — Command `get_client_info`, Helfer `client_info_label` (2 Tests), `<p id="client-info">` in setup.html, CHANGELOG. Diente zugleich als zweiter Desktop-Stand fuer den Update-Nachweis. 35 Rust-Tests. | 2026-09-18 | a6d1a64 | — |
| 260921-9ie | **Biome lauffaehig machen und das Lint-Tor scharf schalten (WINDOWS #35).** `biome.json` per `biome migrate` auf Biome 2.5.0 gezogen: `organizeImports` nach `assist.actions.source`, `linter.rules.recommended` → `preset: "recommended"`, `javascript.parser.unsafeParameterDecoratorsEnabled` (NestJS-Parameter-Dekoratoren: 238 parse-Fehler in 19 Dateien → 0), `quoteStyle: single` (belegt: 1496 einfach-gequotete Importzeilen gegen null doppelte), `vcs.useIgnoreFile`, Ausschluss von `**/__fixtures__/**` (nur html/zip/xml, keine TS-Datei) und `globals.css` (Tailwind-4-At-Regeln). `lint`-Skript (`biome lint .`) in allen fuenf Workspaces; `turbo.json` bekommt `globalDependencies: ["biome.json"]`, sonst liefert der Cache nach einer Regelaenderung alte Ergebnisse. **Zweig (b) gewaehlt, gemessen:** `biome check .` → Exit 1/760 Fehler, `biome lint .` → Exit 1/275, also kein "nur Warnungen"-Ausweg; Skript ruft `lint` statt `check` (haelt 319 Formatierungsbefunde draussen, kein Rundumumbau), Rest gezielt auf `warn` → 0 Fehler, Exit 0. **Sicherheit:** Gruppe `security` bleibt auf `error`, maschinell geprueft; die 6 `noScriptUrl`-Treffer lagen ausnahmslos in der ausgeschlossenen HTML-Testvorlage, keiner in echtem Quellcode. **Registereintrag #35 war in zwei Punkten falsch:** Pfad ist `apps/api/src/user/...` (Einzahl), und die Wirkung des Parser-Schalters betrug 238 statt 17 Fehler. **Nachweise (dreifach unabhaengig — Planer, Orchestrator, Verifier):** `pnpm lint` → "5 successful, 5 total", Exit 0 (vorher "No tasks were executed"); Gegenprobe mit Wegwerfdatei (`debugger`) → Exit 1 mit `noDebugger`, danach Baum wieder sauber; repo-weit 0 parse-Fehler, 0 Fehler; Diff nur Konfiguration/Skripte/Doku, keine Quelldatei, `pnpm-lock.yaml` unveraendert. Verifikation passed (7/7). **Offen als eigener Durchlauf:** rund 2800 Warnungen (`any`-Familie, Barrierefreiheit in `apps/web`), in `docs/anleitung-entwicklung.md` als bewusster Rueckstand festgehalten. | 2026-09-21 | 6a727e9,00d769b,6f0f05a | [260921-9ie-windows-35-biome-json-fuer-biome-2-5-0-r](./quick/260921-9ie-windows-35-biome-json-fuer-biome-2-5-0-r/) |
| 260921-a1d | **Benutzerverwaltung: verbotene Aktionen melden sich jetzt (WINDOWS #36).** Drei Stellen in `apps/web/src/app/(portal)/admin/users/page.tsx` verschluckten Server-Antworten still (`if (res.ok)` ohne else, `catch {}` mit dem Kommentar `// silently fail`): Liste laden, Formular speichern, Loeschen. Sichtbare Wirkung vorher: Formular blieb offen, Loeschdialog stand still, beim gescheiterten Laden log die Seite mit "Keine Benutzer gefunden". Jetzt je ein Banner (`role="alert"`) im Listenkopf, im Formulardialog und im Loeschdialog; `readApiMessage(res)` liest ausschliesslich `body.message` und zeigt den Servertext in einem deutschen Rahmensatz, sonst eine uebersetzte Ersatzmeldung — auch wenn der `fetch` selbst wirft. Vier Schluessel `admin.users.errors.*` in `de.json` **und** `en.json` (Katalog-Paritaet 890/890 geprueft). Dazu `canManageRow`: einem ADMIN werden Bearbeiten/Loeschen in der SUPER_ADMIN-Zeile gar nicht erst angeboten (seit #29 im Alltag erreichbar), "Details" bleibt ueberall. **`apps/api` blieb unangetastet** — der Zielrollen-Riegel im Controller ist und bleibt die wirksame Grenze, der versteckte Knopf ist Ergonomie darueber, kein Ersatz; eigenes Gatter im Plan weist das nach. Gemessen: keine Namen/IDs/Stapelspuren in den 403-Rumpftexten (kein eigener ExceptionFilter in `apps/api/src`). **Nachweise (dreifach unabhaengig):** Web-Tests 66 Dateien/459 Tests gruen (vorher 65/447, neue `users-page.test.tsx` prueft echten DOM-Text via `getByText`/`within`, nicht nur State-Setter), type-check Exit 0, `pnpm lint` 5/5 ohne neue Fehlerrang-Meldung, `silently fail` im Code 3 → 0, `role="alert"` 0 → 3, Diff nur vier Dateien unter `apps/web`. Verifikation passed (7/7). | 2026-09-21 | 38d2586,51bff75,13b70df | [260921-a1d-windows-36-benutzerverwaltung-zeigt-bei-](./quick/260921-a1d-windows-36-benutzerverwaltung-zeigt-bei-/) |
| 260921-bi2 | **Lint-Rueckstand abgebaut: 2923 → 465 Warnungen (WINDOWS #35 Folgearbeit).** Seit das Lint-Tor wirklich prueft, war der Rueckstand sichtbar. Aufgeteilt nach Risiko statt nach Datei: (1) Konfiguration — zwei begruendete `overrides`, (2) maschinelle Fixes + toter Code, (3) Barrierefreiheit von Hand. **Der wichtigste Befund ist ein Beinahe-Schaden:** Biomes `style/useImportType`-Korrektur ist als *safe* eingestuft, zerstoert in `apps/api` aber die NestJS-Abhaengigkeitsspritze — `__metadata("design:paramtypes", [PrismaService, …])` kollabiert zu `[Function, …]`, 61 von 65 Dateien betroffen, API startet nicht mehr. Dabei bleibt `tsc` gruen **und alle 1124 API-Tests bleiben gruen**, weil kein einziger Test `createTestingModule` aufruft — das waere durch jedes vorhandene Tor unbemerkt bis auf alpha durchgelaufen. Planer und Plan-Pruefer haben es unabhaengig voneinander reproduziert (Datei kompiliert, Metadatenzeile verglichen). Deshalb zweiter `overrides`-Eintrag auf `apps/api/**`. Zweite Falle, ebenfalls gemessen: `--only=<regel>` schaltet eine in der Konfiguration abgeschaltete Regel wieder AN — ein repo-weites `biome lint . --only=useImportType --write` haengt die Ausnahme aus (77 API-Dateien veraendert). Nur pfadgebundene Aufrufe. **Nachweis, dass sich nichts geaendert hat, ist NICHT die Testsuite**, sondern ein sha256 ueber alle 593 erzeugten `__metadata`-Zeilen: `6e1583f1…`, vor und nach dem Umbau identisch, dreifach geprueft. Barrierefreiheit: 155 Handkorrekturen in 53 Dateien (Symbole 71, Knopf-Typen 52, Beschriftungen 22, Rollen/Semantik 10) — je Fundstelle entschieden, ob ein Symbol dekorativ (`aria-hidden`) oder die einzige Beschriftung ist (`<title>`/`aria-label`); in der Seitenleiste erkannt, dass der Text beim Einklappen verschwindet, dort also ein echter Name noetig ist. Alle neuen Texte ueber next-intl in de **und** en (892/892 Schluessel). **Zahlen:** gesamt 2923 → 465, echter Quellcode 856 → 386, Testdateien 2067 → 79, Fehler-Rang durchgehend 0. **Bewusst NICHT angefasst, benannt statt stillschweigend:** 288 `noExplicitAny` im Quellcode (echte Typarbeit), 20 `useExhaustiveDependencies` (je ein moeglicher Effekt-Fehler), 30 a11y-Befunde mit Bedienentscheidungsbedarf, `noUselessSwitchCase` (Fallmarke dokumentiert Absicht), sowie fuenf tote Stellen, die Symptome echter Luecken sind — darunter: Passwortwechsel-Seite leitet nach erzwungenem Wechsel nicht weiter, Loeschknopf in `VehicleTable` ohne Besetztzustand, `force-password-change.interceptor` liest das HTTP-Verfahren und fragt es nie ab. **Klicktest am laufenden System** (echte Abbilder, Playwright): API meldet `healthy` und `Nest application successfully started` — Abhaengigkeitsspritze zur Laufzeit bewiesen; `Abbrechen` legt nichts an, `Speichern` legt an; als ADMIN bietet die SUPER_ADMIN-Zeile nur noch `Details`; abgewiesene Server-Antwort erscheint sichtbar als "Der Server hat die Aktion abgelehnt: …". Testbenutzer wieder geloescht. Verifikation passed. | 2026-09-21 | 8d1c8f3,636fe0d,+11 | [260921-bi2-lint-rueckstand-abbauen-mechanische-fixe](./quick/260921-bi2-lint-rueckstand-abbauen-mechanische-fixe/) |
## Deferred Items
@@ -491,4 +492,4 @@ Last session: 2026-09-21T04:50:00Z
Resumed: 2026-09-21 — Sitzung ueber /gsd-resume-work fortgesetzt. Stand geprueft: Arbeitsbaum sauber, main == origin/main auf 55aa287, CI-Lauf 387 fuer 55aa287 erfolgreich (Beta-Images gebaut). Push und CI aus dem letzten Stopp-Punkt sind damit erledigt.
Stopped at: Warte auf Nutzerentscheidung, womit weitergearbeitet wird. Offen fuer den User: alpha pullen (web+api) und danach am Windows-VM-Client die echte Fehlermeldung schicken (Betreff `[Desktop/Windows]` + `Herkunft:`-Zeile pruefen); eigenen Arbeitsplatz-Client einmal per Browser-Installer erneuern; Freigabe 1.3.0 auf Zuruf. Technisch offen im Ledger: WINDOWS #35 (Biome laeuft nicht — biome.json:3 `organizeImports` ist in Biome 2.5.0 unbekannt, `biome check` bricht mit Konfigurationsfehler ab, reproduziert 2026-09-21) und WINDOWS #36 (403-Antworten bleiben in handleSubmit/handleDelete ohne sichtbare Reaktion).
Resume file: None
Last activity: 2026-09-21 - Quick 260921-a1d (WINDOWS #36): Benutzerverwaltung meldet abgewiesene Server-Antworten sichtbar (drei Stellen), ADMIN bekommt in der SUPER_ADMIN-Zeile keine Aktionsknoepfe mehr; apps/api unangetastet, Web-Tests 66/459 gruen
Last activity: 2026-09-21 - Quick 260921-bi2: Lint-Rueckstand 2923 → 465 Warnungen abgebaut (Konfiguration, maschinelle Fixes, toter Code, 155 Handkorrekturen Barrierefreiheit); Beinahe-Schaden abgewendet — Biomes als sicher eingestufte useImportType-Korrektur haette die NestJS-Abhaengigkeitsspritze zerstoert, unbemerkt von tsc und 1124 gruenen Tests
@@ -0,0 +1,439 @@
---
phase: quick-260921-bi2
plan: 01
subsystem: tooling
tags: [biome, lint, a11y, nestjs, decorator-metadata, i18n]
requires: []
provides:
- "biome.json mit genau zwei zielgenauen overrides (Testdateien / apps/api) statt eines
unueberschaubaren 2923er-Rueckstands"
- "45 maschinell erzeugte, von Hand gelesene Korrekturen ueber vier sichere und fuenf
unsichere Biome-Regeln"
- "15 untersuchte Fundstellen toten Codes: 10 folgenlos entfernt, 1 umbenannt (NestJS-
Parameterposition), 4 als benannte Folgeaufgaben gemeldet statt repariert"
- "155 von Hand erledigte Barrierefreiheits-Fundstellen ueber sechs Regeln (Symbole,
Schaltflaechentyp, Beschriftungsbindung, Rollen/ARIA-Merkmale, Tab-Reihenfolge)"
- "Entwickleranleitung auf Endstand 465/386/79 gebracht, beide Ausnahmen begruendet,
Folgeaufgaben benannt"
affects: [ci-lint-gate, apps/web-a11y, apps/api-di]
actuals:
tokens: 37573
tasks: 3
commits: 13
tech-stack:
added: []
patterns:
- "biome.json overrides sind pfadgebunden (apps/api/**), nie repo-weit mit --only=<regel>
angewendet -- --only schaltet eine per Konfiguration abgeschaltete Regel wieder an."
- "Bei einer Regel ohne gesicherten Fix zuerst den Diff lesen (--write ohne --unsafe testen),
danach --unsafe pruefen, danach den ganzen Diff lesen -- nie ungeprueft anwenden."
- "a11y-Fixes koennen sich gegenseitig verschieben: eine Regel loesen kann eine ANDERE
(zurueckgestellte) Regel neu anschlagen, wenn ein Element seine interaktive
Klassifikation verliert (role=button entfernt -> noStaticElementInteractions greift
auf die verbliebenen Drag-Handler). Nach jedem Einzel-Fix die komplette Regelmenge
(in Scope UND zurueckgestellt) neu messen, nicht nur die Zielregel."
key-files:
created: []
modified:
- biome.json
- docs/anleitung-entwicklung.md
- "apps/api/src/** (45 maschinelle Korrekturen + toter Code, Aufgabe 2)"
- "apps/web/src/** (a11y, Aufgabe 3, beide Teillieferungen)"
- apps/desktop/src/setup.html
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
key-decisions:
- "useImportType in apps/api/** abgeschaltet statt maschinell angewendet: emitDecoratorMetadata
erzeugt __metadata(design:paramtypes,...), das NestJS zur Abhaengigkeitsaufloesung liest;
import type entfernt den Wert-Import und ersetzt die erzeugten Typen durch Function-
Platzhalter. 61 von 65 Dateien mit Abhaengigkeitsdaten waeren beschaedigt worden, bei
gruenem tsc und gruenen 1124 Tests (kein Test ruft createTestingModule auf) -- der Fehler
waere durch jedes Tor dieses Projekts unbemerkt hindurchgegangen."
- "noUselessSwitchCase (1 Fundstelle, tender-normalizer.service.ts:60) bewusst NICHT
angewendet: die Fallmarke dokumentiert, warum der Standardzweig auf diesem Weg bleiben
muss; die Regel sieht nur den Code, nicht die Absicht dahinter."
- "useSemanticElements (4 Fundstellen) wurde entgegen der urspruenglichen Einordnung in
PLAN.md (dort unter D-05 zurueckgestellt) in Teillieferung B doch bearbeitet -- Abweichung
von der Vorgabe, siehe Deviations."
- "DropZone.tsx: Datei-Entfernen-Schaltflaeche als Geschwister statt verschachtelt in der
Drop-Flaeche (kein <button> darf ein zweites <button> enthalten); Drag-Handler wanderten
von der Flaechen-<div> auf die Flaechen-<button>, sonst waere ein 'statisches Element mit
Ereignis-Handler' entstanden und haette zwei zurueckgestellte Regeln neu ausgeloest."
- "admin-sidebar.tsx/settings-sidebar.tsx: role=navigation vom <aside> aufs bereits
vorhandene <nav> verschoben statt das <aside> in ein zweites <nav> zu verwandeln --
sonst waere ein doppeltes Navigations-Landmark entstanden."
requirements-completed: [LINT-BACKLOG]
duration: ~150min (Teillieferung B; Gesamtvorgang laenger, ueber mehrere Sitzungen)
completed: 2026-09-21
status: complete
---
# Quick-Vorgang 260921-bi2: Lint-Rueckstand abbauen (mechanische Fixe) Summary
**Lint-Rueckstand von 2923 auf 465 Befunde gesenkt (0 Fehlerstufe durchgehend) — durch eine
begruendete, pfadgebundene Konfigurationsbereinigung, einen von Hand gelesenen maschinellen
Durchgang und 155 handgeschriebene Barrierefreiheits-Korrekturen, ohne die NestJS-
Abhaengigkeitsaufloesung anzutasten.**
## Performance
- **Aufgabe 1 (Konfiguration):** Commit `8d1c8f3`
- **Aufgabe 2 (maschinell + toter Code):** Commits `3811578`, `636fe0d`
- **Aufgabe 3, Teillieferung A (a11y — Symbole, Schaltflaechentyp, Layout/Formulare):**
Commits `e76f3b8`, `4cff316`, `ae82125`, `278aedb`, `969fd01`, `27a6e29`, `73ac08a`
- **Aufgabe 3, Teillieferung B (a11y — Rollen, Semantik, Tab-Reihenfolge, Beschriftungsbindung):**
Commits `21c85a8`, `c79bafa`
- **Abschlussarbeiten (Entwickleranleitung, dieser Vorgang):** Commit `97a6836`
- **Tasks:** 3 (laut PLAN.md), ueber mehrere Sitzungen in zwei Teillieferungen ausgefuehrt
- **Dateien geaendert (gesamter Vorgang):** 110 (biome.json, docs, 2 i18n-Kataloge, ~106 Quell-
und Testdateien)
- **Commits gesamt:** 13
## Vorher/Nachher
| Durchgang | gesamt | echter Quelltext | Testdateien | Fehlerstufe |
|---|---|---|---|---|
| Start | 2923 | 856 | 2067 | 0 |
| Aufgabe 1 — Konfiguration | 754 | 633 | 121 | 0 |
| Aufgabe 2 — maschinell + toter Code | 621 | 542 | 79 | 0 |
| Aufgabe 3A — a11y (Symbole, Schaltflaechen, Layout) | 497 | 418 | 79 | 0 |
| **Aufgabe 3B — a11y (Rollen, Semantik, Beschriftungen) — Endstand** | **465** | **386** | **79** | **0** |
Der Zielwert im PLAN.md-Text lautete 466; der korrekte Wert ist 465, weil Aufgabe 2 beim
Entfernen einer unbenutzten `catch (e: any)`-Bindung in `calendar.service.ts` inzidentell einen
zusaetzlichen `noExplicitAny`-Befund mitgenommen hat (288 statt 289 in echtem Quelltext, 0 in
Testdateien — die Testdatei-Ausnahme aus Aufgabe 1 reicht weiterhin nachweislich nicht in
Produktivcode hinein). Das ist keine nachtraeglich "passend gemachte" Zahl, sondern die
gemessene Tatsache; im Endstand wurde nichts unternommen, um wieder auf 466 zu kommen.
## Aufgabe 1: Konfiguration bereinigen
`biome.json` traegt seither genau zwei `overrides`-Eintraege, sonst nichts an der Regelmenge
geaendert; `security` kommt in der Datei nicht vor (erbt weiterhin `error`).
1. **Testdateien** (`**/*.spec.ts`, `**/*.spec.tsx`, `**/*.test.ts`, `**/*.test.tsx`):
`suspicious/noExplicitAny` auf `off`. Begruendung: `any` haengt dort ausnahmslos an
Attrappen; geprueft mit `grep -rln "^export" --include=*.spec.ts ...` — keine Testdatei
exportiert ein Symbol, keine Nicht-Testdatei fuehrt eine Testdatei ein.
2. **`apps/api/**`**: `style/useImportType` auf `off`. Das ist die wichtigste Einzelentscheidung
des gesamten Vorgangs — siehe naechster Abschnitt.
3. Die fehlerhafte Fixture-Ausnahme (`__fixtures__**` statt `__fixtures__`) korrigiert; Biome
meldte das selbst als `lint/suspicious/useBiomeIgnoreFolder`.
### Der useImportType/NestJS-Befund — der wichtigste Einzelfund dieses Vorgangs
`style/useImportType` ist mit 224 Befunden die groesste Einzelregel, 222 davon in `apps/api`.
Biome stuft die Korrektur als „sicher" ein und wendet sie standardmaessig ohne `--unsafe` an.
Sie ist es in diesem Projekt aber nicht: `apps/api/tsconfig.json` hat `emitDecoratorMetadata`
eingeschaltet, und NestJS loest seine Konstruktor-Abhaengigkeiten zur Laufzeit ueber genau die
Daten auf, die der TypeScript-Compiler aus den Parametertypen erzeugt
(`__metadata("design:paramtypes", [...])`). `import type` markiert einen Import als reinen
Typ-Import; der Compiler entfernt ihn vollstaendig aus dem erzeugten JavaScript — inklusive
der Werte, die `__metadata` braucht. Probelauf an `auth.service.ts` beim Planen: vorher
`__metadata("design:paramtypes", [prisma_service_1.PrismaService, ...])`, nachher
`__metadata("design:paramtypes", [Function, Function, Function, Function, Function, Function])`,
und die zugehoerige `require`-Zeile verschwindet ersatzlos. Ueber den ganzen Workspace gemessen:
**61 von 65 Dateien mit Abhaengigkeitsdaten waeren beschaedigt worden.** Die API startet danach
nicht mehr — jeder DI-Aufloesungsversuch traefe auf `Function` statt auf die echte Klasse.
Der entscheidende Punkt: **kein Tor dieses Projekts haette das bemerkt.** `pnpm type-check`
bleibt gruen (TypeScript prueft Typen, nicht erzeugte Laufzeit-Metadaten). Und kein einziger
der 1124 API-Tests waere rot geworden, denn `grep -rl createTestingModule apps/api/src` liefert
0 Treffer — der gesamte Testbestand startet den NestJS-Dependency-Injection-Container nirgends,
er testet Services/Controller mit von Hand konstruierten Abhaengigkeiten. Ein automatischer,
"sicherer" Fix haette die Anwendung im Betrieb lautlos zerstoert, waehrend jede automatisierte
Pruefung dieses Projekts weiterhin gruen gemeldet haette.
Biome raeumt das Problem in der eigenen Regelbeschreibung ein
(`biome explain useImportType` → Abschnitt „Caveat with TypeScript experimental decorators")
und empfiehlt dort woertlich, die Regel bei solchen Dekoratoren abzuschalten. Aufgabe 1 folgt
dieser Empfehlung mit einem auf `apps/api/**` begrenzten Eintrag — eine bewusste Abweichung von
der generellen mechanischen-Regeln-Vorgabe (D-02), die ausschliesslich deshalb geschieht, weil
"kein Verhaltenswechsel" (D-07) hier Vorrang vor einer kleineren Zahl hat.
**Nachweis, nicht Vermutung:** Vor dem maschinellen Durchgang (Aufgabe 2) wurde ein Fingerabdruck
ueber alle erzeugten `__metadata`-Zeilen genommen (593 Zeilen, sha256
`6e1583f1eb72a089eb0ed98f81158b54a9fbd40dbf41371292725f36ef764300`). Nach Abschluss aller drei
Aufgaben — Konfiguration, maschineller Durchgang, Barrierefreiheit — ist dieser Fingerabdruck
**Zeichen fuer Zeichen identisch**, gerade jetzt erneut gemessen:
```
$ SNAP=$(mktemp -d); pnpm --filter @tessera/api exec tsc --outDir "$SNAP"
$ grep -rh '__metadata(' "$SNAP" | wc -l
593
$ grep -rh '__metadata(' "$SNAP" | sort | sha256sum
6e1583f1eb72a089eb0ed98f81158b54a9fbd40dbf41371292725f36ef764300 -
```
Das ist der tragende Nachweis dieses gesamten Vorgangs — nicht der gruene Testlauf, der diesen
spezifischen Schaden nachweislich nicht aufdecken kann.
## Aufgabe 2: Maschinelle Korrekturen und toter Code
**(A) Vier Regeln mit gesichertem Fix** (`--write` ohne `--unsafe`): `style/useImportType`
(pfadgebunden auf `apps/web packages`, NIE repo-weit — ein repo-weiter Lauf haette die
Ausnahme aus Aufgabe 1 wirkungslos ausgehaengt und 201 `import type`-Zeilen nach `apps/api`
geschrieben, beim Planen genau so gemessen), `complexity/noUselessEscapeInRegex`,
`style/useConst`, `style/useExponentiationOperator`.
**(B) Fuenf Regeln mit `--unsafe`-Fix, Diff vollstaendig von Hand gelesen** (~100 Zeilen):
`style/useNodejsImportProtocol`, `complexity/useLiteralKeys`, `complexity/useOptionalChain`,
`style/useTemplate`, `correctness/useParseIntRadix`. Zwei Dateien brauchten besondere
Aufmerksamkeit:
- `ldap.service.ts` (25 der 31 `useLiteralKeys`-Aenderungen): Verzeichnis-Merkmale
(`objectGUID`, `sAMAccountName`, `cn`, `ou`, `mail`) zeichenweise gegengelesen — ein
verschluckter Grossbuchstabe macht den AD-Abgleich still leer, und AD ist in diesem Projekt
bewusst nur lesend angebunden, faellt also erst beim Anmelden auf.
- `jwt.strategy.ts` / `auth.service.ts`: Verkuerzungen im Anmeldeweg (`useOptionalChain`)
geprueft, dass eine fehlende Sitzung weiterhin zur Abweisung fuehrt, nicht zum Durchwinken.
**Die sechste ungesicherte Regel, `complexity/noUselessSwitchCase` (1 Fundstelle,
`tender-normalizer.service.ts:60`), wurde bewusst NICHT angewendet.** Der Vorschlag wuerde
eine Fallmarke streichen, die unmittelbar ueber einem Kommentar steht, der erklaert, warum der
Standardzweig genau auf diesem Weg bleiben muss. Die Marke dokumentiert Absicht, die der Regel
entgeht. Sie steht weiterhin sichtbar in der Zaehlung (1), nicht unterdrueckt — eine
Unterdrueckung waere hier unehrlicher als das sichtbare Stehenlassen, weil sie wie eine
Erledigung aussehen wuerde, ohne eine zu sein.
**(C) Toter Code, 15 Fundstellen, drei Gruppen:**
1. *Echt tot, folgenlos entfernt (10):* nicht benutzte Fehlervariablen in `calendar.service.ts`
(Zeilen 321, 358), `cert-manager.service.ts` (305, 679), `dkv-parser.service.ts` (42); nicht
benutzte Einfuhren in `create-calendar-source.dto.ts:2`; nicht benutzte Funktion
`forSystemQuery` in `rls-scratch-check.mjs:226`; und `login/page.tsx:21` (unbenutzter
Wegweiser — Weiterleitung ist nachweislich anderswo geloest, daher entfernt ohne Meldung).
2. *Nicht entfernbar, umbenannt (1):* `current-user.decorator.ts:4` — `data` ist der erste von
zwei positionsgebundenen NestJS-Parametern; Streichen wuerde den zweiten verschieben.
Stattdessen mit fuehrendem Unterstrich gekennzeichnet.
3. *Symptome, gemeldet statt repariert (4 — siehe naechster Abschnitt).*
### Die vier gemeldeten Symptomfunde (D-03) — offene Folgeaufgaben
Diese vier unbenutzten Werte waren beim Lesen KEIN totes Code-Rauschen, sondern der Hinweis auf
eine echte Luecke. Sie zu schliessen waere ein Verhaltenswechsel gewesen, den dieser
lint-abbauende Vorgang nicht treffen durfte (D-07):
1. **`force-password-change.interceptor.ts:53`** liest das HTTP-Verfahren in eine Variable und
befragt sie nie — die Freigabeliste unterscheidet also nicht zwischen Lese- und
Schreibzugriff auf die freigegebenen Wege. Variable entfernt, Luecke hier als eigene
Folgeaufgabe benannt.
2. **`change-password/page.tsx:11-12`** hielt Wegweiser und Benutzerablage vor, benutzte beide
nicht. Bestaetigt beim Lesen: nach erfolgreichem Wechsel wird weder weitergeleitet noch die
Benutzerablage aufgefrischt — bei erzwungenem Wechsel bleibt die Person auf der Seite
stehen. Die drei Bindungen entfernt, Befund hier als Folgeaufgabe benannt.
3. **`VehicleTable.tsx:164`** setzte einen Laufzustand fuers Loeschen, las ihn aber nie — die
Loeschschaltflaeche hat also keinen Besetztzustand und laesst sich doppelt ausloesen. Nur
die lesende Bindung entfernt, die setzende blieb; Befund hier als Folgeaufgabe benannt.
4. **`SplitTab.tsx:20`** bekam die Uebersetzungsfunktion und benutzte sie nicht — ein Hinweis
auf fest verdrahtete Texte in diesem Reiter. Parameter entfernt, Befund hier als
Folgeaufgabe benannt.
(Ein fuenfter untersuchter Kandidat, `login/page.tsx:21`, gehoerte urspruenglich zur selben
"Symptom"-Kategorie in der Planung, stellte sich beim Lesen aber als echt folgenlos heraus —
siehe Gruppe 1 oben. Er wird hier zur Vollstaendigkeit genannt, braucht aber keine eigene
Folgeaufgabe.)
**Nachweis fuer den gesamten maschinellen Durchgang:** 45 Quelldateien geaendert, Diff
zeilenbilanziert (keine Formatierung mitgelaufen, D-08), NestJS-Metadaten-Fingerabdruck
unveraendert (siehe oben), beide Testlaeufe punktgleich gruen.
## Aufgabe 3: Barrierefreiheit von Hand (beide Teillieferungen)
155 Fundstellen in 53 Dateien, durchgehend Handarbeit — fuer alle sechs bearbeiteten Regeln bot
Biome weder einen gesicherten noch ungesicherten Fix (einzige Ausnahme: `noRedundantRoles` mit 3
Dateien unter `--unsafe`, Ergebnis trotzdem gelesen).
### Teillieferung A (vorherige Sitzung, Commits `e76f3b8` … `73ac08a`)
- `a11y/noSvgWithoutTitle` (71): je Symbol entschieden — begleitet es sichtbaren Text, wird es
als Schmuck vor der Vorlesehilfe verborgen; steht es allein, bekommt es einen Titel, der die
Bedienung nennt (Uebersetzungskatalog, wo die Datei schon uebersetzt ist). Zwei Fundstellen
ausserhalb der React-Oberflaeche: `apps/web/src/app/icon.svg` (Bildmarke, Titel mit
Produktnamen) und `apps/desktop/src/setup.html:173` (Desktop-Einrichtungsseite).
- `a11y/useButtonType` (52): nur 3 von 25 betroffenen Dateien enthalten ein Formular
(`admin/tenants/page.tsx`, `admin/users/page.tsx`, `admin/ldap/page.tsx`); dort war der
Absendeknopf je bereits richtig ausgezeichnet (1/1/2), die restlichen 16 Fundstellen waren
Neben-Schaltflaechen (Abbrechen, Schliessen, Zeilenaktionen), die beim Klick ungewollt
absendeten — bekamen `type="button"`. In den uebrigen 22 Dateien ohne Formular ist die
Auszeichnung reine Absicherung.
- Zwei neue Uebersetzungsschluessel (LDAP-Standardzuordnung, Suchbutton), in `de.json` UND
`en.json` ergaenzt (Commit `3811578`).
### Teillieferung B (diese Sitzung, Commits `21c85a8`, `c79bafa`)
Die verbleibenden fuenf zugewiesenen Regeln (32 Fundstellen) auf 0 gebracht:
- **`a11y/noRedundantRoles` (4):** maschineller `--unsafe`-Fix, gelesen. Entfernte
`role="button"`/`role="time"`/`role="combobox"` von `button`/`time`/`select`-Elementen, wo
die Rolle bereits implizit ist.
- **`a11y/useAriaPropsForRole` (1):** entfiel automatisch mit obigem Fix — das
`<select role="combobox">` in `search-widget.tsx` verlangte die fehlenden ARIA-Attribute nur
wegen der ueberfluessigen Rolle.
- **`a11y/useSemanticElements` (4):** `admin-sidebar.tsx`/`settings-sidebar.tsx` tragen
`role="navigation"` jetzt am bereits vorhandenen `<nav>` statt am `<aside>` (kein doppeltes
Landmark); `widget-wrapper.tsx` ist jetzt ein echtes `<article>` statt `div role="article"`;
`DropZone.tsx` trennt die "Entfernen"-Schaltflaeche als Geschwister ab, damit die Drop-Flaeche
selbst ein echtes `<button>` werden kann (ein `<button>` darf kein zweites `<button>`
verschachteln) — Klick- UND Drag-Handler wanderten dabei auf den `<button>`, sonst waere die
umgebende `<div>` ein "statisches Element mit Ereignis-Handler" geworden und haette die
zurueckgestellten Regeln `noStaticElementInteractions`/`noNoninteractiveElementInteractions`
neu ausgeloest (geprueft — geschah zunaechst versehentlich, wurde vor dem Commit korrigiert).
- **`a11y/noNoninteractiveTabindex` (1):** `calculator-widget.tsx` traegt jetzt `tabIndex={-1}`
statt `{0}`. Die Zifferntasten sind bereits echte `<button>`-Elemente und damit selbst Teil
der Tab-Reihenfolge; Tastendruecke erreichen `handleKeyboard` weiterhin per Bubbling, sobald
eine Taste fokussiert ist — Verhalten unveraendert, nur ein wirkungsloser Tab-Stopp auf dem
Container selbst entfaellt.
- **`a11y/noLabelWithoutControl` (22):** jede Beschriftung ueber `htmlFor`/`id` an ihr Feld
gebunden — in Formularen mit wiederholten Feldnamen (LDAP, Benutzer, Mandanten) ueber
seitenweit eindeutige, praefixierte Kennungen (`ldap-*`, `user-*`, `tenant-*`). Sonderfall
`calendar-source-form.tsx`: die Farbauswahl beschriftet eine ganze Gruppe von
Farb-Schaltflaechen, kein einzelnes Feld — dafuer `fieldset`/`legend` statt `htmlFor`/`id`
(Rand/Abstand zurueckgesetzt, damit sich am Erscheinungsbild nichts aendert); eine Umwandlung
in `<span>` haette die Assoziation entfernt statt sie herzustellen und wurde darum nicht
gewaehlt.
### Was bewusst stehen bleibt (30 Befunde, D-05)
Diese fuenf Regeln wurden NICHT bearbeitet, weil jede eine Gestaltungsentscheidung oder einen
Verhaltenswechsel verlangt, den dieser Vorgang nicht treffen darf. Gepruefte, unveraenderte
Zaehlung nach Teillieferung B:
| Regel | Befunde | Warum zurueckgestellt |
|---|---|---|
| `a11y/noNoninteractiveElementInteractions` | 11 | verlangt die Entscheidung, ob ein geklickter Bereich eine echte Bedienung wird oder der Klick verschwindet |
| `a11y/noStaticElementInteractions` | 5 | dieselbe Entscheidung, andere Fundstellenmenge |
| `a11y/useKeyWithClickEvents` | 5 | verlangt einen Tastaturweg, den es heute nicht gibt — neue Bedienung, kein Aufraeumen |
| `a11y/useAriaPropsSupportedByRole` | 5 | verlangt einen Blick auf jede gesetzte Rolle einzeln, teils mit Gestaltungsfolgen |
| `a11y/noAutofocus` | 4 | Entfernen verschiebt den Eingabefokus beim Seitenaufruf — Verhaltenswechsel (D-07 verbietet ihn hier) |
Keine dieser Regeln wurde herabgestuft oder abgeschaltet — sie stehen weiterhin auf `warn` und
tauchen in keiner `overrides`-Ausnahme auf.
## Verifikation (soeben erneut ausgefuehrt)
```
--- in-scope (Ziel 0) ---
noLabelWithoutControl 0
noRedundantRoles 0
useSemanticElements 0
useAriaPropsForRole 0
noNoninteractiveTabindex 0
--- zurueckgestellt (muss unveraendert bleiben) ---
noNoninteractiveElementInteractions 11
useKeyWithClickEvents 5
noStaticElementInteractions 5
useAriaPropsSupportedByRole 5
noAutofocus 4
Endstand: total 465 real 386 test 79 errors 0
```
- **`apps/api` und `packages` unberuehrt seit `636fe0d`:** `git diff --name-only 636fe0d..HEAD -- apps/api packages` → leer.
- **NestJS-`__metadata`-Fingerabdruck:** 593 Zeilen, sha256
`6e1583f1eb72a089eb0ed98f81158b54a9fbd40dbf41371292725f36ef764300` — identisch zum Ausgangswert.
- **`apps/web` Vitest:** `Test Files 66 passed (66)`, `Tests 459 passed (459)`.
- **`apps/api` Vitest:** `Test Files 69 passed (69)`, `Tests 1124 passed (1124)`.
- **`pnpm type-check`:** 4/4 erfolgreich.
- **`pnpm lint --force`:** 5/5 erfolgreich, 0 Befunde der Stufe Fehler (nur Warnungen/Info).
- **de/en-Uebersetzungskataloge:** 892 Schluessel je Katalog, Mengen identisch (0 nur-de, 0 nur-en).
- **`noExplicitAny` nach der Testdatei-Ausnahme:** 288 in echtem Quelltext (siehe Abschnitt
"Vorher/Nachher" fuer die 289→288-Abweichung), 0 in Testdateien.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] Handler-Typannotation in DropZone.tsx nach Restrukturierung**
- **Found during:** Teillieferung B, `useSemanticElements`-Fix an `DropZone.tsx`
- **Issue:** Nach dem Verschieben der Drag-Handler von der `<div>` auf die `<button>`
blieb die Typannotation `React.DragEvent<HTMLDivElement>` stehen; `pnpm type-check` schlug
mit zwei `TS2322`-Fehlern fehl.
- **Fix:** Annotation auf `React.DragEvent<HTMLButtonElement>` korrigiert.
- **Files modified:** `apps/web/src/app/(portal)/modules/cert-manager/components/DropZone.tsx`
- **Verification:** `pnpm type-check` danach 4/4.
- **Committed in:** `21c85a8`
**2. [Rule 1 - Bug, waehrend der Arbeit selbst erkannt und korrigiert] Neu ausgeloeste
zurueckgestellte Regeln in DropZone.tsx**
- **Found during:** Teillieferung B, unmittelbar nach dem ersten Entwurf des
`useSemanticElements`-Fixes an `DropZone.tsx`
- **Issue:** Das blosse Entfernen von `role="button"`/`tabIndex`/`onClick` von der Flaechen-
`<div>` (um die Verschachtelung von zwei `<button>`-Elementen aufzuloesen) liess die
verbliebenen `onDragOver`/`onDragLeave`/`onDrop`-Handler auf einer jetzt rollenlosen `<div>`
stehen — das loeste `noStaticElementInteractions` und `noNoninteractiveElementInteractions`
NEU aus, zwei Regeln, die laut Auftrag bei 5 bzw. 11 unveraendert bleiben mussten.
- **Fix:** Struktur korrigiert: die Drop-Flaeche selbst wurde zum `<button>` (traegt jetzt
Klick- UND Drag-Handler), die "Entfernen"-Schaltflaeche liegt als absolut positioniertes
Geschwister in der Ecke statt verschachtelt.
- **Files modified:** dieselbe Datei wie oben.
- **Verification:** Volle Regelmessung nach dem Fix zeigt `noStaticElementInteractions=5`,
`noNoninteractiveElementInteractions=11` — unveraendert zum Ausgangswert.
- **Committed in:** `21c85a8` (im selben Commit korrigiert, nie mit dem Fehler committet)
---
**Total deviations:** 2 auto-fixed (1 blocking type error, 1 selbst erkannte und vor dem
Commit korrigierte Regelkollision). Keine der beiden Abweichungen hat den Endstand beeinflusst
— beide wurden vor dem jeweiligen Commit vollstaendig geloest.
### Vom Plantext abweichende Zuordnung
**[Scope-Abweichung] `a11y/useSemanticElements` (4 Fundstellen) in Teillieferung B bearbeitet,
obwohl PLAN.md diese Regel unter D-05 als "erst mit Gestaltungsentscheidung" zurueckgestellt
hatte.** Der Auftrag fuer diese Sitzung hat die Regel explizit in den 32er-Umfang von
Teillieferung B aufgenommen (Zielwert 465 rechnet sie mit ein: 497 − 32 = 465). Bearbeitet wie
oben beschrieben — in allen vier Faellen ohne Verhaltenswechsel, nur Tag-/Attributverschiebung.
Dokumentiert hier, weil PLAN.md selbst etwas anderes vorsah.
## Issues Encountered
Keine ungeloesten Probleme. Die einzige echte Schwierigkeit — die gegenseitige Verschiebung von
a11y-Klassifikationen zwischen bearbeiteten und zurueckgestellten Regeln bei `DropZone.tsx` — ist
unter Deviations dokumentiert und vor dem Commit geloest worden.
## Known Stubs
Keine. Alle Aenderungen sind vollstaendige, funktionierende Korrekturen; keine Platzhalter,
keine leeren Datenquellen.
## User Setup Required
None — keine externe Konfiguration erforderlich.
## Next Phase Readiness
Der Lint-Rueckstand ist von 2923 auf 465 gesunken und vollstaendig benannt: fuenf
zurueckgestellte a11y-Regeln (30 Befunde, D-05), eine bewusst nicht angewendete Regel
(`noUselessSwitchCase`, 1 Befund) und vier gemeldete D-03-Symptomfunde. Empfohlene Folgeaufgaben
fuer einen spaeteren Vorgang, in absteigender Dringlichkeit:
1. `force-password-change.interceptor.ts` — HTTP-Verfahren tatsaechlich pruefen, sonst
unterscheidet die Freigabeliste nicht zwischen Lese- und Schreibzugriff.
2. `change-password/page.tsx` — nach erzwungenem Wechsel weiterleiten und Benutzerablage
auffrischen.
3. `VehicleTable.tsx` — Besetztzustand der Loeschschaltflaeche tatsaechlich anzeigen.
4. `SplitTab.tsx` — fest verdrahtete Texte durch den Uebersetzungskatalog ersetzen.
5. Die fuenf zurueckgestellten a11y-Regeln (30 Befunde) als eigener, mit UI/Design
abgestimmter Durchgang.
Kein Blocker fuer laufenden Betrieb: `pnpm lint --force` bleibt gruen, CI-Tor unveraendert scharf.
## Self-Check: PASSED
Alle referenzierten Dateien (`biome.json`, `docs/anleitung-entwicklung.md`, diese Summary,
`DropZone.tsx`, `calendar-source-form.tsx`) auf Datenträger gefunden. Alle referenzierten
Commit-Hashes (`8d1c8f3`, `3811578`, `636fe0d`, `e76f3b8`, `4cff316`, `ae82125`, `278aedb`,
`969fd01`, `27a6e29`, `73ac08a`, `21c85a8`, `c79bafa`, `97a6836`) im Verlauf gefunden.
---
*Vorgang: quick-260921-bi2*
*Abgeschlossen: 2026-09-21*
File diff suppressed because one or more lines are too long