Skip to content

feat(billing): add requireQuota middleware for plan-based limits#3275

Merged
PierreBrisorgueil merged 2 commits intomasterfrom
feat/billing-require-quota
Mar 18, 2026
Merged

feat(billing): add requireQuota middleware for plan-based limits#3275
PierreBrisorgueil merged 2 commits intomasterfrom
feat/billing-require-quota

Conversation

@PierreBrisorgueil
Copy link
Contributor

@PierreBrisorgueil PierreBrisorgueil commented Mar 18, 2026

Summary

  • Add requireQuota(resource, action) factory middleware that gates routes by plan-based usage quotas
  • Reads limits from config.billing.quotas[plan][resource][action], checks current month usage via BillingUsage service
  • Returns 429 with QUOTA_EXCEEDED payload (resource, action, limit, current, upgradeUrl) when over limit
  • Orgs without subscription or with past_due status are treated as free plan; Infinity means unlimited

Test plan

  • 10 unit tests covering: under quota, at/over quota, missing subscription, past_due, Infinity bypass, error payload, missing org context, unconfigured resource, zero usage
  • All 244 existing unit tests still pass
  • Lint passes

Closes #3270

Summary by CodeRabbit

  • New Features
    • Added usage quota limits based on subscription plan tier. Users reaching their plan's quota limits will receive a quota exceeded response with upgrade information.

Copilot AI review requested due to automatic review settings March 18, 2026 21:24
@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Warning

Rate limit exceeded

@PierreBrisorgueil has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 4 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5785e6ea-f20d-4db5-b517-2e76eb29cdbc

📥 Commits

Reviewing files that changed from the base of the PR and between f17f27e and 58dd6d5.

📒 Files selected for processing (2)
  • modules/billing/middlewares/billing.requireQuota.js
  • modules/billing/tests/billing.quota.unit.tests.js

Walkthrough

This PR introduces a new Express middleware factory requireQuota(resource, action) that enforces per-plan usage limits. The middleware determines a user's plan from their subscription status, retrieves quota configuration, checks current usage, and responds with 429 if the limit is exceeded. Accompanying unit tests verify quota enforcement across multiple scenarios including missing subscriptions, past due statuses, and unlimited quotas.

Changes

Cohort / File(s) Summary
Billing Quota Middleware Implementation
modules/billing/middlewares/billing.quota.middleware.js
New middleware factory that gates access based on per-plan quotas by reading config, determining plan from subscription status, and comparing usage against limits. Returns 429 QUOTA_EXCEEDED when limit is reached.
Billing Quota Middleware Tests
modules/billing/tests/billing.quota.unit.tests.js
Comprehensive unit test suite covering quota enforcement scenarios: under/at/over limit, missing subscription, past_due status, unlimited quotas, missing organization (403), unconfigured resources, and error payload validation with upgradeUrl.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Middleware as Quota Middleware
    participant SubRepo as SubscriptionRepository
    participant Config
    participant UsageService as BillingUsageService
    participant Response

    Client->>Middleware: HTTP Request (resource, action)
    Middleware->>Middleware: Check org in request
    alt No organization
        Middleware->>Response: 403 Forbidden
    else Organization present
        Middleware->>SubRepo: Get subscription by org
        alt No subscription or past_due
            Middleware->>Middleware: Set plan = 'free'
        else Subscription active
            Middleware->>Middleware: Set plan = subscription.plan
        end
        Middleware->>Config: Read quota limit<br/>quotas[plan][resource][action]
        alt No quota configured or Infinity
            Middleware->>Client: Call next()
        else Quota exists
            Middleware->>UsageService: Get current usage<br/>(org, resource, action)
            alt Current >= Limit
                Middleware->>Response: 429 QUOTA_EXCEEDED<br/>(details + upgradeUrl)
            else Under limit
                Middleware->>Client: Call next()
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: introducing a requireQuota middleware for enforcing plan-based usage limits.
Description check ✅ Passed The description covers the main objectives, test plan with checkmarks, and references the linked issue, but lacks explicit scope details (modules impacted, risk level) and validation checklist items per template.
Linked Issues check ✅ Passed All coding requirements from #3270 are met: middleware factory, quota config reading, usage checking, 429 response with correct payload, free plan treatment, and Infinity support.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the requireQuota middleware implementation and its unit tests, with no out-of-scope modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/billing-require-quota
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new billing middleware to enforce plan-based monthly usage quotas, enabling downstream projects to gate specific actions based on configured limits and current usage.

Changes:

  • Introduces requireQuota(resource, action) middleware that resolves plan and enforces config.billing.quotas limits using BillingUsageService.
  • Returns a 429 QUOTA_EXCEEDED payload including resource, action, limit, current, and upgradeUrl when the quota is reached/exceeded.
  • Adds unit tests covering free/past_due handling, unlimited (Infinity), missing subscription/org context, and unconfigured quotas.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
modules/billing/middlewares/billing.quota.middleware.js New quota-enforcement middleware using subscription plan + monthly usage counters.
modules/billing/tests/billing.quota.unit.tests.js Unit tests validating quota decisions and error payload behavior.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/middlewares/billing.quota.middleware.js`:
- Line 22: The returned async middleware function requireQuotaMiddleware is
missing a JSDoc header; add a JSDoc block immediately above "return async
function requireQuotaMiddleware(req, res, next) {" with a one-line description,
`@param` {Request} req, `@param` {Response} res, `@param` {Function} next, and
`@returns` {Promise<void>} to satisfy the repository rule that every new/modified
JS function has a one-line description and param/returns tags.
- Around line 48-55: Replace the raw res.status(429).json(...) in the billing
quota middleware with the shared responses helper so the response uses the
standard { type, message, data } envelope; specifically, in the function that
currently returns the 429 (the billing quota middleware around the return
statement using variables resource, action, limit, current), call the
centralized responses helper (e.g., responses.error or responses.send depending
on project helper) to send status 429 and pass { type: 'QUOTA_EXCEEDED',
message: 'Quota exceeded', data: { resource, action, limit, current, upgradeUrl:
config.billing?.upgradeUrl || '/billing/plans' } } instead of the raw JSON.
🪄 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: 2b6fe068-ba0c-4a97-b933-98992528d9eb

📥 Commits

Reviewing files that changed from the base of the PR and between cf4763f and f17f27e.

📒 Files selected for processing (2)
  • modules/billing/middlewares/billing.quota.middleware.js
  • modules/billing/tests/billing.quota.unit.tests.js

- Rename billing.quota.middleware.js → billing.requireQuota.js for naming
  consistency with billing.requirePlan.js
- Add JSDoc to inner middleware function per repository coding guidelines
- Document bypass cases (null/undefined limit, Infinity) in outer JSDoc
- Use responses.error envelope for 429 quota response instead of raw JSON
- Update test assertions to match standardized response envelope
@PierreBrisorgueil PierreBrisorgueil merged commit 4ee7e48 into master Mar 18, 2026
3 checks passed
@PierreBrisorgueil PierreBrisorgueil deleted the feat/billing-require-quota branch March 18, 2026 21:44
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.

feat(billing): requireQuota middleware for plan-based limits

2 participants