# Permissions by screen folder

> Canonical HTML: https://screenrig.ai/docs/permissions

A hotel manager runs the screens of one hotel, an agency's agent works on one
client's floor, a regional lead owns a dozen stores. Limit each of them to the
screen folders and screens they work on. Everything inside a folder is theirs,
everything outside it is out of reach, and the screens that matter most can
require a second approver for every change.

## Who is limited

- **A member.** The project owner limits a member to chosen screen folders and
  screens. The member signs in as before and sees and changes only their own
  screens.
- **An agent.** The owner limits an agent the same way. An agent also never
  reaches further than the person responsible for it: its reach is its own scope
  narrowed by that person's, so a limited person never acts through a wider
  agent.
- **Never limited.** The project owner and service clients of the whole project.

A limit is a *scope*. It is read on every request, never stored in a token or a
session, so a change applies to the person's next request without signing in
again. A caller with no scope works on the whole project and pays nothing for the
check.

## Folders and inheritance

[Screen folders](https://screenrig.ai/docs/cli.md#screen-folders) are the
hierarchy. A scope that names a folder holds every screen in that folder and in
every folder inside it, and it follows the folder when the folder moves.

```text
Hotel
  Lobby            <- the lobby manager's scope holds Lobby and Bar
    Bar
  Casino Floor     <- the floor manager's scope holds Casino Floor
  Rooms
```

- A scope holds up to 1,000 folders and 200 single screens, and at least one
  of the two.
- A single screen can sit in any number of scopes, and so can a folder.
- Ids must name live folders and screens of the project when the scope is
  written. A folder or screen deleted later leaves an id that grants nothing.
- A member who approves reviews is limited to folders. Single screens are for
  members who do not approve.
- A person is either limited to screens or an
  [uploader](https://screenrig.ai/docs/authentication.md#uploaders), never both:
  an uploader is limited to content, a limited member to screens.

## Set a scope

Only the project owner sets, changes or ends a scope, in the dashboard.

1. Open the dashboard's [Access](https://screenrig.ai/dashboard/access) page.
2. Under People, open the member and use **Screens**. Check the folders, which
   include everything inside them, and add single screens if the member does not
   approve. Save.
3. For an agent, open it under Agents and use the same **Screens** control.
4. To limit a person before they join, add the scope to the invitation.

Remove the scope in the same place to give the member the whole project again.

Setting a member's scope ends the agents that person brought to the project, so
nothing keeps the wider reach it was given before. A scope is refused while the
person, or an agent they brought, holds a live
[service client](https://screenrig.ai/docs/service-clients.md) of the project:
revoke each client the refusal names and set the scope again. Transferring the
project to a member removes that member's scope.

A member invited with a scope joins as a member who cannot approve. The owner
turns on **Can approve** for them on the same page when they should decide
reviews for their folders.

## What a limited person does and sees

Inside the scope a limited person works as a member of the project does, in the
dashboard, with the CLI and over the API:

- **Screens.** Read, health, plays, uptime, screenshots and live view,
  comments, commands such as reboot, clear cache, identify and update, tags,
  fields, location, name, playlist, playlist schedule, takeover, archive and
  delete.
- **Folders.** Create, rename, move and delete folders inside the scope, and set
  a folder's default playlist. The folder a scope names stays: only a person
  with a wider scope deletes it.
- **Moves.** A screen or folder moves from one place inside the scope to
  another. The source and the destination are both inside it.
- **Campaigns.** Create, change and delete a campaign whose whole audience is
  inside the scope.
- **Fleet actions.** Select screens by id or by folder inside the scope.
- **New screens.** A limited person who can approve pairs or provisions a screen
  into a folder of the scope. The new screen names its folder, so it lands
  inside the scope.
- **Notes.** Read and write the notes about their own screens, about playlists
  and about nothing.

Content (media, playlists, applications, cards, card data) stays governed by
the member's role, exactly as for any member.

A limited person reaches no project administration: members, invitations,
service clients, agent sign-ins, fleet links, billing, settings, webhooks,
notifications, alerts, triggers, schedule imports and project-wide reports are
refused. Each answers `outside_screen_scope`.

### A campaign is editable only inside the scope

A campaign is listed to everyone, and a limited person edits it only when its
whole audience is inside their scope. Otherwise `editable` is `false` and the
campaign is read-only to them.

- A folder or screen in the scope is inside it.
- An `any` rule is inside when every child is.
- An `all` rule is inside when at least one child is, because it is an
  intersection.
- A tag rule, and the rule for every screen, are never inside.

### A limited person who cannot approve

A limited member who cannot approve reviews reads everything in the scope and
runs commands, screenshots and comments, and changes what plays only through an
approver. Assigning a playlist, schedules, takeovers, campaigns, folders and
moves answer `approver_required` for them. A member without a scope is
unchanged.

## What is outside the scope

Screens outside the scope are hidden from every list: the screens list, a
folder's screens, campaign screens, the calendar, events and the live stream.
The folder tree shows the scope's folders and the folders above them, read-only
and without a screen count, so the tree has a root. Their siblings are hidden.

A request that names a screen, folder, selector or audience outside the scope is
refused whole and never narrowed: nothing is written. An id outside the scope
and an id that does not exist get the same answer.

```json
{
  "status": 403,
  "errors": [
    {
      "code": "outside_screen_scope",
      "screen_scope": { "folder_ids": ["sfd_01LOBBY"], "screen_ids": [] },
      "hint": "Ask the project owner to widen the scope, or leave this to a member of the whole project."
    }
  ]
}
```

`screen_scope` names the caller's own scope, so the caller can tell what it may
use. Playback records, the calendar and the Player log take a screen of the
scope (the calendar also a folder). Project-wide health trend and daily uptime
are refused; the per-screen health history and uptime are open.

## Delegated administration

Give a venue manager their folders and let them run them:

1. The owner limits the manager to the venue's folders.
2. The owner turns on **Can approve** for the manager.
3. The manager assigns playlists, schedules and campaigns in their folders
   directly, and decides the [reviews](https://screenrig.ai/docs/agents.md#reviews)
   that agents propose for those folders.

An approver who is limited decides only a review whose whole reach is inside
their scope, and the Reviews page lists only those. A limited approver decides
no ad creative review. A review that reaches a screen outside the scope answers
`outside_screen_scope`.

## Protected folders

A protected folder is for screens where no single person changes what plays. A
person who can approve turns on **Protected** for a folder in the dashboard, and
the protection covers every folder inside it. Agents and service clients never
protect a folder, and an agent removes protection only as a proposal:
`screenrig screen folder update ID --unprotect` becomes a review that a second
approver decides. A limited approver protects folders inside their scope, not a
folder their scope names. A change that reaches a screen in a protected folder becomes a review
that a second approver decides, at every access level, Manage included.

An agent that assigns a playlist to a screen in a protected folder gets
`pending_review` and the review. The screen keeps playing what it played until a
second approver decides.

```sh
screenrig screen assign scr_01EXAMPLESCREEN000000000 --playlist-id pl_01WELCOME
screenrig reviews list --kind protected_change
screenrig reviews show rvw_01EXAMPLEREVIEW0000000000
```

What happens to a change depends on the change:

- **A review.** Assigning a playlist, setting or clearing a playlist schedule
  or a takeover, on one screen or a fleet, is a `screen_change` review. Creating,
  changing or deleting a campaign whose audience reaches a protected screen,
  creating a folder inside a protected folder, moving, deleting or setting the
  default playlist of a folder in or holding one, moving screens or folders into
  or out of one, and clearing protection are a `protected_change` review. The
  change is applied in the approving decision. A rename is live.
- **A refusal.** Tag, field, location, timezone and wall edits, replacing a
  screen, deleting, archiving, suspending, display power and its schedule, a play
  page, a toast, ad inventory, trigger targets and schedule imports that reach a
  protected screen answer `protected_target`. To make the change, an approver
  clears protection through a review, the change is made, and the folder is
  protected again. A trigger that fans out leaves protected screens as they are
  and counts them.
- **Open.** Resuming, unarchiving, rebooting, reloading, identifying,
  maintenance and screenshots stay open.

A review waits for a person other than the proposer and other than the person
responsible for the proposing agent or service client. The decision is refused
with `second_approver_required` when the decider is the same person. When the
project has only one approver, the refusal says to make another member an
approver. A change proposed before its folder was protected meets the rule when
it is approved. A review that has gone out of date while it waited answers
`review_stale`; propose the change again.

A project with no protected folder pays nothing for the rule.

## Reserved campaigns

A campaign marked **Reserved** is changed, paused, deleted or un-reserved only
by a person who can approve reviews: the owner, or an approver whose scope holds
the campaign's whole audience. A person turns on **Reserved** in the campaign's
form in the dashboard. Agents and service clients never change a reserved
campaign, at any access level, and their attempts answer `reserved_item`.
Reserve the campaign that carries a brand's fixed schedule, and a manager or an
agent cannot change it by accident.

## Tags are not scope

A scope is folders and single screens. Anyone who may change a screen can write
its tags, so a tag scope would let one manager extend their own reach or another
manager's. Use folders for ownership and tags for selection inside it.

A fleet action or campaign that selects by tag is refused to a limited person
whole, with `outside_screen_scope`, and the hint says to select by ids or by
folder.

## Agents

A limited agent works with the CLI the way a limited member does in the
dashboard.

```sh
screenrig agent status
screenrig screen list
screenrig screen folder list
screenrig screen pair "$PAIRING_CODE" --folder sfd_01LOBBY --name "Lobby entrance"
screenrig screen assign scr_01EXAMPLESCREEN000000000 --playlist-id pl_01WELCOME
screenrig screen folder update sfd_01LOBBY --unprotect
screenrig campaign show cmp_01EXAMPLECAMPAIGN0000000
```

- `agent status` shows the agent's `screen_scope` and the `person_screen_scope`
  of the person responsible for it.
- `screen list` and `screen folder list` hold only its screens and folders.
- `screen pair` takes `--folder` and needs a folder of the scope.
- `screen folder update ID --unprotect` proposes removing a folder's
  protection, sent alone. It becomes a review that a second approver decides.
- `campaign show` prints `editable` and `reserved`.
- With no project selected, `screen list` leaves out a project where the agent
  is limited. Select the project.

## Refusals and how to fix them

Every refusal names the way back in its `hint`.

| Problem | Status | When | Fix |
| --- | --- | --- | --- |
| [`outside_screen_scope`](https://screenrig.ai/problems/outside-screen-scope) | 403 | The screen, folder, selector, audience or route is outside the caller's scope | Use a screen or folder in `screen_scope`, or ask the project owner to widen the scope |
| `approver_required` | 403 | A limited member who cannot approve changes what plays, or an agent, a service client or a person who cannot approve protects a folder | Ask an approver to make the change, or ask the owner to turn on Can approve |
| [`protected_target`](https://screenrig.ai/problems/protected-target) | 409 | The change reaches a screen in a protected folder and has no review form | Ask an approver to clear protection through a review, make the change, protect the folder again |
| [`second_approver_required`](https://screenrig.ai/problems/second-approver-required) | 403 | The person deciding a protected review is the proposer or answers for the proposing agent | Ask another approver, or ask the owner to let another member approve reviews |
| [`reserved_item`](https://screenrig.ai/problems/reserved-item) | 403 | A reserved campaign is changed by someone who cannot approve, or by an agent or service client | Ask an approver to make the change or clear the flag |
| [`review_stale`](https://screenrig.ai/problems/review-stale) | 409 | The campaign, folder or screens a protected review was proposed against changed | Read them again and propose the change again |
| `resource_conflict` | 409 | A scope is set on the owner, on an uploader, on an approver with single screens, or while a service client of the person holds | Follow the hint: end the other limit, remove single screens, or revoke the named service clients |

A protected change that is accepted answers `202` with `status: pending_review`
and the review, the same answer a Propose agent gets. Follow it with
`screenrig reviews show ID`.

## Audit

Every change is an event in the project's log, written in the transaction that
makes the change:

| Event | When |
| --- | --- |
| `project.member_screen_scope_changed` | A member's scope is set, changed or ended |
| `agent.screen_scope_changed` | An agent's scope is set, changed or ended |
| `screen.folder_protection_changed` | A folder is protected or unprotected |
| `campaign.reserved_changed` | A campaign is reserved or unreserved |

Reviews write the usual `review.*` events, and the approving person is the actor
of what a review applies.

## API

The owner's routes take the dashboard session.

| Route | What it does |
| --- | --- |
| `PUT` and `DELETE /api/members/{user_id}/screen-scope` | Set or end a member's scope |
| `PUT` and `DELETE /api/agents/{id}/screen-scope` | Set or end an agent's scope |
| `PATCH /api/screen-folders/{id}` with `protected` | Protect a folder, sent alone |
| `POST /api/campaigns` and `PATCH /api/campaigns/{id}` with `reserved` | Reserve a campaign |

The [API reference](https://screenrig.ai/docs/api.md) lists every request, answer and
problem. The problems are in the [problem types](https://screenrig.ai/problems).

## Related

- [Authentication](https://screenrig.ai/docs/authentication.md): access levels, review settings and uploaders.
- [Agents](https://screenrig.ai/docs/agents.md#reviews): how reviews work for an agent's changes.
- [Signage CLI](https://screenrig.ai/docs/cli.md#screen-folders): screen folders and fleet commands.
- [Service clients](https://screenrig.ai/docs/service-clients.md): credentials for servers and CI jobs.
