docs(quick-260916-k2z): Plan — Kalender-Widget: mehrere Kalender am selben Tag als kleine Kreise je Kalender (max. 3, Rest grau gebuendelt)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 14:33:09 +02:00
parent f79c6bbe8c
commit 45b20a9fd4
@@ -0,0 +1,173 @@
---
phase: quick-260916-k2z
plan: 01
type: execute
wave: 1
depends_on: []
autonomous: true
requirements: [QUICK-260916-K2Z]
files_modified:
- apps/web/src/components/dashboard/widgets/calendar-month.ts
- apps/web/src/components/dashboard/widgets/calendar-month.test.ts
- apps/web/src/components/dashboard/widgets/calendar-widget.tsx
- apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
- CHANGELOG.md
estimate:
tokens: 22000
raw_tokens: 22000
tasks: 2
confidence: low
must_haves:
truths:
- "Kalender-Widget, Monatsraster: liegen an einem Tag Termine aus GENAU EINEM Kalender (eine `sourceId`), sieht der Tag aus wie heute — eine Plakette `data-testid=\"calendar-day-count\"` in Größe `h-[clamp(10px,3cqw,16px)]`, Inline-Hintergrund in der Kalenderfarbe mit `text-white`, ohne Farbe `bg-primary text-primary-foreground` (Tests 3, 3b, 3c bleiben unverändert grün)."
- "Liegen an einem Tag Termine aus ZWEI oder DREI Kalendern, stehen unten rechts in der Zelle zwei bzw. drei kleine Kreise nebeneinander (`h-[clamp(8px,2.4cqw,12px)]`, Schrift `text-[clamp(6px,1.5cqw,8px)]`), jeder in der Farbe seines Kalenders mit der Anzahl der Termine dieses Kalenders; Reihenfolge = erstes Auftreten in den nach Start sortierten Tagesterminen."
- "Liegen an einem Tag Termine aus MEHR ALS DREI Kalendern, zeigen die ersten zwei Kalender je einen kleinen farbigen Kreis und ein dritter grauer Kreis (`bg-muted-foreground text-background`, `data-testid=\"calendar-day-count-rest\"`) die SUMME der Termine aller übrigen Kalender."
- "Gruppierung erfolgt nach `sourceId`, NICHT nach Farbe (zwei Kalender mit gleicher Farbe bleiben zwei Kreise); die sichtbare Farbe eines Kreises ist die `color` des ersten Termins seiner Gruppe, Rückfall wie bisher Akzentfarbe."
- "Tooltip beim Überfahren bleibt unverändert (Zeilen mit Farbpunkt in Startreihenfolge)."
- "CHANGELOG.md, `## Unveröffentlicht` → `### Geändert`: der vorhandene Stichpunkt lautet jetzt „Kalender-Widget: Plakette am Tag in der Farbe des Kalenders; mehrere Kalender am selben Tag zeigen je einen kleinen Kreis“ — kein neuer Stichpunkt, kein Punkt am Ende, echte Umlaute."
- "Gates: `pnpm --filter @tessera/web type-check` Exit 0; `pnpm --filter @tessera/web exec vitest run` komplett grün (Basislinie 52 Dateien / 350 Tests → danach 52 Dateien / 354 Tests: +2 calendar-month, +2 calendar-widget); changelog.test.ts grün. KEIN `biome check`, kein Docker-Build, kein Deploy, kein Testserver, kein `git push`."
artifacts:
- "apps/web/src/components/dashboard/widgets/calendar-month.ts — neue Exporte `DaySourceGroup`, `DayBadge`, `CALENDAR_DAY_BADGE_MAX = 3`, `groupDayBySource(events)`, `buildDayBadges(events, max = CALENDAR_DAY_BADGE_MAX)`"
- "apps/web/src/components/dashboard/widgets/calendar-month.test.ts — neue Tests 8 (groupDayBySource) und 9 (buildDayBadges)"
- "apps/web/src/components/dashboard/widgets/calendar-widget.tsx — Plaketten-IIFE (Z. 246-264) ersetzt durch Wrapper `data-testid=\"calendar-day-badges\"` mit `buildDayBadges(day.events).map(...)`"
- "apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx — neue Tests 3d (zwei Kalender → zwei Kreise) und 3e (vier Kalender → zwei Kreise + grauer Rest)"
- "CHANGELOG.md — Stichpunkt Z. 16 erweitert"
key_links:
- "`groupEventsByDate` (calendar-month.ts Z. 110-121) sortiert jede Tagesgruppe bereits nach Start (quick-260916-jvj) — `groupDayBySource` darf NICHT selbst sortieren, sondern übernimmt die Reihenfolge von `day.events`, damit Kreis-Reihenfolge und Tooltip-Reihenfolge übereinstimmen."
- "Ein DOM-Element trägt nur EIN `data-testid`. Deshalb: farbige Kreise `calendar-day-count`, grauer Restkreis `calendar-day-count-rest`, Wrapper `calendar-day-badges` (Tests zählen Kinder des Wrappers für „drei Kreise“)."
- "Die Positionierung `absolute bottom-px right-px` wandert von der Plakette auf den Wrapper; Tests 3b/3c prüfen nur Text, Inline-Hintergrund und die Klassen `text-white`/`bg-primary`/`text-primary-foreground` — diese Klassen bleiben auf der Plakette selbst."
- "Grau-Wahl: `--muted-foreground` ist hell oklch 0.55, dunkel oklch 0.65 (globals.css Z. 71/98). `text-white` wäre im Dunkelmodus auf 0.65 schwach; `text-background` (hell = weiß, dunkel = dunkel) ist auf beiden Themes lesbar. `bg-muted` (0.96/0.30) wäre auf der Zelle `bg-muted/50` unsichtbar."
- "`toHaveStyle({ backgroundColor: '#c44040' })` normalisiert hex→rgb (Muster Test 3b); Rückfall-Fall über `style.backgroundColor === ''` prüfen (Muster Test 3c)."
---
<objective>
Folgeaufgabe zu 260916-jvj (Plakette in Kalenderfarbe): Liegen an einem Tag Termine aus mehreren Kalendern, zeigt die Plakette bisher nur die Farbe des frühesten Termins und die Gesamtzahl. Ab jetzt bekommt jeder Kalender einen eigenen kleinen Kreis in seiner Farbe mit seiner Anzahl (bis drei Kalender); ab dem vierten Kalender fassen zwei farbige Kreise plus ein grauer Restkreis mit der Summe die Übrigen zusammen. Ein einzelner Kalender sieht weiter aus wie heute.
Purpose: Gemischte Tage im Monatsraster auf einen Blick lesbar machen (User-Entscheidung „ja, mach so“).
Output: Zwei reine Hilfsfunktionen in calendar-month.ts mit Unit-Tests, Kreis-Rendering im Widget mit Komponententests, erweiterter CHANGELOG-Stichpunkt, zwei Commits.
</objective>
<execution_context>
@~/.claude/gsd-core/workflows/execute-plan.md
@~/.claude/gsd-core/templates/summary.md
</execution_context>
<context>
@/home/vicolab/projects/tessera-ctl/CLAUDE.md
@/home/vicolab/projects/tessera-ctl/apps/web/src/components/dashboard/widgets/calendar-month.ts
@/home/vicolab/projects/tessera-ctl/apps/web/src/components/dashboard/widgets/calendar-month.test.ts
@/home/vicolab/projects/tessera-ctl/apps/web/src/components/dashboard/widgets/calendar-widget.tsx
@/home/vicolab/projects/tessera-ctl/apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx
@/home/vicolab/projects/tessera-ctl/CHANGELOG.md
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Hilfsfunktionen groupDayBySource / buildDayBadges in calendar-month.ts mit Unit-Tests</name>
<files>apps/web/src/components/dashboard/widgets/calendar-month.ts, apps/web/src/components/dashboard/widgets/calendar-month.test.ts</files>
<read_first>
- apps/web/src/components/dashboard/widgets/calendar-month.ts (Kopfkommentar Z. 1-20, `groupEventsByDate` Z. 104-121, Export-Stil)
- apps/web/src/components/dashboard/widgets/calendar-month.test.ts (Fabrik `ev(id, start, end, extra)` Z. 19-29 setzt `sourceId: 's1'` als Vorgabe; `extra` überschreibt `sourceId`/`color`; Testnummerierung endet bei Test 7 + „Zusatz“)
- apps/web/src/lib/calendar-api.ts Z. 41-51 (`CalendarEvent`: `sourceId: string`, `color?: string`)
</read_first>
<behavior>
- Test 8 (groupDayBySource): (a) drei Termine, alle `s1` mit `color: '#c44040'` → genau eine Gruppe `{ sourceId: 's1', color: '#c44040', count: 3 }`. (b) Termine in der Reihenfolge s2, s1, s2 (Eingabereihenfolge wird NICHT umsortiert) → zwei Gruppen in der Reihenfolge s2 (count 2), s1 (count 1). (c) Termine ohne `color` → `color` der Gruppe ist `undefined` (nicht `''`, nicht `null`). (d) zwei Kalender mit derselben Farbe `#123456` → trotzdem zwei Gruppen (Gruppierung nach `sourceId`, nicht nach Farbe). (e) Farbe der Gruppe ist die `color` des ERSTEN Termins der Gruppe, auch wenn ein späterer Termin derselben Quelle eine andere Farbe trägt. (f) leeres Array → `[]`.
- Test 9 (buildDayBadges): (a) 1 Quelle → genau ein Eintrag `{ key: 's1', color, count, rest: false }`. (b) 2 Quellen → zwei Einträge, beide `rest: false`, Reihenfolge wie Gruppen. (c) 3 Quellen → drei Einträge, alle `rest: false`, KEIN Restkreis. (d) 4 Quellen s1(1 Termin), s2(2), s3(1), s4(3) → genau drei Einträge: [0] key `s1` count 1, [1] key `s2` count 2, [2] `{ key: '__rest__', color: undefined, count: 4, rest: true }` (1+3 = Summe von s3 und s4). (e) `buildDayBadges(vierQuellen, 2)` → zwei Einträge: s1 und Rest mit count 6 (2+1+3). (f) leeres Array → `[]`.
</behavior>
<action>
In `calendar-month.ts` nach `groupEventsByDate` (Z. 121) zwei reine Funktionen plus Typen/Konstante ergänzen; kein React, keine DOM-Zugriffe (Modulregel aus dem Kopfkommentar).
1. `export interface DaySourceGroup { sourceId: string; color?: string; count: number }` und `export function groupDayBySource(events: CalendarEvent[]): DaySourceGroup[]`: über `events` in gegebener Reihenfolge laufen, `Map<string, DaySourceGroup>` nach `event.sourceId`; beim ersten Auftreten Gruppe mit `color: event.color` (kann `undefined` sein) und `count: 0` anlegen, dann `count` erhöhen; Rückgabe `Array.from(map.values())` (Map-Einfügereihenfolge = erstes Auftreten). NICHT sortieren — die Reihenfolge kommt aus `groupEventsByDate` (dort bereits nach Start sortiert), damit Kreise und Tooltip dieselbe Reihenfolge haben.
2. `export const CALENDAR_DAY_BADGE_MAX = 3;`, `export interface DayBadge { key: string; color?: string; count: number; rest: boolean }` und `export function buildDayBadges(events: CalendarEvent[], max: number = CALENDAR_DAY_BADGE_MAX): DayBadge[]`: `groups = groupDayBySource(events)`. Wenn `groups.length <= max` → jede Gruppe zu `{ key: group.sourceId, color: group.color, count: group.count, rest: false }`. Sonst → die ersten `max - 1` Gruppen wie eben, danach genau ein Eintrag `{ key: '__rest__', color: undefined, count: Summe der count aller Gruppen ab Index max - 1, rest: true }`. Leere Eingabe ergibt `[]`.
3. Kopfkommentar der Datei (Z. 14-19) um einen Satz ergänzen: Kreise je Kalender werden nach `sourceId` gruppiert, Reihenfolge = erstes Auftreten in der start-sortierten Tagesgruppe, ab dem vierten Kalender grauer Restkreis mit Summe (quick-260916-k2z). Deutsche Kommentare, ASCII-Umlaute wie im Bestand (ue/ae/oe).
4. In `calendar-month.test.ts` die Importliste um `buildDayBadges` und `groupDayBySource` erweitern und nach Test 7 die Tests 8 und 9 gemäß `<behavior>` anlegen (deutsche Testnamen im Stil „Test 8: groupDayBySource …“). Termine mit der vorhandenen Fabrik `ev(...)` erzeugen und `sourceId`/`color` über den `extra`-Parameter setzen; alle Termine eines Tests auf denselben Tag legen, das ist für die Helfer aber unerheblich (sie kennen keine Tage).
Reihenfolge TDD: Tests zuerst schreiben, `vitest run calendar-month` rot sehen, dann Implementierung, grün.
</action>
<verify>
<automated>cd /home/vicolab/projects/tessera-ctl && pnpm --filter @tessera/web exec vitest run src/components/dashboard/widgets/calendar-month.test.ts && grep -c "export function groupDayBySource\|export function buildDayBadges\|export const CALENDAR_DAY_BADGE_MAX" apps/web/src/components/dashboard/widgets/calendar-month.ts | grep -qx 3</automated>
</verify>
<done>Tests 8 und 9 grün, alle bisherigen calendar-month-Tests weiter grün (Datei 11 Tests); `groupDayBySource` gruppiert nach `sourceId` in Reihenfolge des ersten Auftretens mit `color` des ersten Gruppentermins (undefined ohne Farbe); `buildDayBadges` liefert 1/2/3 Einträge ohne Rest bzw. bei mehr als `max` Gruppen `max - 1` Einträge plus einen `rest: true`-Eintrag mit summierter Anzahl. Commit: `feat(web): Kalender-Tag nach Kalender gruppieren, Kreise je Kalender berechnen (calendar-month)`.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Kreise je Kalender im Widget rendern, Komponententests, CHANGELOG, Gesamtlauf</name>
<files>apps/web/src/components/dashboard/widgets/calendar-widget.tsx, apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx, CHANGELOG.md</files>
<read_first>
- apps/web/src/components/dashboard/widgets/calendar-widget.tsx Z. 9-19 (Importliste aus `./calendar-month`), Z. 27-37 (Kopfkommentar, Satz zur Plakette), Z. 246-264 (Plaketten-IIFE: `badgeColor = day.events[0]?.color`, `badgeClass`, `data-testid="calendar-day-count"`)
- apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx Z. 44-54 (Fabrik `ev`, Vorgabe `sourceId: 's1'`), Z. 125-208 (Tests 3, 3b, 3c — Erwartungen an die Einzelplakette, die unverändert grün bleiben müssen)
- CHANGELOG.md Z. 13-16 (`### Geändert`, vorhandener Stichpunkt „Kalender-Widget: Plakette am Tag in der Farbe des Kalenders“)
</read_first>
<behavior>
- Test 3d (zwei Kalender am selben Tag): Mock-Termine am 2026-07-20 in dieser Array-Reihenfolge: s2 `#4060c4` 10:00, s2 `#4060c4` 14:00, s1 `#c44040` 09:00 (s1 steht im Array zuletzt, ist aber der früheste Termin). Erwartung in der Zelle `[data-date="2026-07-20"]`: `getAllByTestId('calendar-day-count')` hat Länge 2; [0] Text „1“, `toHaveStyle({ backgroundColor: '#c44040' })`; [1] Text „2“, `toHaveStyle({ backgroundColor: '#4060c4' })`; beide `toHaveClass('text-white')`, beide `not.toHaveClass('bg-primary')`, beide `toHaveClass('h-[clamp(8px,2.4cqw,12px)]')`; `queryByTestId('calendar-day-count-rest')` ist null; Wrapper `getByTestId('calendar-day-badges')` hat `childElementCount` 2.
- Test 3e (vier Kalender am selben Tag): Mock-Termine am 2026-07-21: s1 `#111111` 08:00 (1 Termin), s2 `#222222` 09:00 und 09:30 (2 Termine), s3 ohne Farbe 10:00 (1 Termin), s4 `#444444` 11:00, 12:00, 13:00 (3 Termine). Erwartung in `[data-date="2026-07-21"]`: Wrapper `calendar-day-badges` hat `childElementCount` 3; `getAllByTestId('calendar-day-count')` Länge 2 mit [0] „1“ + Hintergrund `#111111`, [1] „2“ + Hintergrund `#222222`; `getByTestId('calendar-day-count-rest')` hat Text „4“, `toHaveClass('bg-muted-foreground')`, `toHaveClass('text-background')`, `style.backgroundColor === ''`, `not.toHaveClass('text-white')`.
- Bestehende Tests 3, 3b, 3c laufen unverändert grün (Einzelplakette: eine `calendar-day-count`, Farbe/`text-white` bzw. `bg-primary text-primary-foreground`).
</behavior>
<action>
1. `calendar-widget.tsx`: Import `buildDayBadges` aus `./calendar-month` in die bestehende alphabetische Importliste (Z. 9-19) aufnehmen. Die IIFE Z. 246-264 komplett durch einen Wrapper ersetzen, der nur bei `hasEvents` gerendert wird: `<span data-testid="calendar-day-badges" className="absolute bottom-px right-px flex items-end gap-px">` mit `buildDayBadges(day.events).map((badge) => ...)`. Die Positionierung (`absolute bottom-px right-px`) liegt damit NUR auf dem Wrapper, nicht mehr auf den Kreisen. Vor dem `return` des Zellen-Callbacks `const badges = buildDayBadges(day.events);` und `const single = badges.length === 1;` berechnen (kein IIFE mehr).
Je Kreis ein `<span key={badge.key}>` mit:
- `data-testid`: `badge.rest ? 'calendar-day-count-rest' : 'calendar-day-count'` — ein Element kann nur EIN `data-testid` tragen, deshalb keine Doppelvergabe.
- Klassen aus einem Array, `.filter(Boolean).join(' ')` wie bisher: immer `flex items-center justify-center rounded-full px-0.5 font-semibold leading-none`; bei `single` zusätzlich `h-[clamp(10px,3cqw,16px)] min-w-[clamp(10px,3cqw,16px)] text-[clamp(7px,1.8cqw,10px)]` (heutige Größe), sonst `h-[clamp(8px,2.4cqw,12px)] min-w-[clamp(8px,2.4cqw,12px)] text-[clamp(6px,1.5cqw,8px)]`; Farbklassen: `badge.rest` → `bg-muted-foreground text-background`, sonst `badge.color` → `text-white`, sonst `bg-primary text-primary-foreground`.
- `style`: `badge.color && !badge.rest ? { backgroundColor: badge.color } : undefined`.
- Inhalt: `{badge.count}`.
Grau-Wahl bewusst `text-background` statt `text-white`: `--muted-foreground` ist im Dunkelmodus ein helles Grau (oklch 0.65), weiße Schrift wäre dort schwach; `text-background` ist hell weiß und dunkel dunkel, also auf beiden Themes lesbar (Begründung als kurzen deutschen Kommentar über den Wrapper schreiben, ASCII-Umlaute).
Kopfkommentar Z. 33-35 anpassen: Zaehl-Plakette in der Farbe des Kalenders; bei mehreren Kalendern am selben Tag je ein kleiner Kreis pro Kalender (max. drei, danach zwei plus grauer Restkreis mit Summe, Logik in `buildDayBadges`, quick-260916-k2z). Tooltip-Block (Z. 311-346) NICHT anfassen.
2. `calendar-widget.test.tsx`: nach Test 3c die Tests 3d und 3e gemäß `<behavior>` anlegen (Muster von 3b/3c: `mockFetchEvents.mockResolvedValue([...])`, `await import('./calendar-widget')`, `render` mit eigener `instanceId` `cal-3d`/`cal-3e`, `waitFor` auf „Juli 2026“, Zelle über `document.querySelector('[data-date="…"]')`, `within(...)`). `sourceId` und `color` je Termin über den `extra`-Parameter der Fabrik `ev` setzen. Reihenfolge-Prüfung in 3d ergibt sich daraus, dass s1 im Mock-Array zuletzt steht, aber als frühester Termin den ersten Kreis bekommt.
3. `CHANGELOG.md` Z. 16: den vorhandenen Stichpunkt ersetzen durch `- Kalender-Widget: Plakette am Tag in der Farbe des Kalenders; mehrere Kalender am selben Tag zeigen je einen kleinen Kreis` — KEINEN neuen Stichpunkt anlegen, kein Punkt am Ende, echte Umlaute, sonst nichts im CHANGELOG ändern.
4. Gesamtlauf: `pnpm --filter @tessera/web type-check` (Exit 0) und `pnpm --filter @tessera/web exec vitest run` (alle grün, erwartet 52 Dateien / 354 Tests; Basislinie 350 + 2 aus Task 1 + 2 aus diesem Task). Weicht die Zahl ab, Ursache benennen, nicht schönreden. Kein `biome check`, kein Docker-Build, kein Deploy, kein Testserver, kein `git push`.
</action>
<verify>
<automated>cd /home/vicolab/projects/tessera-ctl && pnpm --filter @tessera/web type-check && pnpm --filter @tessera/web exec vitest run && grep -qF "Kalender-Widget: Plakette am Tag in der Farbe des Kalenders; mehrere Kalender am selben Tag zeigen je einen kleinen Kreis" CHANGELOG.md && grep -q 'data-testid="calendar-day-count-rest"\|calendar-day-count-rest' apps/web/src/components/dashboard/widgets/calendar-widget.tsx && grep -q "buildDayBadges" apps/web/src/components/dashboard/widgets/calendar-widget.tsx</automated>
</verify>
<done>Einzelplakette sieht aus wie bisher (Tests 3, 3b, 3c unverändert grün); Tests 3d und 3e grün (zwei Kalender → zwei kleine Kreise in je eigener Farbe mit eigener Anzahl in Startreihenfolge; vier Kalender → zwei farbige Kreise plus grauer Restkreis `bg-muted-foreground text-background` mit Summe 4); Tooltip unverändert; CHANGELOG-Stichpunkt erweitert; `type-check` Exit 0; Vitest komplett grün mit 52 Dateien / 354 Tests. Commit: `feat(web): Kalender-Widget zeigt je Kalender einen kleinen Kreis am Tag; Changelog`.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| API → Widget | `CalendarEvent[]` vom Backend (`fetchEvents`), Felder `sourceId`/`color` werden im DOM als Schlüssel bzw. Inline-Stil verwendet |
## STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-K2Z-01 | Tampering | `style={{ backgroundColor: badge.color }}` | low | accept | Unverändert gegenüber 260916-jvj: React setzt Inline-Stile über die CSSOM-Eigenschaft, kein `dangerouslySetInnerHTML`; `color` stammt aus der eigenen Quellen-Tabelle (Admin/Anwender pflegt sie selbst) |
| T-K2Z-02 | Denial of Service | `groupDayBySource` | low | accept | Lineare Laufzeit über die Tagestermine, Eingabe ist bereits auf das 42-Tage-Fenster begrenzt |
| T-K2Z-SC | Tampering | npm-Installs | low | accept | Keine neuen Pakete in diesem Auftrag |
</threat_model>
<verification>
- `pnpm --filter @tessera/web type-check` Exit 0
- `pnpm --filter @tessera/web exec vitest run` 52 Dateien / 354 Tests grün (calendar-month 11, calendar-widget 15, changelog.test.ts grün)
- Einzelplakette: Tests 3/3b/3c ohne Änderung grün
- Zwei Commits (Task 1: Helfer + Unit-Tests; Task 2: Widget + Komponententests + CHANGELOG), kein Push
</verification>
<success_criteria>
- Tage mit einem Kalender: unverändert eine Plakette in Kalenderfarbe (oder Akzent)
- Tage mit zwei/drei Kalendern: zwei/drei kleine Kreise, je Kalenderfarbe und eigene Anzahl, Reihenfolge nach frühestem Termin
- Tage mit vier oder mehr Kalendern: zwei farbige Kreise plus grauer Restkreis mit Summe der übrigen
- Gruppierung nach `sourceId`, nicht nach Farbe
- CHANGELOG-Stichpunkt erweitert, alle Gates grün
</success_criteria>
<output>
Create `.planning/quick/260916-k2z-kalender-widget-mehrere-kalender-am-selb/260916-k2z-SUMMARY.md` when done
</output>