Entitlements: one pure function decides every limit
Every limit in RowShield — project counts, scan intervals, alert channels, seats — comes from a single pure function called entitlementsFor. It takes the organisation’s plan and subscription status and returns what that organisation is entitled to right now. No hidden lookups, no environment-dependent behaviour, no special cases buried in route handlers.
Purity is the point. Because the answer depends only on its inputs, it can be unit tested without a payment provider or a network, and because both the dashboard and the API call the same function, the two cannot disagree about what a plan allows.
One function, two callers
The interface consults entitlements when rendering: the connect form knows the project ceiling before you fill it in, and the alerts page offers only channels your plan includes. The worker applies the same numbers on schedule — the poller computes each organisation’s effective scan interval from the identical call, so a plan change takes effect without redeploying anything. Same inputs, same outputs, same instant.
const ent = entitlementsFor(
{ plan: 'indie', subscriptionStatus: org.subscriptionStatus },
{ billingEnabled: true },
);
// ent.maxProjects === 3
// ent.minPollingIntervalMin === 60
// ent.alertChannels === ['email', 'slack']
// ent.paymentFailing === falseLimits feel like signposts, not walls
When an action exceeds an entitlement, the response names the limit, explains it in a sentence, and identifies the cheapest plan that would allow the action. Nothing is silently truncated: a fourth project on Indie is refused with a message, not accepted and hidden.
Scan frequency works by clamping rather than rewriting. A project configured for five-minute polls on a plan whose floor is hourly is simply scanned hourly — the setting is kept untouched, so it takes effect again the moment the plan allows it.
Fail-open when billing is not configured
With no payment credentials present — every local development run and every continuous-integration job — billingEnabled is false and entitlements resolve to the full Team set, ungated. A paywall that depended on a secret being present would make the application unusable out of the box and fail in the wrong direction; the code chooses deliberately to fail open in development and closed nowhere.
Related questions
- If the interface and API call the same function, can I trust the UI to show real limits?
- Yes. There is no second source of truth to drift out of date. What the interface displays is what the API enforces, because both read the same return value.
- Where is the function defined?
- In packages/billing, alongside the plan catalogue. It imports no SDK and touches no network, which is why the whole paywall can be reviewed — or tested — in one sitting.
Did this answer your question? If not, tell us what is missing — article corrections go straight to the person who maintains it.