mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
A category with no invoice lines in a period simply had no row, so a category going quiet was indistinguishable from one that never existed, and filtering to a category that was never billed returned an empty table. The query is now three levels. The aggregate groups as before. A grid crosses every period that saw revenue with every category the filter allows, and LEFT JOINs the aggregate onto it so a missing combination lands at zero. The wrapper does the display rounding and the labelling. Two things had to move for that to be correct: - The lag() window is now in the wrapper. A window function only sees the rows its own query level produces, so left on the aggregate it would skip a category's silent periods — billed in January and March, it would read March's prior as January and report flat growth. - The category filter is off the aggregate and enforced by the grid's category list. Filtering the aggregate too would make the period axis depend on the selection, which is what left the table empty when the selected category had never been billed. Periods come from the data, not generate_series over the date filter: a twelve-month range over one billed month would otherwise publish eleven months of pure zeros, and daily granularity would multiply that by thirty. The Categories KPI is now "Categories with revenue" — a bare count of live categories reads as a contradiction next to a table listing all fourteen. EXPLAIN-validated against the dev database across seven filter shapes, including the empty-array case (hence unnest(ARRAY[...]) over VALUES, which is a syntax error when empty). Claude-Session: https://claude.ai/code/session_01LoY3hNWqcaAC1pYmGPN7jr