dashboard: consume /billing/usage + /team/summary (§10.20)#33
Merged
Conversation
Retires the client-side Usage-panel aggregation (resources → useMemo) in favour of the new server-side cached aggregates. The dashboard no longer pulls the full resource list just to compute six numbers; the agent API caches the rollup per team in Redis (30s for billing/usage, 5min for team/summary) and shares it across surfaces. Per the §13 freshness rule, the eventual-consistency tradeoff is now visible to users — the Usage panel renders an "as of Ns ago · cached 30s" footnote so they can tell whether a freshly-provisioned resource should already appear in the figures. api/index.ts — adds fetchBillingUsage() + fetchTeamSummary() typed wrappers, including BillingUsage / TeamSummary / UsageMetric / TeamSummaryCounts types. BillingPage.tsx — replaces the resources useMemo aggregate with the server payload. The Usage panel still renders the same six rows; values now come from `billingUsage.usage.<service>.bytes` (or `.count`) and the seats row finally reads a real member count (closes the §10.7 gap for the Usage panel). Adds formatAsOf() helper + data-testid `billing-usage-as-of` for the eventual-consistency footnote. AppShell.tsx — extends SidebarUpgradeCard to fetch /team/summary once per session-load (5m Redis cache + browser Cache-Control makes this cheap) and render a "N resources · M members" line on paid-tier cards. Skipped for anonymous/free where the card is the upgrade CTA only. Tests: 164 pass, 3 skipped (matches main). New §10.20 coverage in BillingPage.test.tsx asserts: - listResources() is NOT called for usage data (regression guard) - fetchBillingUsage() is called exactly once - the `as_of` footnote renders when the cached payload arrives - zero-usage server response renders zeroes in every row - server bytes → MB conversion (100 MB Postgres → "100 / 1 GB") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re removal PR #33 (caching layer §10.20) and PR #32 (fixture removal §10.21) both edited BillingPage.tsx in different places. Merge resolution keeps: - fetchBillingUsage() from #33 for the Usage panel (server-side cached 30s with singleflight) - billingErr + billingLoading state from #32 for honest error rendering when fetchBilling rejects (no more fixture-fallback lie) Drop the now-unused listResources() call in the useEffect — usage data comes from fetchBillingUsage now, not client-side aggregation. Update BillingPage.test.tsx — the two §10.21 error-state tests need to mock fetchBillingUsage too (was previously mocking listResources, which is no longer called by the page). Test gate: 172 passed, 3 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Pairs with the api §10.20 PR (https://github.com/InstaNode-dev/api/pull/22). Retires the client-side Usage-panel aggregation in
BillingPage(resources → useMemo) and wires the new cached server aggregates. Sidebar gains live resource/member counts that previously didn't render because there was no live source.api/index.ts—fetchBillingUsage()+fetchTeamSummary()typed wrappers, withBillingUsage/TeamSummary/UsageMetrictypes.BillingPage.tsx— Usage panel reads fromfetchBillingUsage()instead of summinglistResources()storage bytes client-side. Renders an "as of Ns ago · cached 30s" footnote so users can see the eventual-consistency window (per §13).AppShell.tsx—SidebarUpgradeCardfetches/team/summaryonce per session-load (5m Redis cache + browserCache-Control: max-age=300keeps the cost low) and renders "N resources · M members" on paid-tier cards.Test plan
npx tsc --noEmit— clean.npm test -- --run— 164 pass, 3 skipped (matches main).listResources()is NOT called for usage;fetchBillingUsage()is called once; theas_offootnote renders.§14 caching-review checklist (consumer side)
This PR is a pure read consumer — the cache lives on the agent API. The dashboard relies on the API's
Cache-Control: private, max-age=30, stale-while-revalidate=60for browser caching. No client-side stash, no localStorage usage state.🤖 Generated with Claude Code