feat/ui-impact
needs attentionviewing older commit027e5ea · incrementalpre-PRreviewed 2026-07-24 20:04 UTC4H · 9M · 8L · 3I- Purpose
- feat/ui-impact builds the Energía dashboard UI for Grupo Axo — bill analysis, anomaly detection, portfolio comparisons, demand/ESG views, findings system, and payment reconciliation.
- Goal
- Add MXN (peso spend) as a selectable unit alongside kWh in the Comparativo page using the same DiD cohort model.
- Sub-goals
- SG-1: Add mxn field to MonthPoint and Tuple; backfill 23 stores with real bill totals from Supabase
- SG-2: Make analyzeStore unit-aware (Unit='kwh'|'mxn'); has() guard treats mxn=0 as missing
- SG-3: Unidad toggle UI; all formatters, charts, KPIs, table columns, CSV exports branch on unit
- What
- anomaly.ts: Unit type + unit param on analyzeStore. realConsumption.ts: mxn field on MonthPoint with Supabase bill totals for 23 stores. page.tsx: Unidad toggle and all views unit-aware.
- Why
- Grupo Axo needs peso spend comparisons for budget/finance reporting alignment.
- Areas
- apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts+25−8apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/realConsumption.ts+30−22apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx+90−55
- Blast
- 3 files, ~+145/-85 in this increment; branch total: 69 files +25547/-4 across energia dashboard, utility/finding domain, platform API.
Findings · 20
correctness3
BASE_WINDOW guard weakened — can proceed with < 7 total series entries
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:77
Old guard: store.series.length. New guard: filter(has).length. Correct intent but relaxation is undocumented.
Sparse MXN cohort produces non-contiguous baseline months
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:100
Peers with mxn=0 excluded from cohortValueAt; BASE_WINDOW points may span non-contiguous months.
points filtered by has — index-based consumers may misalign
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:110
security1
?tienda= URL param safe — bounded to hardcoded STORES array
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:153
conventions6
excessKwhDia field is unit-dependent but named kWh
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:49
AnomalyResult.excessKwhDia is $/día when metric='mxn'. Rename to excessPerDay or thread Unit into AnomalyResult.
Repeated 'Gasto'/'Consumo' ternaries — 6 sites exceed abstraction threshold
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:491
Project rule: three similar lines > premature abstraction. Extract noun(u) helper.
JSDoc comments on formatters describe WHAT, not WHY
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:44
fmtNorm, fmtCfe, rawVal, colRaw JSDoc restate the signature. Remove or replace with WHY.
axisLabel double ternary — prefer Record<Unit, Record<Metric, string>>
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:49
t17 mxn=18090 with exact=false contradicts 'dated bills' doc comment
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/realConsumption.ts:154
kwhDia still exported — verify no external consumers before removing
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/realConsumption.ts:82
tests4
analyzeStore MXN path has zero test coverage
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:77
No __tests__/ dir. Missing: mxn=0→null; <BASE_WINDOW+1 mxn>0→null; valid MXN result; cohort sparsity divergence from kWh mode.
MonthPoint Tuple positional slot added — no regression test for S() mapping
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/realConsumption.ts:45
kwh and mxn are both number — a positional swap passes TS but silently misaps values.
valOf divides by p.dias — no zero guard, no test
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:85
dias is always ≥1 in practice but NaN would silently propagate into DiD KPIs if dias=0 reached valOf.
normRowsFor/portfolioRows MXN column keys untested
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:70
A mismatch in colRaw/colDia would silently produce wrong CSV headers.
improvement6
kwhDia, sumKwh, meanKwhDia are dead exports
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/realConsumption.ts:82
anomaly.ts removed its kwhDia import; sumKwh and meanKwhDia have no consumers. Delete or un-export.
rawVal/hasVal in page.tsx duplicate num/has closures in anomaly.ts
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:51
Identical logic in two files. Export a standalone pointValue(p, u) from anomaly.ts.
Table cell renderer is three-level nested ternary
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:564
Extract to formatCell(h, v, unit) for testability and readability.
portfolioRows recomputed on export click — rows memo holds this data
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:532
portfolioStats and portfolioDiD both iterate all STORES separately
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/page.tsx:225
Unit type conceptually belongs in realConsumption.ts alongside MonthPoint
apps/platform/src/app/[locale]/(dashboard)/energia/comparativo/_lib/anomaly.ts:32
History · 15 commits
- 96ca7d7needs attentionincremental0H · 9M · 12L2026-07-25 16:40
- 25516f7needs attentionincremental5H · 7M · 8L2026-07-25 03:29
- a7f8d64needs attentionincremental0H · 4M · 5L2026-07-25 01:56
- 7fc4ef0needs attentionincremental2H · 6M · 8L2026-07-24 21:04
- 027e5eaneeds attentionincremental4H · 9M · 8L2026-07-24 20:04current
- 95a101eneeds attentionincremental3H · 6M · 5L2026-07-24 16:09
- 5d0d186needs attentionincremental1H · 3M · 5L2026-07-24 15:36
- c3c5121needs attentionincremental2H · 1M · 5L2026-07-24 15:17
- ded4e61needs attentionincremental2H · 3M · 9L2026-07-24 14:22
- 312a1f4needs attentionincremental1H · 4M · 4L2026-07-24 04:01
- b48af56needs attentionincremental1H · 6M · 6L2026-07-24 03:14
- 6d07cc8needs attentionincremental2H · 4M · 5L2026-07-24 00:50
- 261b55eneeds attentionincremental5H · 11M · 6L2026-07-24 00:38
- 5b8a252needs attentionincremental3H · 6M · 9L2026-07-24 00:19
- f29cc5bneeds attentionfull9H · 17M · 11L2026-07-23 23:07