feat(billing): add GET /api/billing/usage endpoint#3277
feat(billing): add GET /api/billing/usage endpoint#3277PierreBrisorgueil merged 3 commits intomasterfrom
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughAdds a new authenticated endpoint GET /api/billing/usage plus policy mapping and controller logic to return an organization's billing plan, current usage counters, flattened quota limits, and billing period; includes unit tests and CASL Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant API as "API /api/billing/usage"
participant Auth as "JWT / policy"
participant Org as "organization.resolveOrganization"
participant Controller as "BillingController.getUsage"
participant SubSvc as "BillingService"
participant UsageSvc as "BillingUsageService"
participant Config as "Config (quotas)"
Client->>API: GET /api/billing/usage (JWT)
API->>Auth: validate JWT & policy.isAllowed
Auth-->>API: allowed
API->>Org: resolve organization
Org-->>Controller: org id
Controller->>SubSvc: getSubscription(orgId)
SubSvc-->>Controller: subscription | null
Controller->>UsageSvc: get(orgId)
UsageSvc-->>Controller: usage { counters, month }
Controller->>Config: read billing.quotas[plan]
Controller-->>Controller: flatten quotas, normalize limits
Controller-->>Client: 200 { plan, period, usage, limits }
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new authenticated billing usage endpoint so the frontend can fetch current plan usage counters and quota limits in one call, with CASL authorization wired through the policy middleware.
Changes:
- Add
GET /api/billing/usageroute guarded by JWT, org resolution, and CASL. - Add
readability forBillingUsageand map/api/billing/usage→BillingUsagesubject type. - Implement
getUsagecontroller logic and add unit tests for plan fallback + quota flattening.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/billing/controllers/billing.controller.js | Adds getUsage controller to compute plan, period, usage counters, and flattened limits. |
| modules/billing/routes/billing.routes.js | Registers GET /api/billing/usage with auth/org/policy middleware chain. |
| modules/billing/policies/billing.policy.js | Grants read on BillingUsage for authenticated users with org membership. |
| lib/middlewares/policy.js | Maps the new route path to the BillingUsage CASL subject. |
| modules/billing/tests/billing.usage.endpoint.unit.tests.js | Adds unit coverage for subscription states, unknown plan, flattening, and error path. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@modules/billing/controllers/billing.controller.js`:
- Around line 7-8: The controller is calling SubscriptionRepository directly
(imported as SubscriptionRepository) which breaks the service-layer boundary;
add a subscription retrieval method on the service layer (e.g., add
getSubscriptionById or fetchSubscription in BillingUsageService) that uses
SubscriptionRepository internally, then update the controller to call
BillingUsageService.getSubscriptionById(...) instead of referencing
SubscriptionRepository, and remove the SubscriptionRepository import from the
controller so all repository access is encapsulated by BillingUsageService.
- Around line 89-99: The code copies planQuotas values directly into limits
which means non-finite values like Infinity will become null when
JSON-serialized; update the assignment where limits[`${resource}.${action}`] =
planQuotas[resource][action]; to detect non-finite numbers (e.g.,
Number.isFinite) and encode them explicitly (for example the string "unlimited"
or another agreed sentinel) before building the response so
responses.success(...) returns JSON-safe quota values that match the intended
meaning; touch the limits population logic and ensure any downstream consumers
expect the chosen sentinel, leaving usage.counters and responses.success calls
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: bdb36d2e-4ff1-496a-b972-f84f05e16415
📒 Files selected for processing (5)
lib/middlewares/policy.jsmodules/billing/controllers/billing.controller.jsmodules/billing/policies/billing.policy.jsmodules/billing/routes/billing.routes.jsmodules/billing/tests/billing.usage.endpoint.unit.tests.js
- Move subscription lookup behind BillingService (service-layer rule) - Remove SubscriptionRepository import from controller - Use usage.month for period instead of recomputing (avoid drift) - Normalize Infinity quotas to null for JSON-safe serialization - Update tests to match new service boundary and null limits
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@modules/billing/controllers/billing.controller.js`:
- Line 70: The current ternary that sets const plan = (!subscription ||
subscription.status === 'past_due') ? 'free' : (subscription.plan || 'free');
only guards one non-active status; change the logic so only subscription.status
values 'active' or 'trialing' permit the paid plan and all other statuses map to
'free' (e.g., if no subscription or status not in {'active','trialing'} =>
'free', else use subscription.plan); apply the identical fix in the similar
check inside billing.requireQuota.js (the middleware that determines plan/quota)
so both controller (plan assignment) and middleware use the same whitelist of
allowed statuses.
In `@modules/billing/tests/billing.usage.endpoint.unit.tests.js`:
- Around line 100-114: Add unit tests covering other non-active subscription
statuses by duplicating the existing test for 'past_due' and changing
mockBillingService.getSubscription to resolve values like { plan: 'starter',
status: 'canceled' } and { plan: 'starter', status: 'unpaid' } (or any
additional statuses your controller will treat as non-active); call
billingController.getUsage with the same mocked req/res and assert the response
contains plan: 'free' and the expected limits, reusing
mockBillingUsageService.get as in the current test to ensure the controller
behavior is validated for each non-active status.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 43f0adbb-a015-40ac-b214-3825e98d6738
📒 Files selected for processing (5)
lib/middlewares/policy.jsmodules/billing/controllers/billing.controller.jsmodules/billing/policies/billing.policy.jsmodules/billing/routes/billing.routes.jsmodules/billing/tests/billing.usage.endpoint.unit.tests.js
- Replace past_due-only check with active/trialing allowlist - All other statuses (canceled, unpaid, incomplete, etc.) now map to free - Add test.each for all non-active statuses + trialing test
Summary
GET /api/billing/usageendpoint returning current plan, period, usage counters, and flattened quota limitsreadability onBillingUsageCASL subject for authenticated users with org membership/api/billing/usageCloses #3272
Test plan
Summary by CodeRabbit