Part of the AMI interval cluster (#76/#77). The dashboard's global RangeControl is month-resolution only (All / YTD / 12mo / 24mo / 36mo / custom-month, YYYYMM). 15-min electric data now exists, but there is no way to aim at it — you can't say "show me Tuesday June 10" or open one day at full 96-interval resolution.
Problem
RangeControl / lib/range.ts speak only ym (YYYYMM); interval widgets receive a full-month [from, to] and the history chart just dumps a downsampled wide span.
- No day-level drilldown: no way to click into / select a single day and see its raw 15-min profile, nor to step day-by-day or week-by-week.
- For exploring intra-day structure (the whole point of 15-min data) the current UX is unusable.
Proposal
- Add sub-month navigation for the interval views: a day/week picker (and prev/next stepper) that resolves to a precise
[from,to] day-span, independent of the month-grained global range. Keep lib/range.ts pure; add interval-range resolution as pure, hand-calc-tested helpers (don't compute in components).
- Add a single-day drilldown view: select a day (e.g. click a point in Usage history / a heatmap cell, or pick a date) → render that day's full 15-min (electric) / hourly (gas) profile. Reuse
/api/interval (from/to already support a day span) and the existing self-fetching widget pattern; respect gaps as line breaks (never fabricated zeros, standards §1).
- Decide and document how the per-widget day selection relates to the global
RangeControl (scoped override vs. global change) — keep it discoverable in the default view.
Acceptance criteria
Pointers
components/RangeControl.tsx, lib/range.ts (month-grained today), components/Dashboard.tsx (range → ISO from/to threading), app/api/interval/route.ts (already accepts from/to day bounds), components/widgets/IntervalHistory.tsx + IntervalLoadShape.tsx (self-fetching pattern), lib/widgets/registry.tsx (isPlaced gating).
Part of the AMI interval cluster (#76/#77). The dashboard's global
RangeControlis month-resolution only (All / YTD / 12mo / 24mo / 36mo / custom-month,YYYYMM). 15-min electric data now exists, but there is no way to aim at it — you can't say "show me Tuesday June 10" or open one day at full 96-interval resolution.Problem
RangeControl/lib/range.tsspeak onlyym(YYYYMM); interval widgets receive a full-month[from, to]and the history chart just dumps a downsampled wide span.Proposal
[from,to]day-span, independent of the month-grained global range. Keeplib/range.tspure; add interval-range resolution as pure, hand-calc-tested helpers (don't compute in components)./api/interval(from/toalready support a day span) and the existing self-fetching widget pattern; respect gaps as line breaks (never fabricated zeros, standards §1).RangeControl(scoped override vs. global change) — keep it discoverable in the default view.Acceptance criteria
/api/verifystays green (UI-only change); Docker test stage green.Pointers
components/RangeControl.tsx,lib/range.ts(month-grained today),components/Dashboard.tsx(range → ISOfrom/tothreading),app/api/interval/route.ts(already acceptsfrom/today bounds),components/widgets/IntervalHistory.tsx+IntervalLoadShape.tsx(self-fetching pattern),lib/widgets/registry.tsx(isPlacedgating).