> ## Documentation Index
> Fetch the complete documentation index at: https://wiki.aclid.bio/llms.txt
> Use this file to discover all available pages before exploring further.

# Roles and sites

> Organization roles, module visibility, and the two site-level access models.

Every operation is scoped to the caller's organization (see [Authentication](/api/authentication)). Within an organization, three further layers decide what a caller can see and do.

## Organization roles

Every user is either an **Admin** or a **Member** of their organization. The role is determined per request from the authenticated user.

Admin-only operations fail for members with an error instead of returning partial data.

Other operations branch rather than refuse. For instance `incidents` and `incidentMetrics` return every incident to an admin, but only the incidents a member created, is involved in, or witnessed; and `Incident.actions` is filtered to the actions assigned to the member.

## Module visibility

The `navigation` query returns the modules a user should see. A module is included when **both** of the following hold:

1. The module is enabled for the organization.
2. The module's condition, if it has one, passes for the caller.

| Module | Slug | Condition |
| - | - | - |
| Dashboard | ` ` (a single space) | none |
| Inventory | `inventory` | none |
| Equipment | `equipment` | none |
| Procedures | `procedures` | none |
| Incidents | `incidents` | none |
| Training | `trainings` | none |
| Calendar | `calendar` | Admin |
| Inspections | `inspections` | Admin |
| Reports | `reports` | Admin |
| Permits | `permits` | Admin |
| IBC | `ibc-projects` | Admin, or the caller is the investigator on at least one IBC project in the organization |
| Waste tracking | `waste` | Admin, in organizations where Aclid has enabled waste tracking |

Visibility in the navigation controls what appears in the app for that user.

## Site scope

Some data is tied to a **site**: a `Location` with `isSite: true`. Users can be assigned to sites with a per-site role of `admin` or `member` (exposed by `me.locationAssignments`).

* A caller with **no** site assignments in the organization is *unrestricted*: they read org-wide and their effective role is their organization role.
* A caller with **one or more** assignments is *restricted*: they only reach records that belong to their assigned sites, with the role they hold at that site.

Site scope is **default-deny** for the records it covers. A record with no location matches no site, so restricted callers can neither see nor write it; unrestricted callers may. Omitting a `siteId` argument narrows a restricted caller to all their assigned sites rather than widening the result, and passing a `siteId` they are not assigned to fails with `Unauthorized`.

Today site scope applies to equipment: `equipmentList`, `equipment`, `equipmentMetrics` and `equipmentStatusChanges` are filtered, and `createEquipment`, `editEquipment`, `uploadEquipmentManual` and the maintenance-schedule mutations require access to the equipment's site. Any assigned role (admin or member) may write inside its own scope; site assignments decide *which* records a caller can touch, not whether they may write at all. The `sites` query is narrowed to the caller's assigned sites so a site picker never offers a site the equipment reads would reject.

Actions inherit the permissions of what they hang off. `editAction` and `deleteAction` are allowed for an organization Admin, or for the admin of the site owning the equipment when the action is linked to an equipment event. Every other action requires an organization Admin.

## Site restriction

Protocols, policies and trainings use a different, **default-allow** model. A document with no site restrictions is visible to everyone, everywhere. A document restricted to one or more sites is hidden from a caller when none of the sites "in view" match:

* The `siteId` argument (the site selected in the header) narrows the view to that site; a restricted caller may only select a site they are assigned to.
* With no `siteId`, a restricted caller's view is their assigned sites, and an unrestricted caller's view is every site, so nothing is hidden.

Training refreshers carry no site restrictions of their own and inherit the restriction of the training they follow. When a training is assigned to groups, members whose site assignments do not intersect the training's sites are skipped (a user with no assignments is never skipped), and `assignTrainingToGroups` returns the number skipped as `skippedMemberCount`. The `siteNames` fields list the sites a document is restricted to; a document pinned to every site in the organization returns an empty list, which the app renders as "All".

Restriction site ids must be sites (`isSite: true`) in the caller's organization, otherwise the mutation fails.

## Org-wide admin

Changing *who else* can see a document is reserved for callers whose view of `sites` is complete. `setProtocolSites`, `setPolicySites` and `setTrainingSites` require an **org-wide admin**: the caller must be an Admin **and** have no site assignments. A site-restricted admin fails this check with `Unauthorized: requires org-wide admin`, because their editor never shows the full site list and a replace-set write from them would silently drop sites they cannot see.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.