# @leumas/entitlements

Policy-driven entitlement engine — plans/memberships DECLARE capabilities + quota limits as data; one primitive gates & meters everywhere. The swappable membership-access axis (sibling to PassNode's...


Policy-driven, **swappable** entitlement engine. Plans/memberships **declare** capabilities + quota limits
as data; one primitive gates & meters everywhere — no `if (plan === 'Pro')` sprinkled through the code.

This is the **membership-access axis** (who may use a Leumas platform feature, and how much). It is a
sibling of, not the same as, **PassNode** in `@leumas/auth` (the tenant→end-user *monetization* axis).

## Model

A **capability** is a dotted key. Its value is a boolean (feature flag) or a number (quota limit):

```
imperium.hosting: true      imperium.maxSites: 5
imperium.customDomains: false   imperium.reverseProxy: true   imperium.tenantSeats: 10
```

Rules live as **data** in the Studio-editable `entitlement_policies` collection (one doc per plan/service),
with optional per-user overrides in `membership.metadata`. Change "Pro gets 5 sites + reverse-proxy" by
editing a doc — zero code change.

## Backend

```js
import { createEntitlements, createEntitlementsRouter } from '@leumas/entitlements';

const entitlements = createEntitlements({
  load: () => connector.get().read('entitlement_policies'),
  getUserMemberships: (userId) => membershipsService.listMemberships(userId),
});
await entitlements.refresh();                 // + refresh on the /db change-feed for entitlement_policies

app.use('/api/thing', entitlements.requireCapability('imperium.hosting'), thingRouter);
await entitlements.checkQuota(req.user, 'imperium.maxSites', currentCount); // throws 402 if over
app.use('/entitlements', createEntitlementsRouter({ entitlements, requireAuth }));
```

## Frontend

The API resolves server-side; the frontend fetches the resolved map once (`GET /entitlements/me`) and gates
off it. `@leumas/features` ships the React glue: `CapabilityProvider`, `useCapability(cap)`, `useLimit(cap)`
and `<RequireCapability cap=… fallback=… />`.


---
Source: shared/packages/entitlements/README.md
Canonical: https://docs.leumas.tech/p/packages/entitlements
