5313fbc019
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
21 KiB
21 KiB
phase, plan, type, wave, depends_on, autonomous, requirements, files_modified, estimate, must_haves
| phase | plan | type | wave | depends_on | autonomous | requirements | files_modified | estimate | must_haves | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260916-jvj | 01 | execute | 1 | true |
|
|
|
|
Purpose: Sichtbare Bedienfehler vor der nächsten Beta beseitigen; Kalenderfarben im Widget durchgängig nutzen. Output: Sortierung in calendar-month.ts, Plakette/Tooltip-Punkt in calendar-widget.tsx, CSS-Block in globals.css, drei neue Tests, zwei CHANGELOG-Stichpunkte, zwei Commits.
<execution_context>
@/.claude/gsd-core/workflows/execute-plan.md
@/.claude/gsd-core/templates/summary.md
</execution_context>
Live gemessen am 2026-09-16 (Planer):
- calendar-month.ts:
groupEventsByDateZ. 106-114 sammelt per[...existingEvents, event]in API-Reihenfolge, KEINE Sortierung (Vorgabe „bereits sortiert“ trifft nicht zu).selectUpcomingEventsZ. 179-186 zeigt den Sortier-Komparator, der zu übernehmen ist:new Date(a.start).getTime() - new Date(b.start).getTime(). Kopfkommentar Z. 14-17 beschreibt die Starttag-Regel. - calendar-month.test.ts: Test 2 Z. 50-64 nutzt einen
ev(id, start, end)-Helfer undgrouped.get('2026-07-20'); dort Test 2b anhängen. - calendar-widget.tsx: Plakette Z. 244-251 (
data-testid="calendar-day-count", Klassen enthaltenrounded-full bg-primary px-0.5 ... text-primary-foreground); Listen-Farbpunkt Z. 272-277 (data-testid="event-color-dot",className="mt-1 h-2 w-2 shrink-0 rounded-full",style={{ backgroundColor: event.color || 'var(--muted-foreground)' }},aria-hidden="true"); Tooltip-Zeilen Z. 314-321 (<div key={event.id} className="flex gap-2">, dann Uhrzeit-Spanshrink-0 tabular-nums text-muted-foreground, dann Titel-Spanmin-w-0 break-words).cellClassZ. 220-227 zeigt das Muster Array →.filter(Boolean).join(' ')für zusammengesetzte Klassen. Doc-Kommentar Z. 27-55 erwähnt „Zaehl-Plakette“ (Z. 33). - calendar-widget.test.tsx: 10 Tests;
ev(id, start, end, extra?)Z. 44-54 nimmtPartial<CalendarEvent>(also{ color: '#c44040' });within,fireEventimportiert; Test 3 Z. 121-141 (Plakette zählt), Test 4 Z. 143-166 (Tooltip perfireEvent.mouseEnterauf[data-date="2026-07-20"], danachscreen.getByTestId('calendar-day-tooltip')). Termintitel stehen auch in „Nächste Termine“ im DOM — Tooltip-Abfragen IMMER mitwithin(tooltip). - CalendarEvent (apps/web/src/lib/calendar-api.ts Z. 41-51):
color?: string. - SOURCE_COLOR_PALETTE (calendar-source-form.tsx Z. 12-21): #c44040, #40a060, #4060c4, #8040c4, #c49040, #409090, #c44080, #808080 — alle mittlere Töne, weiße Schrift lesbar.
- globals.css: 127 Zeilen,
@import "tailwindcss"Z. 1,@custom-variant darkZ. 22,@theme inlineZ. 24-50, Tokens,bodyZ. 115-119,.app-shell-main-Media-Block Z. 121-126 (Dateiende). Kein@layer, kein.wmde-markdown. - markdown.css (node_modules/.pnpm/@uiw+react-markdown-preview@5.2.1_*/node_modules/@uiw/react-markdown-preview/markdown.css): Z. 477-481
.wmde-markdown ul, .wmde-markdown ol { margin 0; padding-left: 2em }ohne list-style; Z. 483-485ol ol, ul ol → lower-roman; Z. 636-638.wmde-markdown div > ol:not([type]) → decimal(nur ol, ul hat nichts); Z. 878-880.wmde-markdown .task-list-item { list-style-type: none }; Z. 893-895.wmde-markdown .contains-task-list input[type='checkbox'](Klassennamen bestätigt:contains-task-listam ul,task-list-itemam li). - CHANGELOG.md
## Unveröffentlicht:### Geänderthat einen Punkt (Kalenderquellen Adressfeld),### Behobenhat zwei (Notiz-Widget Listen abhaken, Textbereich Hell/Dunkel). Neue Punkte jeweils als letzte Zeile des Abschnitts anhängen. - Testbasis:
pnpm --filter @tessera/web exec vitest run= 52 Dateien / 347 Tests; Skriptetest/type-checkin apps/web/package.json vorhanden.
1. calendar-month.ts, `groupEventsByDate` (Z. 106-114): nach dem Sammeln jede Tagesgruppe nach Start aufsteigend sortieren — Komparator wie in `selectUpcomingEvents` (`new Date(a.start).getTime() - new Date(b.start).getTime()`); `Array.prototype.sort` ist stabil, Termine mit gleichem Start behalten die API-Reihenfolge. Doc-Kommentar der Funktion und Kopfkommentar (Starttag-Regel Z. 14-17) um einen Satz ergänzen: Gruppen sind nach Start sortiert, damit Plakettenfarbe (erster Termin) und Tooltip-Reihenfolge deterministisch sind (quick-260916-jvj).
2. calendar-widget.tsx, Plakette (Z. 244-251): vor dem `return` der Zelle `const badgeColor = day.events[0]?.color;` bestimmen (Gruppe ist jetzt sortiert, [0] = frühester Termin). Klassenstring nach dem `cellClass`-Muster zusammensetzen: unveränderter Basisteil (`absolute bottom-px right-px flex h-[clamp(10px,3cqw,16px)] min-w-[clamp(10px,3cqw,16px)] items-center justify-center rounded-full px-0.5 text-[clamp(7px,1.8cqw,10px)] font-semibold leading-none`) plus bei `badgeColor` `text-white`, sonst `bg-primary text-primary-foreground`. `style={badgeColor ? { backgroundColor: badgeColor } : undefined}` — ohne Farbe darf KEIN style-Attribut entstehen (Test 3c prüft `''`). `data-testid` bleibt `calendar-day-count`.
3. calendar-widget.tsx, Tooltip-Zeile (Z. 314-321): als erstes Kind der `flex gap-2`-Zeile einen Span einfügen mit `data-testid="tooltip-color-dot"`, `className="mt-1 h-2 w-2 shrink-0 rounded-full"`, `style={{ backgroundColor: event.color || 'var(--muted-foreground)' }}`, `aria-hidden="true"` — exakt dieselbe Rückfallregel wie der Listen-Punkt Z. 272-277 (`mt-1` zentriert den 8-px-Punkt in der 16-px-Zeile von `text-xs`). Uhrzeit- und Titel-Span unverändert dahinter.
4. Doc-Kommentar calendar-widget.tsx Z. 33 („Zaehl-Plakette an Tagen mit Terminen“) ergänzen: Plakette in der Farbe des Kalenders des fruehesten Termins, sonst Akzentfarbe; Tooltip-Zeilen mit Farbpunkt (quick-260916-jvj). ASCII-Umlaute wie im umgebenden Kommentar (ae/oe/ue), das ist dort Konvention.
Keine weiteren Änderungen: Liste „Nächste Termine“, Portal, Klemmung, Ladefenster bleiben unangetastet. Commit: `feat(web): Kalender-Plakette in der Farbe des Kalenders, Farbpunkt je Tooltip-Zeile`.
cd /home/vicolab/projects/tessera-ctl && grep -q "tooltip-color-dot" apps/web/src/components/dashboard/widgets/calendar-widget.tsx && grep -q "day.events\[0\]?.color" apps/web/src/components/dashboard/widgets/calendar-widget.tsx && grep -q "Test 3b" apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx && grep -q "Test 3c" apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx && grep -q "Test 2b" apps/web/src/components/dashboard/widgets/calendar-month.test.ts && pnpm --filter @tessera/web exec vitest run src/components/dashboard/widgets/calendar-month.test.ts src/components/dashboard/widgets/calendar-widget.test.tsx && pnpm --filter @tessera/web type-check
calendar-month.test.ts und calendar-widget.test.tsx komplett grün (10 → 12 Widget-Tests, +1 Month-Test); Plakette bekommt bei `color` Inline-Hintergrund + `text-white`, ohne `color` unverändert `bg-primary text-primary-foreground` ohne style-Attribut; Tooltip-Zeilen mit Farbpunkt in Startzeit-Reihenfolge; tsc 0 Fehler.
Task 2: Aufzählungspunkte in Markdown-Ansichten (globals.css), CHANGELOG, voller Testlauf
apps/web/src/app/globals.css, CHANGELOG.md
1. globals.css: ans Dateiende (nach dem `.app-shell-main`-Media-Block Z. 121-126) einen Block anhängen, eingeleitet von einem kurzen deutschen Kommentar (Muster der bestehenden Kommentare, ASCII-Umlaute wie dort): Tailwind-Preflight setzt `ul, ol { list-style: none }` in `@layer base`, markdown.css von @uiw/react-markdown-preview stellt es nicht wieder her — deshalb fehlten auf „Was ist neu“ und in der Notiz-Vorschau die Punkte; ungeschichtete Regel hier schlägt die Layer-Regel; Aufgabenlisten bleiben ohne Punkt (quick-260916-jvj). Danach genau diese vier Regeln, je eine Zeile: `.wmde-markdown ul { list-style: disc; }` — `.wmde-markdown ul ul { list-style: circle; }` — `.wmde-markdown ol { list-style: decimal; }` — `.wmde-markdown ul.contains-task-list, .wmde-markdown li.task-list-item { list-style: none; }`. Kein `@layer`, kein `!important`, keine weiteren Selektoren. Klassennamen `contains-task-list`/`task-list-item` sind gegen markdown.css Z. 878/894 bestätigt.
2. CHANGELOG.md, Abschnitt `## Unveröffentlicht`: unter `### Geändert` als letzte Zeile `- Kalender-Widget: Plakette am Tag in der Farbe des Kalenders` anhängen; unter `### Behoben` als letzte Zeile `- „Was ist neu“ und Notiz-Ansicht: Aufzählungspunkte wieder sichtbar` anhängen. Typografische Anführungszeichen „…“ wie im Bestand, kein Punkt am Zeilenende, Überschriften zeichengenau unverändert, kein CRLF.
3. Volle Gates laufen lassen (siehe verify). Kein `biome check` (bekannter Konfigurationsfehler, biome.json nicht anfassen), kein Docker-Build, kein Deploy, kein Testserver, kein `git push`. Commit: `fix(web): Aufzählungspunkte in Markdown-Ansichten (Was ist neu, Notiz) wieder sichtbar; Changelog`.
In der SUMMARY vermerken: Plakettenfarbe = frühester Termin des Tages (bei mehreren Quellen an einem Tag keine Mischung, bewusst einfach); `groupEventsByDate` sortiert jetzt (war vorher API-Reihenfolge); CSS-Block ist bewusst ungeschichtet, weil Preflight in `@layer base` liegt.
cd /home/vicolab/projects/tessera-ctl && grep -q '^\.wmde-markdown ul { list-style: disc; }' apps/web/src/app/globals.css && grep -q '^\.wmde-markdown ul ul { list-style: circle; }' apps/web/src/app/globals.css && grep -q '^\.wmde-markdown ol { list-style: decimal; }' apps/web/src/app/globals.css && grep -q '^\.wmde-markdown ul\.contains-task-list, \.wmde-markdown li\.task-list-item { list-style: none; }' apps/web/src/app/globals.css && grep -q 'quick-260916-jvj' apps/web/src/app/globals.css && grep -qx -- '- Kalender-Widget: Plakette am Tag in der Farbe des Kalenders' CHANGELOG.md && grep -qx -- '- „Was ist neu“ und Notiz-Ansicht: Aufzählungspunkte wieder sichtbar' CHANGELOG.md && grep -qx '## Unveröffentlicht' CHANGELOG.md && ! grep -q $'\r' CHANGELOG.md && pnpm --filter @tessera/web type-check && pnpm --filter @tessera/web exec vitest run
globals.css enthält die vier Listen-Regeln mit Kommentar am Dateiende; CHANGELOG.md hat beide neuen Stichpunkte in den richtigen Abschnitten; `type-check` Exit 0; `vitest run` komplett grün mit 52 Dateien / 350 Tests (Umlaut-Wächter 3/3, changelog.test.ts grün eingeschlossen).
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| API → Browser (event.color) | Farbwert stammt aus der gespeicherten Kalenderquelle (Formular-Palette, im Backend als String abgelegt) und landet als Inline-backgroundColor im DOM |
| Markdown → DOM | Bereits durch rehypeSanitize abgedeckt (260916-dcz/iex); dieser Auftrag ändert nur CSS, keine Sanitizer-Konfiguration |
STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|---|---|---|---|---|---|
| T-JVJ-01 | Tampering | calendar-widget.tsx Inline-Stil aus event.color |
low | accept | React setzt style.backgroundColor als Eigenschaftswert (kein HTML, kein url()-Kontext); ungültige Werte verwirft der Browser. Identische Nutzung besteht bereits beim Listen-Farbpunkt (Z. 275). Keine neue Angriffsfläche. |
| T-JVJ-02 | Information Disclosure | globals.css .wmde-markdown-Regeln |
low | accept | Reines Styling ohne Datenfluss; Selektoren wirken nur innerhalb des Markdown-Containers. |
| T-JVJ-SC | Tampering | npm/pnpm installs | low | accept | Keine Paketinstallation in diesem Auftrag (nur Quell- und CSS-Änderungen). |
| </threat_model> |
<success_criteria>
- Plakette im Monatsraster zeigt die Kalenderfarbe des frühesten Termins des Tages (weiße Schrift), ohne Farbe unverändert Akzentfarbe
- Tooltip-Zeilen mit Farbpunkt (gleiche Rückfallregel wie die Liste), Reihenfolge nach Startzeit
- „Was ist neu“ und Notiz-Vorschau zeigen Aufzählungspunkte; Aufgabenlisten mit Kästchen bleiben ohne Punkt
- CHANGELOG.md um zwei kurze Stichpunkte ergänzt
- Alle Gates grün, zwei Commits, kein Push </success_criteria>