# Phase 4: Heatmap Interaction - Context
**Gathered:** 2026-04-08
**Status:** Ready for planning
## Phase Boundary
Add click-through navigation from heatmap day cells to Kimai's timesheet view, and a project filter dropdown that re-fetches and re-renders the heatmap without page reload.
## Implementation Decisions
### Click Navigation
- Clicking any day cell navigates to Kimai's timesheet list filtered by that date (`/en/timesheet/?daterange=YYYY-MM-DD`)
- Empty cells (no data) are clickable too — user may want to add time for that day
- Pointer cursor + subtle hover highlight (opacity change) on all cells as click affordance
- If a project filter is active, preserve it in the timesheet URL (`&projects[]=N`)
### Project Filter
- Filter dropdown positioned next to the heatmap SVG (right side), using the spare horizontal space since the heatmap isn't full card width
- Projects only — no activity filter (API already supports `?project=N`)
- Default state: "All Projects" selected, no filter applied
- Selecting a project fetches from API with `?project=N`, re-renders heatmap in place; color scale recalculates for filtered data
### Testing Strategy
- Vitest tests for click navigation: verify click handler sets `window.location.href` to correct Kimai URL pattern
- Vitest tests for filter dropdown: verify dropdown renders, selecting fires fetch with correct query param, heatmap re-renders with new data
- Fixture data matching existing HeatmapData shape from prior tests
### Claude's Discretion
- Exact Kimai timesheet URL format (verify against Kimai source)
- Filter dropdown styling details (should use Tabler/Kimai form classes)
- How to populate the project list (new API endpoint or extend existing one)
## Existing Code Insights
### Reusable Assets
- `renderHeatmap(container, data, config)` in `assets/src/heatmap.ts` — main rendering function, can be called again with new data for filter updates
- `HeatmapData` / `DayEntry` types in `assets/src/types.ts` — shared data shape
- `HeatmapController::data()` already accepts `?project` query parameter
- `HeatmapService::getDailyAggregation()` already supports `?int $projectId` parameter
### Established Patterns
- d3 selections for SVG rendering with data binding
- Tooltip positioning via fixed-position div (mouseenter/mouseleave)
- IIFE format with `KimaiHeatmap` global, `kimai.initialized` event for deferred init
- Tabler CSS variables for theming (`--tblr-bg-surface`, `--tblr-body-color`, etc.)
### Integration Points
- `data-url` attribute on container div passes API endpoint to JS
- Widget template at `Resources/views/widget/heatmap.html.twig` with Tabler card embed
- CSS at `Resources/public/heatmap.css`
- Route `heatmap_data` resolves to `/heatmap/data`
## Specific Ideas
- User wants filter next to the heatmap (not in header or below) since the SVG doesn't fill the full card width — use the horizontal space to the right
## Deferred Ideas
None — discussion stayed within phase scope.