Skip to content

fix(usage): compute credit balance from all-time usage, not a 30-day window#44

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
AliaksandrNazaruk:fix/usage-balance-alltime
Jul 2, 2026
Merged

fix(usage): compute credit balance from all-time usage, not a 30-day window#44
ralyodio merged 1 commit into
profullstack:masterfrom
AliaksandrNazaruk:fix/usage-balance-alltime

Conversation

@AliaksandrNazaruk

Copy link
Copy Markdown
Contributor

Problem

GET /api/usage computed balanceUsd = totalCredits − totalUsage, where totalCredits sums all-time confirmed/forwarded credit_deposits but totalUsage sums only the last-30-days usage_events (that query is windowed + .limit(1000) because it also feeds the history/breakdowns). So any spend older than 30 days is never subtracted and the balance is overstated — e.g. top up $100, spend $90 in January, return in March → balance shows ~$100 again (see #43).

Fix

Subtract an all-time usage total for the balance, computed via a DB-side aggregate (cost_usd.sum()), while keeping the existing 30-day query for the history/daily/module breakdowns. It falls back to the recent-window sum if PostgREST aggregates aren't available, so it can never overstate more than the current behavior:

let totalUsage = (events || []).reduce((s, e) => s + Number(e.cost_usd || 0), 0); // fallback
const { data: usageAgg, error: usageAggErr } = await admin
  .from("usage_events").select("total:cost_usd.sum()").eq("user_id", user.id).single();
const allTimeUsage = Number((usageAgg as { total?: number } | null)?.total);
if (!usageAggErr && Number.isFinite(allTimeUsage)) totalUsage = allTimeUsage;

Note

If you'd prefer a dedicated usage_total_cost(user_id) SQL function (the repo already uses .rpc(...) elsewhere) over the PostgREST aggregate, I'm happy to switch to a migration + RPC — just say the word. The aggregate keeps this PR code-only and safe by construction.

Fixes #43.

…window

/api/usage computed balanceUsd = totalCredits - totalUsage where totalCredits
summed ALL confirmed/forwarded credit_deposits (no date filter) but totalUsage
summed only the usage_events from the last 30 days (and capped at 1000 rows,
since that query also feeds the history/breakdowns). So any spend older than
30 days effectively 'came back' and the remaining balance was overstated
(e.g. top up $100, spend $90 in January, return in March -> balance shows
~$100 again).

Subtract an all-time usage total for the balance via a DB-side aggregate,
falling back to the recent-window sum if PostgREST aggregates are unavailable
(so it can never overstate more than before). The 30-day query is kept for
history/daily/module breakdowns.
@ralyodio ralyodio merged commit b740a19 into profullstack:master Jul 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

usage: credit balance overstated — subtracts only 30-day usage from all-time credits

2 participants