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.
Storage is over 90% — the gate returns a soft-limit warning before it denies.
The code
// 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'),
],
],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
Install feature management
Boolean features and metered resource features behind a single access check.
Run thisbash composer require particle-academy/laravel-fmsDefine 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.
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.
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.
