One Shot answers two different authorization questions, and it answers them with two different
mechanisms on purpose: whether a workspace is *allowed to use a paid feature at all*, and whether
*this specific user can act on this specific record*. Conflating the two either lets a free account
touch paid functionality, or makes every feature-gate check reimplement record-level scoping. Keep
them separate.

## Entitlement: the coarse paywall

`RequireEntitlement` answers "may this workspace use the paid surface at all?" Include it in any
controller whose feature is paid:

```ruby
class ProjectsController < ApplicationController
  include RequireEntitlement
  # ...
end
```

It checks `Billing.for(Current.account).entitled?` on every action, and redirects to the pricing
page when the account isn't entitled. Admins are exempt, so an admin account can always reach a
paid controller regardless of subscription status. Drop the include entirely for a feature that
should be free.

See [Gating a Feature](/docs/billing-entitlements/gating-a-feature) for the full walkthrough of
adding this to a new resource.

## Record-level authorization: Pundit

Entitlement answers "is this workspace allowed in here," not "which rows can it see." That's
Pundit's job. Every resource gets a policy in `app/policies/`, subclassing `ApplicationPolicy`, and
two safety defaults apply everywhere:

- **Account-scoped by default.** `ApplicationPolicy::Scope` filters any relation carrying an
  `account_id` column down to the acting user's account. Call `policy_scope(SomeModel)` instead of
  `SomeModel.all`, and a request for another tenant's record can't leak through, even if a
  developer forgets to scope a specific query by hand.
- **Deny by default.** The base policy returns `false` for every action. A resource's own policy
  has to opt in per action; nothing is implicitly allowed just because a policy class exists.

Controllers call `authorize @record` before acting on it, and `policy_scope(Relation)` when listing
records. `pundit_user` resolves to `Current.user` (guests get `nil`, so a policy can distinguish
signed-in from anonymous without a separate check). `ProjectPolicy` is the reference
implementation, and `spec/policies/project_policy_spec.rb` is the reference spec, including the
tenant-isolation test: requesting a record that belongs to a different account by id should behave
like the record doesn't exist, not like it's forbidden. A 404, not a 403, is what stops a URL from
confirming that another tenant's data exists at all.

## Roles

`User#role` is either `member` or `admin`. There's no admin UI in v1: an admin manages data through
`bin/rails console`, and the `admin?` check exists mainly to exempt admin accounts from entitlement
checks. You can use the same flag to gate an admin area you build yourself later.

## Next

See how billing and entitlement fit together:
[How Billing Works](/docs/billing-entitlements/how-billing-works).
