# Phase 5: Polish - Context **Gathered:** 2026-04-08 **Status:** Ready for planning ## Phase Boundary Add streak indicator, summary statistics row, and weekend visual distinction to the heatmap widget. Also integrate user's start-of-week preference from Kimai. ## Implementation Decisions ### Streak Indicator - Count consecutive calendar days (including weekends) with tracked time, counting backward from today - Display as a simple text line above or below the heatmap: "Current streak: N days" - If today has no entries yet, check from yesterday backward (user may still be tracking today) - Computed client-side from the fetched heatmap data — no new API endpoint ### Summary Stats Row - Rendered below the heatmap SVG, inside the same Tabler card - Three stats: Total Hours, Avg Hours/Day (days with tracked time only), Busiest Day - Computed client-side from the fetched heatmap data array - Styled as inline stat items using Tabler's existing typography classes - "Busiest Day" shows date + hours (e.g., "Mar 15 — 8.5h") ### Weekend Styling - Weekend cells (Saturday/Sunday) get reduced opacity (0.85) compared to weekday cells - Applied via CSS class `.heatmap-weekend` with opacity rule - Empty weekend cells also get the distinction so the grid pattern is visible - No border changes — keep existing rounded rect style ### Start-of-Week Preference - Read user's `first_weekday` from Kimai (exposed via User entity or system config) - Pass as `data-week-start` attribute on the container div (0=Sunday, 1=Monday, etc.) - Use in d3 grid layout to set which day is row 0 - Adjust day-of-week labels to match - Default to Monday if not available (current behavior) ### Testing Strategy - Vitest tests for streak calculation (consecutive days, gaps, weekend inclusion, today edge case) - Vitest tests for summary stats computation (totals, averages, busiest day) - Vitest tests for weekend cell class assignment - CSS changes don't need unit tests — visual verification ### Claude's Discretion - Exact Tabler CSS classes for the stats row layout - How to extract `first_weekday` from Kimai's User entity (check source) - Whether streak resets on weekends or not (decision: it does — every calendar day counts) - d3 time interval function for configurable week start (d3.timeSunday vs d3.timeMonday etc.) ## Existing Code Insights ### Reusable Assets - `renderHeatmap(container, data, config)` — main render, needs extension for weekend classes and stats - `init()` — fetches data and calls render, will also compute streak/stats after data arrives - `HeatmapData.days` array — source for all client-side computations - `generateCells()` helper — can add weekend detection here - `HeatmapWidget::getData()` — can add `weekStart` to template data ### Established Patterns - d3 selections for SVG element class assignment - Data attributes on container div for passing server config to JS - Tabler card structure with widget template embedding - CSS classes added to cells based on data state (`.heatmap-empty`) ### Integration Points - `heatmap.html.twig` — add `data-week-start` attribute, stats container div - `heatmap.css` — add `.heatmap-weekend`, `.heatmap-stats` styles - `heatmap.ts` — extend `renderHeatmap` for weekends, add streak/stats functions - `HeatmapWidget.php` — pass user's week start preference to template ## Specific Ideas - Memory note: heatmap must respect Kimai user's start-of-week preference (not hardcoded Monday) - Stats should feel lightweight — not a full stats panel, just quick context below the heatmap ## Deferred Ideas None — all three requirements (POLI-01, POLI-02, POLI-03) plus start-of-week fit within polish scope.