Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
11 KiB
phase, plan, status, subsystem, tags, dependency-graph, tech-stack, key-files, decisions, metrics, actuals, plan_head_before
| phase | plan | status | subsystem | tags | dependency-graph | tech-stack | key-files | decisions | metrics | actuals | plan_head_before | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260916-iex | 01 | complete | dashboard-widgets |
|
|
|
|
|
|
|
3c890af |
Phase quick-260916-iex Plan 01: Dashboard-Widgets — Notiz-Häkchen, Favoriten-Titel, Link-Widget entfernt Summary
Drei vom Anwender festgelegte Nachbesserungen an den Dashboard-Widgets: Aufgabenlisten im Notiz-Widget sind in der Ansicht jetzt direkt per Klick abhakbar, das Favoriten-Widget bekommt einen optionalen Titel mit eigener Kopfzeile, und das überflüssig gewordene Einzel-Link-Widget ist vollständig aus Web, API, i18n und Handbuch entfernt (samt idempotenter Aufräum-Migration für bestehende Datenbanken).
Was gebaut wurde
Task 1 — Notiz-Widget: Aufgabenlisten abhakbar (Commit 684f063)
Neues Hilfsmodul note-task-list.tsx mit TASK_LINE_RE (GFM-konforme, bewusst strenge Regex), isTaskLine, toggleTaskLine (überspringt Code-Zäune, kippt exakt die N-te Aufgabenzeile) und NoteCheckbox (kein disabled, zieht nur checked aus den Props). note-widget.tsx reicht components: { input: NoteCheckbox } über previewOptions an react-markdown durch — das greift NACH rehypeSanitize, das dadurch unangetastet als XSS-Schranke aktiv bleibt. Ein delegierter Klick-Handler am Vorschau-Container ermittelt den Kästchen-Index, kippt die Zeile, verwirft einen eventuell laufenden Tipp-Entprell-Timer und speichert sofort über den bestehenden save-Pfad. 16 Tests (9 Hilfsmodul inkl. eines Tests mit dem echten MDEditor.Markdown, 7 Widget).
Task 2 — Favoriten-Widget: optionaler Titel (Commit 7f1ee3b)
config.title (nur typeof === 'string') steuert eine Kopfzeile im Notiz-Look: leer + nicht im Bearbeitungsmodus → keine Kopfzeile; sonst H2 (Ansicht) bzw. Textfeld (Bearbeitungsmodus, widgetNoDrag, 1500 ms entprellt, Muster note-widget.tsx). Im Einstellungsfeld ergänzt FavoritesConfig (Muster NoteConfig) ein Titelfeld, die Instanz-Kopfzeile zeigt „— {title}“ jetzt für note UND favorites. Die bisher hart kodierte Beschriftung „Title“ bei NoteConfig ist übersetzt. 3 neue Schlüssel (note.titleLabel, favorites.titleLabel, favorites.titlePlaceholder) in de/en. 7 neue Tests (4 Widget, 3 Panel).
Task 3 — Link-Widget restlos entfernt (Commit 39ea147)
link-widget.tsx/.test.tsx gelöscht; Typ link aus WidgetType, WIDGET_CONSTRAINTS, WIDGET_REGISTRY (Icon + wire-Funktion), Katalog, Seiten-Verdrahtung, Tests und i18n (de/en) entfernt. API: create-widget.dto.ts (@IsIn-Liste) und widget-module-map.ts (Kommentare) auf sieben Typen angepasst, schema.prisma unverändert. Neue Migration 20260916120000_remove_link_widget mit genau einer idempotenten DELETE FROM "WidgetInstance" WHERE "widgetType" = 'link'; (FavoriteLink kaskadiert über den bestehenden FK) — nicht ausgeführt, der Anwender spielt sie per Deploy ein. Neuer widget-wrapper.test.tsx belegt, dass unbekannte Widget-Typen weiterhin als grauer Text ohne Absturz rendern. Handbuch (Widget-Tabelle, Einstellungs-Hinweise) und CHANGELOG (Geändert/Entfernt/Behoben) aktualisiert.
Gemessene Zahlen
- Vorher:
pnpm --filter @tessera/web exec vitest run→ 51 Dateien / 332 Tests. - Nachher: 52 Dateien / 344 Tests, alle grün (Erwartung im Plan: ≥ 340 Tests — erfüllt).
pnpm --filter @tessera/web type-check→ Exit 0.pnpm --filter @tessera/api type-check→ Exit 0.pnpm --filter @tessera/api exec vitest run src/dashboard→ 31 Tests grün.- Umlaut-Wächter → 3/3 grün.
git diff --quiet HEAD -- apps/api/prisma/schema.prisma→ unverändert (kein Diff).- Kein
biome check, keinprisma migrate, kein Docker-Build, kein Deploy, kein Testserver, keingit push.
Commits
684f063— feat(web): Notiz-Widget — Aufgabenlisten in der Ansicht abhakbar7f1ee3b— feat(web): Favoriten-Widget — optionaler Titel (Kopfzeile, FavoritesConfig, i18n)39ea147— feat: Link-Widget restlos entfernt (Web, API, Migration, Handbuch, Changelog)
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] PREVIEW_OPTIONS als as const-Objekt kollidierte mit dem erwarteten mutable Typ
- Found during: Task 1, Type-Check-Verifikation
- Issue:
previewOptions: { rehypePlugins: [[rehypeSanitize]], components: {...} } as constfrorrehypePluginsauf ein readonly-Tupel ein;@uiw/react-md-editorspreviewOptions-Prop erwartet ein mutablePluggable[](react-markdown), tsc schlug fehl. - Fix:
as constentfernt, stattdessenPREVIEW_OPTIONS: PreviewOptions = {...}mittype PreviewOptions = NonNullable<React.ComponentProps<typeof MDEditor>['previewOptions']>(direkter Typimport aus dem transitiven Paket@uiw/react-markdown-previewscheiterte unter pnpms strikter Isolation, da es keine direkte Dependency vonapps/webist). - Files modified:
apps/web/src/components/dashboard/widgets/note-widget.tsx - Commit:
684f063
2. [Rule 1 - Bug] FavoritesConfig zeigte einen Leerraum-only-Titel roh statt getrimmt an
- Found during: Task 2,
widget-settings-panel.test.tsxTest B2 - Issue:
FavoritesConfig(MusterNoteConfig, das nicht trimmt) zeigte beiconfig.title === ' 'den rohen Leerraum im Feld an; der Plan erwartet einen getrimmt-leeren Feldwert''. - Fix: Anzeigewert auf
rawTitle.trim() === '' ? '' : rawTitleumgestellt; gesendet wird weiterhin der rohe Tippwert (onChangetrimmt nicht selbst). - Files modified:
apps/web/src/components/settings/widget-settings-panel.tsx - Commit:
7f1ee3b
3. [Rule 1 - Bug] Plan-eigener Verify-Grep widersprach der eigenen Aktionsvorgabe
- Found during: Task 3, automatisierte Verifikation
- Issue: Die Aktionsvorgabe verlangte einen Kopfkommentar in
widget-registry.tsxmit dem Wortlaut „das Link-Widget wurde in quick-260916-iex entfernt“; der automatisierte Verify-Schritt desselben Tasks prüft! grep -qi "link" apps/web/src/components/dashboard/widget-registry.tsx ...— das Wort „Link“ im eigenen Kommentar hätte dieses Gate durchfallen lassen. - Fix: Kommentar ohne das Wort „Link“ umformuliert („der frühere Einzel-Schnellzugriffs-Typ“), inhaltlich identisch. Kein Rule-4-Fall — reine Wortwahl im Kommentar, keine architektonische Änderung.
- Files modified:
apps/web/src/components/dashboard/widget-registry.tsx - Commit:
39ea147
Known Stubs
Keine.
Threat Flags
Keine neue, im Plan nicht bereits erfasste sicherheitsrelevante Oberfläche gefunden. Alle sechs im <threat_model> benannten Maßnahmen (T-IEX-01 bis T-IEX-06) sind wie spezifiziert umgesetzt: rehypeSanitize bleibt aktiv, toggleTaskLine schreibt nur die Zielzeile, Favoriten-Titel läuft über React-Textknoten ohne dangerouslySetInnerHTML, Titel-Speichern ist entprellt, die Migration hat ein enges Prädikat und ist idempotent, unbekannte Widget-Typen crashen nicht.
Self-Check: PASSED
apps/web/src/components/dashboard/widgets/note-task-list.tsx— FOUNDapps/web/src/components/dashboard/widgets/note-task-list.test.tsx— FOUNDapps/web/src/components/dashboard/widgets/widget-wrapper.test.tsx— FOUNDapps/api/prisma/migrations/20260916120000_remove_link_widget/migration.sql— FOUNDapps/web/src/components/dashboard/widgets/link-widget.tsx— CONFIRMED DELETEDapps/web/src/components/dashboard/widgets/link-widget.test.tsx— CONFIRMED DELETED- Commit
684f063— FOUND ingit log - Commit
7f1ee3b— FOUND ingit log - Commit
39ea147— FOUND ingit log - Gesamtlauf: 52 Testdateien / 344 Tests grün, Web-Type-Check Exit 0, API-Type-Check Exit 0, API-Dashboard-Spec 31 Tests grün