All use cases
Commerce

Gate features by plan and meter usage

One check for "can they do this?", whether it is a flag or a quota.

The problem

Plan checks start as one if and end up everywhere: in controllers, in views, in a job, in a queue worker. Each copy encodes the plan names slightly differently, and the day you add a tier you find them all by grepping and missing one.

Metered limits are worse, because the failure is silent. A quota that is never checked does not error — it just never runs out, and you find out from the bill.

What you are building

Live surfaces, not screenshots — every one composed from the same components you would install.

Usage and limits

Metered features from laravel-fms, showing remaining allowance before the gate denies.

Usage this periodTeam
8,420
API calls
6 / 10
Seats
92%
Storage
API calls84%
Seats60%
Storage92%

Storage is over 90% — the gate returns a soft-limit warning before it denies.

The code

Define the feature oncephp
// config/fms.php -- boolean for on/off, resource for anything metered. Both take
// callables, so entitlement is DERIVED from the subscription rather than copied
// onto the user record where it goes stale.
'features' => [
    'use-mcp' => [
        'name'    => 'Use MCP',
        'type'    => 'boolean',
        'enabled' => fn ($user) => $user->subscribedToProduct('pro'),
    ],

    'ai-tokens' => [
        'name'  => 'AI tokens',
        'type'  => 'resource',
        'limit' => 10_000,
        'usage' => fn ($user) => $user->tokenUsage()->thisPeriod()->sum('tokens'),
    ],
],
Ask the same question everywherephp
use ParticleAcademy\Fms\Facades\FMS;

// Route boundary.
Route::middleware(['auth', RequireFeature::class.':use-mcp'])->group(/* ... */);

// UI hint, from the SAME source -- so the interface never offers something the
// route will refuse, and a metered feature can show what is left before it
// denies.
return Inertia::render('Workspace', [
    'can'       => ['useMcp' => FMS::canAccess('use-mcp')],
    'remaining' => FMS::remaining('ai-tokens'),
]);

How to solve it

  1. Install feature management

    Boolean features and metered resource features behind a single access check.

    Run thisbash
    composer require particle-academy/laravel-fms
  2. Define features once, in config

    Each feature declares its type and either its enabled rule or its limit. Callbacks receive the user and a context, so a limit can vary by plan without the call sites knowing how.

  3. Check access the same way everywhere

    One facade, one helper, one middleware for routes. Gates and policies are consulted first, so existing authorization keeps working rather than being replaced.

  4. Attach features to what you sell

    With the catalog installed, features attach to products — so the plan a customer bought determines what they can reach, with no second mapping to maintain.