Skip to content

feat(billing): add useQuota composable for plan-based feature gating#3743

Merged
PierreBrisorgueil merged 2 commits intomasterfrom
feat/billing-use-quota
Mar 19, 2026
Merged

feat(billing): add useQuota composable for plan-based feature gating#3743
PierreBrisorgueil merged 2 commits intomasterfrom
feat/billing-use-quota

Conversation

@PierreBrisorgueil
Copy link
Copy Markdown
Collaborator

@PierreBrisorgueil PierreBrisorgueil commented Mar 19, 2026

Summary

  • Add fetchUsage() store action calling GET /billing/usage and storing quota data (plan, period, usage, limits)
  • Create useQuota composable with canDo(resource, action) and usagePercent(resource, action) helpers for plan-based feature gating
  • Add 20 unit tests covering store action, canDo logic (under/at/over limit, Infinity, undefined, null), usagePercent (correct %, cap at 100, edge cases), refresh, and computed defaults

Test plan

  • npx eslint passes on all changed files
  • All 20 new unit tests pass
  • Full test suite (675 tests) passes with no regressions

Closes #3739

Summary by CodeRabbit

  • New Features

    • Added quota management functionality to check if users can perform actions based on their billing limits.
    • Added usage tracking that displays resource consumption as a percentage of allocated limits.
    • Added ability to refresh quota and usage information on-demand.
  • Tests

    • Added comprehensive unit tests for quota management features.

Copilot AI review requested due to automatic review settings March 19, 2026 07:36
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 19, 2026

Warning

Rate limit exceeded

@PierreBrisorgueil has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 2 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: 3a0d3820-a067-4644-ae1a-7a1dbace5d67

📥 Commits

Reviewing files that changed from the base of the PR and between 952c270 and 3777dc0.

📒 Files selected for processing (2)
  • src/modules/billing/composables/billing.useQuota.js
  • src/modules/billing/tests/billing.useQuota.unit.tests.js

Walkthrough

Added a new Vue composable useQuota that provides quota checking and usage percentage computation for billing-based feature gating. The composable integrates with the billing store, which now includes a new quota state property and a fetchUsage() action that fetches quota data from the billing usage endpoint.

Changes

Cohort / File(s) Summary
Billing Quota Composable & Store
src/modules/billing/composables/billing.useQuota.js, src/modules/billing/stores/billing.store.js
New composable exports reactive plan, period, usage, limits computed properties; canDo(resource, action) method returns true when limit is missing, null, or Infinity; usagePercent(resource, action) computes 0–100 percentage with clamping; refresh() triggers fetchUsage(). Store now includes quota state and async fetchUsage() action that GET-requests /api/billing/usage endpoint.
Billing Quota Tests
src/modules/billing/tests/billing.useQuota.unit.tests.js
Comprehensive unit tests validating fetchUsage() endpoint behavior, quota data persistence, error handling with loading state reset, canDo() logic across under/at/over-limit states, usagePercent() percentage computation with edge cases (Infinity, null, undefined), integer rounding, and computed property defaults when quota is null.

Sequence Diagram

sequenceDiagram
    actor User
    participant Component as Vue Component
    participant Composable as useQuota()
    participant Store as useBillingStore
    participant API as Billing API

    User->>Component: Use composable to check quota
    Component->>Composable: Call refresh()
    Composable->>Store: Call fetchUsage()
    Store->>Store: Set loading = true
    Store->>API: GET /api/billing/usage
    API-->>Store: Return quota data
    Store->>Store: Store quota in state
    Store->>Store: Set loading = false
    Store-->>Composable: Return quota
    Composable-->>Component: Update computed values
    Component->>Composable: Call canDo(resource, action)
    Composable-->>Component: Return boolean (based on limits vs usage)
    Component->>Composable: Call usagePercent(resource, action)
    Composable-->>Component: Return 0–100 percentage
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #3740 — Dependent feature for displaying billing usage bars and upgrade prompts relies on the quota data and helper functions introduced in this PR.

Possibly related PRs

  • #3723 — Introduces the initial billing store scaffold that this PR extends with quota state and fetchUsage() action.

Suggested labels

billing

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a useQuota composable for plan-based feature gating, which is the primary objective of this pull request.
Description check ✅ Passed The description covers the main changes, includes a test plan with verification checkmarks, and references the closed issue. However, it deviates from the template by omitting several required sections like Scope, Validation checklist, and Guardrails.
Linked Issues check ✅ Passed The PR successfully implements all requirements from issue #3739: adds fetchUsage() action, useQuota composable with canDo() and usagePercent(), exposes usage/limits/plan/period, and includes 20 unit tests covering all specified scenarios.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the useQuota composable and supporting infrastructure (store action and unit tests). No unrelated modifications are present.
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-use-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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.19%. Comparing base (8203f2c) to head (3777dc0).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3743   +/-   ##
=======================================
  Coverage   99.18%   99.19%           
=======================================
  Files          26       26           
  Lines         863      873   +10     
  Branches      223      223           
=======================================
+ Hits          856      866   +10     
  Misses          7        7           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

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 quota/usage support to the billing module so downstream projects can gate UI features based on plan limits via a dedicated composable backed by a store action.

Changes:

  • Added fetchUsage() action to the billing Pinia store to fetch and cache quota usage/limits data from the billing API.
  • Introduced useQuota() composable to expose plan, period, usage, limits, plus canDo() and usagePercent() helpers and a refresh() method.
  • Added unit tests covering the store fetch and composable quota calculations/defaults.

Reviewed changes

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

File Description
src/modules/billing/stores/billing.store.js Adds quota state and fetchUsage() action to retrieve and store usage/limits data.
src/modules/billing/composables/billing.useQuota.js New composable providing quota gating helpers and accessors backed by the billing store.
src/modules/billing/tests/billing.useQuota.unit.tests.js New unit tests for fetchUsage, canDo, usagePercent, refresh, and computed defaults.

Copy link
Copy Markdown

@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 `@src/modules/billing/composables/billing.useQuota.js`:
- Around line 43-45: The usagePercent() function treats falsy limits the same as
"no limit", so a limit of 0 incorrectly returns 0% while canDo() treats 0 as
blocking; update usagePercent() to explicitly handle limit === 0 by returning
100 (or another value consistent with canDo's semantics) before the no-limit
check (i.e., check if limit === 0 first), then keep the existing branch for
limit === Infinity or undefined; reference the usagePercent() function, the
limit variable, usage.value[key], and canDo() to ensure consistent behavior
across both functions.

In `@src/modules/billing/tests/billing.useQuota.unit.tests.js`:
- Around line 121-176: Add a regression test to the existing
describe('usagePercent') block to cover the case when a resource limit equals 0:
set store.quota with usage e.g. { 'documents.create': 1 } and limits {
'documents.create': 0 }, call usagePercent('documents', 'create') and assert it
returns 0; place the new it(...) alongside the other tests so usagePercent is
exercised for the zero-limit edge case.
🪄 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: f496d4c8-1ef5-447e-9f9d-ff627ff6ea21

📥 Commits

Reviewing files that changed from the base of the PR and between d591112 and 952c270.

📒 Files selected for processing (3)
  • src/modules/billing/composables/billing.useQuota.js
  • src/modules/billing/stores/billing.store.js
  • src/modules/billing/tests/billing.useQuota.unit.tests.js

Comment thread src/modules/billing/composables/billing.useQuota.js Outdated
Comment thread src/modules/billing/tests/billing.useQuota.unit.tests.js
@PierreBrisorgueil PierreBrisorgueil merged commit 85e2984 into master Mar 19, 2026
4 checks passed
@PierreBrisorgueil PierreBrisorgueil deleted the feat/billing-use-quota branch March 19, 2026 08:00
PierreBrisorgueil pushed a commit that referenced this pull request Apr 1, 2026
# [1.5.0](v1.4.0...v1.5.0) (2026-04-01)

### Bug Fixes

* **analytics:** PostHog api_host bug + identify/group on login ([#3772](#3772)) ([534fdf3](534fdf3)), closes [#3753](#3753) [#3766](#3766) [#3769](#3769) [#3771](#3771)
* **auth,admin:** move mailer warning to admin page, fix verify-email routing, align invite button ([0d195c4](0d195c4))
* **auth:** add missing $route.query mock in verifyEmail tests ([b2732f6](b2732f6))
* **auth:** address CodeRabbit review feedback ([1d14b06](1d14b06))
* **auth:** address review feedback from pass 1 ([bd27d2f](bd27d2f))
* **auth:** address review feedback from pass 1 ([a87fdb1](a87fdb1))
* **auth:** address review feedback from pass 2 — prevent form flash on load ([a6afeca](a6afeca))
* **auth:** fix runtime deprecation warnings and add auth view unit tests ([1901dad](1901dad)), closes [#3592](#3592)
* **auth:** persist snackbar dismissal on implicit close ([5e464c3](5e464c3))
* **auth:** resolve lint errors and update test mocks for fetchServerConfig ([a642001](a642001))
* **billing:** add store unit tests and fix view import paths ([e370272](e370272))
* **billing:** address CodeRabbit review — guards, tests, JSDoc, price fallback ([f0f6657](f0f6657))
* **billing:** address CodeRabbit review feedback ([b195d2d](b195d2d))
* **billing:** address CodeRabbit review feedback ([8435d1c](8435d1c))
* **billing:** address CodeRabbit review feedback ([4187771](4187771))
* **billing:** address review — tier comparison, graceful failure, tests, naming ([7b00b91](7b00b91))
* **billing:** address review feedback — pricing card, fetch guard, router tests ([34cbda9](34cbda9))
* **billing:** address UI review findings ([b281a8a](b281a8a))
* **billing:** address UI review findings ([ead3eb0](ead3eb0))
* **billing:** address UI review findings ([b2d3897](b2d3897))
* **billing:** address UI review findings ([a756cd9](a756cd9))
* **billing:** align CASL guard subject with backend policy ([7e8287b](7e8287b))
* **billing:** align CASL guard subject with backend policy ([8e9b768](8e9b768))
* **billing:** correct plan field name, add enterprise badge, store cleanup ([#3733](#3733)) ([9b6e30d](9b6e30d)), closes [#3729](#3729) [#3730](#3730) [#3731](#3731) [#3732](#3732) [#3729](#3729) [#3730](#3730) [#3731](#3731) [#3732](#3732)
* **billing:** correct test URL assertions to match store checkout URLs ([cd64628](cd64628))
* **billing:** correct view import paths to match lowercase filenames ([e2646dd](e2646dd))
* **billing:** default free plan display + E2E security tests ([#3751](#3751)) ([025534a](025534a))
* **billing:** fix branch coverage and E2E auth guard test ([2864cf7](2864cf7))
* **billing:** fix branch coverage and harden E2E auth test ([7b91edb](7b91edb))
* **billing:** fix error-handling tests and restore CASL guard on /billing route ([bcb15a6](bcb15a6))
* **billing:** fix plan merge — match by planId/name and build price objects ([1c1c765](1c1c765))
* **billing:** gate fetchSubscription behind org check and add missing [@returns](https://github.com/returns) JSDoc ([9dd15a7](9dd15a7))
* **billing:** harden URL validation, test assertions, and error handling ([44d9cc2](44d9cc2))
* **billing:** include canceled query param in checkout cancel URL ([9e28636](9e28636))
* **billing:** propagate errors, add CASL route metadata, rename views ([39343ba](39343ba))
* **billing:** remove duplicate import in E2E test ([02576f5](02576f5))
* **billing:** rename views, fix test assertions, address review feedback ([cb72130](cb72130))
* **billing:** separate checkout error from fetch error in pricing view ([78db8b1](78db8b1))
* **billing:** update store cancel URL to include canceled query param ([ca5f1a3](ca5f1a3))
* **billing:** validate portal URL and catch fetchSubscription rejection ([7534b6c](7534b6c))
* **ci:** ensure coverage thresholds pass with all modules ([8e0c970](8e0c970)), closes [#3710](#3710)
* **ci:** remove ARC-specific conditionals from CI.yml ([#3806](#3806)) ([48747f3](48747f3)), closes [#3805](#3805)
* **config:** add missing api section to config.test.js ([#3679](#3679)) ([fff9ffc](fff9ffc)), closes [#3676](#3676)
* **config:** address review — use lodash-es, drop glob dep, add env warning ([1ec84fa](1ec84fa))
* **config:** address review feedback from pass 1 ([3336f09](3336f09))
* **config:** align app_title default between Dockerfile and hooks/build ([b08dbf3](b08dbf3))
* **config:** backward-compat fallback for sucessColor and improve warning ([1965557](1965557))
* **config:** fail fast when config is missing in production builds ([#3671](#3671)) ([c660ba4](c660ba4)), closes [#3669](#3669)
* **config:** generateConfig ignores module env-specific configs ([#3827](#3827)) ([1ffd80e](1ffd80e)), closes [#3826](#3826)
* **config:** remove [@desc](https://github.com/desc) tag from deepMerge JSDoc ([7c4b613](7c4b613))
* **config:** remove duplicate vuetify.theme block from app config merge ([5a583a7](5a583a7))
* **config:** remove unused imports and fix typo in generateConfig ([7b0c006](7b0c006))
* **config:** replace _.merge with deepMerge to fix array handling ([4e91025](4e91025)), closes [#3628](#3628)
* **config:** skip undefined values and guard against prototype pollution in deepMerge ([ffc574e](ffc574e))
* **config:** use pathToFileURL for cross-platform dynamic imports ([acad44e](acad44e))
* **core:** address review feedback from pass 1 ([0f6e3af](0f6e3af))
* **core:** make datatable generic via fetchAction prop ([e3a4926](e3a4926)), closes [#3596](#3596)
* **coverage:** exclude bootstrapper files with 0% coverage from collection ([4dfde5a](4dfde5a))
* **datatable:** increase per page select width to 100px ([#3779](#3779)) ([ff65d6f](ff65d6f)), closes [#3778](#3778)
* **docker:** add DEVKIT_NODE_api_port to docker-compose.test.yml ([#3815](#3815)) ([0f06402](0f06402)), closes [#3809](#3809)
* **docker:** make docker-compose.test.yml work for downstream projects ([#3790](#3790)) ([838aec1](838aec1)), closes [#3789](#3789)
* **docs:** add src/ prefix and use <env> placeholder in merge order table ([5af5d5b](5af5d5b))
* **docs:** mark global env override config files as optional ([7459d0f](7459d0f))
* **e2e:** read ports from project config instead of hardcoding ([#3777](#3777)) ([ec56d20](ec56d20)), closes [#3775](#3775)
* **header:** address review feedback from pass 1 ([b05d210](b05d210))
* **home,config:** address review feedback from pass 1 ([709ccbe](709ccbe))
* **home:** add JSDoc for tabs colorMode validator and tabStyle method ([a7fb5e3](a7fb5e3))
* **home:** add JSDoc to created() hook in home.team.view ([7548c15](7548c15))
* **home:** address CodeRabbit review feedback ([9990286](9990286))
* **home:** hero vertical centering, overlap prop, and Vuetify 4 typography migration ([4c26b25](4c26b25)), closes [#3587](#3587)
* **home:** pass colorMode to tabs component so forced text color applies to tab items ([50256d8](50256d8))
* **lodash:** use lodash-es imports for proper tree-shaking ([50570cf](50570cf))
* **nav:** fix organizations ghost item icon in sidenav ([bca4237](bca4237)), closes [#3706](#3706)
* **pull-request skill:** add consecutive_zero guard and re-check pending review checks ([18c70f8](18c70f8))
* **pull-request skill:** address review feedback — clarity and consistency ([2dd1ce2](2dd1ce2))
* **pull-request skill:** reply and resolve all threads including non-actionable ([ff776c8](ff776c8))
* **security:** harden auth views against XSS and weak validation ([#3735](#3735)) ([c3b844d](c3b844d))
* **seo-inject:** add JSON-LD structured data injection ([#3670](#3670)) ([5b36e5c](5b36e5c)), closes [#3664](#3664)
* **seo:** improve heading hierarchy and alt text for accessibility ([#3661](#3661)) ([918f9bd](918f9bd))
* **seo:** puppeteer prerender Docker support + minor plugin fixes ([#3673](#3673)) ([8ac241b](8ac241b))
* **seo:** skip runtime JSON-LD when seo-inject handles schema ([#3677](#3677)) ([#3680](#3680)) ([b0d90ac](b0d90ac))
* **skill:** add merge conflict check in pull-request convergence loop ([ef136ed](ef136ed)), closes [#3707](#3707)
* **skill:** address review feedback from pass 1 ([4020b82](4020b82))
* **skill:** handle CHANGES_REQUESTED, UNKNOWN mergeable, and standardize $PR usage ([13cb3cf](13cb3cf))
* **skill:** pull-request skill should ignore stack-level CodeRabbit comments for downstream projects ([97d2cb2](97d2cb2)), closes [#3604](#3604)
* **skills:** clarify feature Phase 0 completeness check ([#3773](#3773)) ([8ac6b1b](8ac6b1b))
* **skills:** match coderabbitai[bot] login in monitoring jq filter ([aae850f](aae850f))
* **update-stack:** add concrete gh issue create command and resolution guidance ([6092368](6092368))
* **update-stack:** add downstream-only new files rule to conflict table ([4a15e39](4a15e39))
* **update-stack:** address review feedback from pass 1 ([f7ed820](f7ed820))
* **update-stack:** address review feedback from pass 2 ([2bef8a3](2bef8a3))
* **update-stack:** clarify failure origin criteria in step 3bis ([a71515e](a71515e))

### Features

* add /frontend design skill + migrate Vuetify 3 patterns to V4 ([#3644](#3644)) ([2f2a8ff](2f2a8ff))
* **analytics:** add useFeatureFlag and usePostHog composables ([#3774](#3774)) ([2506a4f](2506a4f)), closes [#3771](#3771)
* **auth:** add email verification gate UI for org setup ([999aa60](999aa60))
* **auth:** add password visibility toggle ([#3752](#3752)) ([ea3b0a0](ea3b0a0)), closes [#336](#336)
* **auth:** display server-side auth status on signin/signup pages ([0f4276d](0f4276d))
* **billing:** add billing page with plan badge and subscription management ([e9a1fc5](e9a1fc5)), closes [#3715](#3715)
* **billing:** add BillingUsageBar component and enhance UpgradePrompt ([#3744](#3744)) ([0e9ca7f](0e9ca7f))
* **billing:** add checkout flow with auth/org guards and Stripe redirect ([ce17d67](ce17d67)), closes [#3714](#3714)
* **billing:** add checkout flow with auth/org guards and Stripe redirect ([f762d91](f762d91)), closes [#3714](#3714)
* **billing:** add feature gates — composable, upgrade prompt, router guard ([207c022](207c022)), closes [#3716](#3716)
* **billing:** add homepage pricing section ([a8ced6d](a8ced6d)), closes [#3717](#3717)
* **billing:** add pricing page with plan cards and billing toggle ([abb1d4a](abb1d4a)), closes [#3713](#3713)
* **billing:** add pricing page with plan cards and billing toggle ([0881a9f](0881a9f)), closes [#3713](#3713)
* **billing:** add useQuota composable for plan-based feature gating ([#3743](#3743)) ([85e2984](85e2984))
* **billing:** move pricing to dedicated page, update topnav ([eaab6f3](eaab6f3))
* **billing:** scaffold billing module with store, router, and views ([7b08b12](7b08b12)), closes [#3712](#3712)
* **ci:** skip setup-node and playwright install on self-hosted runner ([#3803](#3803)) ([104d4f8](104d4f8)), closes [#3802](#3802)
* **ci:** support configurable runner via RUNNER variable ([#3794](#3794)) ([1151d02](1151d02)), closes [#3792](#3792)
* **ci:** use APP_ENV variable for generateConfig in CI ([#3801](#3801)) ([e384c7c](e384c7c)), closes [#3795](#3795)
* **config:** migrate WAOS_VUE_* env prefix to DEVKIT_VUE_* ([7ad1a7f](7ad1a7f)), closes [#3614](#3614)
* **header:** add float scroll behavior and document all config options ([d1d4891](d1d4891))
* **home:** add dedicated 404 Not Found page ([#3655](#3655)) ([ac73739](ac73739))
* **home:** add FAQ accordion component with JSON-LD schema ([#3821](#3821)) ([444e62c](444e62c)), closes [#3819](#3819)
* **nav:** liquid glass sidenav with Apple-style inset mode ([#3737](#3737)) ([8203f2c](8203f2c))
* **pageHeader:** add tabs slot as alternative to icon + title ([#3781](#3781)) ([763d814](763d814)), closes [#3780](#3780)
* phase 2 organizations ([#3702](#3702)) ([71c6a5c](71c6a5c)), closes [#3674](#3674) [#3675](#3675) [#3684](#3684) [#3686](#3686) [#3681](#3681) [#3682](#3682) [#3683](#3683) [#3684](#3684) [#3685](#3685) [#3686](#3686) [#3675](#3675) [#3674](#3674)
* rename /frontend to /ui, add workflow rules ([#3704](#3704)) ([3d8259e](3d8259e))
* **sentry:** add Sentry error tracking and ErrorBoundary component ([#3788](#3788)) ([b5463d7](b5463d7)), closes [#3787](#3787)
* **seo-inject:** add noscript fallback, preconnect hints, and theme-color ([#3663](#3663)) ([261a3a8](261a3a8))
* **seo:** add pre-rendering of home page at build time ([#3660](#3660)) ([39d9414](39d9414))
* **seo:** add seo-static Vite plugin for robots.txt, sitemap.xml, manifest.json ([#3658](#3658)) ([0a50388](0a50388))
* **update-stack:** report upstream issues when verify fails on stack code ([71dbecc](71dbecc))
* **verify:** add coverage enforcement to verify skill ([#3776](#3776)) ([63301f9](63301f9))

### Performance Improvements

* **ci:** optimize GitHub Actions ([#3793](#3793)) ([e31287e](e31287e)), closes [#3791](#3791)
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): useQuota composable for plan-based feature gating

2 participants