---
id: w8/m1/t005
title: Month-to-date aggregation in internal/store + fake-clock unit tests
worker: worker8
status: done
estimate: 30m
depends_on: [w8/m1/t001]
---

## Objective

Give the store the read side m2 will consume: a month-to-date aggregation — per workspace, broken down by service and kind (and tier for `instance_seconds`) — computed in SQL over `usage_hourly`, with the month boundary decided by an injected clock so tests don't depend on wall time.

## Context

- `lego/backend/internal/store/` is the home (alongside `plans.go`, `workspaces.go`); `fake_test.go` + `store_pg_test.go` show the existing dual (fake + real-Postgres) test pattern.
- "Month to date" = from the first instant of the current calendar month (UTC) to now — Render's billing-period framing; take `now` as a parameter rather than calling `time.Now()` in the query layer.
- Return shape: rows of (service_id, kind, tier, total quantity) for one workspace — m2's core verb shapes it for adapters; keep the store layer dumb.

## Steps

1. Add `UsageMonthToDate(ctx, workspaceID, now)` to the store interface + Postgres implementation (single `GROUP BY` query).
2. Extend the store fake for it.
3. Unit tests: rows straddling the month boundary count only in their own month; empty month returns empty, not error.

## Files

- `lego/backend/internal/store/` (new `usage.go` + fake + tests)

## Acceptance criteria

- [ ] A row at 23:00 on the last day of June and one at 01:00 on July 1 aggregate into different months (fake-clock test).
- [ ] Aggregates sum across hourly windows per (service, kind, tier) correctly against real Postgres (`store_pg_test.go` path).

## Out of scope

- The core verb / authz / adapters (m2).
