Docyrus ACL Design
Configure tenant access control with docyrus acl, then validate the setup before handing it off. The Docyrus ACL system has five concepts:
| Concept |
What it is |
| Role |
Named permission group assigned to users |
| Hierarchy Unit |
Org-tree node for org-chart-aware row-level security (RLS) |
| Role Query |
Row-level filter attached to one or more roles for a data source |
| Operation |
System-defined permission slug (read-only — you can't create these) |
| Rule |
Binds a role to a target (data source / app / AI tool / settings) with a list of allowed operation slugs |
For platform concepts see the docyrus-platform skill. For CLI flag tables see the docyrus-cli-app skill. This skill is the ACL-specific workflow.
Workflow
Follow in order. A role without rules grants nothing useful.
Confirm auth.
docyrus auth who --json # confirm session + tenant
No session → stop and ask the user to run docyrus auth login.
Survey available operations. Before creating rules, know which operations exist per target type:
docyrus acl operations list --targetType data_source --json
docyrus acl operations list --targetType settings --json
docyrus acl operations list --targetType devtools --json
The full catalog is in references/operation-catalog.md.
Create roles. See Roles. One role per logical access level (e.g. "Viewer", "Editor", "Admin"). If the role is app-scoped pass --tenantAppId.
Create hierarchy units (skip if org-chart RLS is not needed). See Hierarchy Units. Build parent units before children.
Create role queries (skip if row-level record filtering is not needed). See Role Queries. Each role query narrows which records a role can see in a specific data source.
Create rules. Each rule grants a role a set of operations on one specific target. See Rules. Start with data_source rules, then settings, devtools, app, ai_tool as needed.
Validate. Re-read each object to confirm it landed with the right values. See Validate.
A full worked example (two-role CRM setup with data-source rules, a settings rule, and a role query) is in references/workflow-examples.md.
Roles
# List roles (optionally filter by name/slug)
docyrus acl roles list --json
docyrus acl roles list --search "editor" --json
# Get one role
docyrus acl roles get --roleId <uuid> --json
# Create a role
docyrus acl roles create --slug "crm-viewer" --name "CRM Viewer" --json
docyrus acl roles create --slug "crm-editor" --name "CRM Editor" \
--tenantAppId <app-uuid> --ownership CUSTOM --json
# Update a role (PATCH — any subset of fields)
docyrus acl roles update --roleId <uuid> --name "CRM Viewer (Read-Only)" --json
# Delete a role and all its assignments
docyrus acl roles delete --roleId <uuid> --json
Key fields:
--slug and --name are required on create.
--ownership ∈ SYSTEM | CUSTOM | APP | USER | PRODUCT (default CUSTOM).
--tenantAppId scopes the role to a specific app.
--disableLogin (int 0/1) prevents login when the user only holds this role.
--activitySummaryReportQueryId points to a custom query UUID for the role's activity summary dashboard.
--data '<json>' / --from-file ./payload.json override individual flags.
Hierarchy Units
Hierarchy units form an org-chart tree. Users are then assigned to units, and data-source data_access/unit_peer_access rules use that tree for RLS.
# List units (optionally filter by parent or name)
docyrus acl hierarchy-units list --json
docyrus acl hierarchy-units list --parentId <uuid> --json
docyrus acl hierarchy-units list --search "sales" --json
# Get one unit
docyrus acl hierarchy-units get --unitId <uuid> --json
# Create (build parents before children)
docyrus acl hierarchy-units create --name "Sales" --json
docyrus acl hierarchy-units create --name "Sales East" --parentId <sales-unit-uuid> --json
# Update
docyrus acl hierarchy-units update --unitId <uuid> --name "Sales West" --json
# Delete (fails if the unit has children — delete children first)
docyrus acl hierarchy-units delete --unitId <uuid> --json
--name is required on create.
--parentId is optional; omit for a root unit.
Role Queries
A role query is a DSQL-style filter object attached to one or more roles for a specific data source. Users whose active role matches are restricted to only the rows that match the query.
# List role queries
docyrus acl role-queries list --json
docyrus acl role-queries list --dataSourceId <uuid> --json
docyrus acl role-queries list --roleId <uuid> --json
docyrus acl role-queries list --restrictionLevel hidden --json
# Get one
docyrus acl role-queries get --roleQueryId <uuid> --json
# Create
docyrus acl role-queries create \
--roleIds "<role-uuid-1>,<role-uuid-2>" \
--dataSourceId <ds-uuid> \
--query '{"field":"status","operator":"eq","value":"active"}' \
--restrictionLevel "read-only" \
--json
# Update
docyrus acl role-queries update --roleQueryId <uuid> \
--query '{"field":"status","operator":"in","value":["active","pending"]}' --json
# Delete
docyrus acl role-queries delete --roleQueryId <uuid> --json
Key fields:
--roleIds comma-separated UUIDs — required on create.
--query JSON string of the filter object — required on create.
--dataSourceId scopes the query to one data source (optional — omit for a global filter).
--restrictionLevel ∈ hidden | read-only | not-deletable.
--filterChildRelations boolean — also apply the filter to child-relation queries.
Operations
Operations are system-defined and read-only — you can list them but cannot create, modify, or delete them.
# List all operations
docyrus acl operations list --json
# Filter by target type
docyrus acl operations list --targetType data_source --json
docyrus acl operations list --targetType settings --json
docyrus acl operations list --targetType devtools --json
docyrus acl operations list --targetType ai --json
docyrus acl operations list --targetType ai_tool --json
docyrus acl operations list --targetType field --json
# Search by name or slug
docyrus acl operations list --search "delete" --json
docyrus acl operations list --search "manage" --targetType settings --json
--targetType values: data_source, field, ai, settings, devtools, app, ai_tool.
The full operation catalog (slugs + names per target type) is in references/operation-catalog.md.
Rules
A rule grants a role a set of operations on exactly one target. One rule = one (role × target) binding.
# List rules
docyrus acl rules list --json
docyrus acl rules list --roleId <uuid> --json
docyrus acl rules list --targetType settings --json
docyrus acl rules list --dataSourceId <uuid> --json
docyrus acl rules list --appId <uuid> --json
docyrus acl rules list --aiToolId <uuid> --json
docyrus acl rules list --includeArchived --json # default: archived rules are hidden
# Get one rule
docyrus acl rules get --ruleId <uuid> --json
# Create a rule
# data_source target (default)
docyrus acl rules create \
--roleId <role-uuid> --dataSourceId <ds-uuid> \
--allowedOperations "view,create,edit,delete" --json
# settings target (no FK — omit dataSourceId/appId/aiToolId)
docyrus acl rules create \
--roleId <role-uuid> --targetType settings \
--allowedOperations "manage_users,manage_teams" --json
# devtools target
docyrus acl rules create \
--roleId <role-uuid> --targetType devtools \
--allowedOperations "cody,studio" --json
# ai_tool target
docyrus acl rules create \
--roleId <role-uuid> --targetType ai_tool --aiToolId <tool-uuid> \
--allowedOperations "allow" --json
# Update a rule (PATCH — supply only what changes)
docyrus acl rules update --ruleId <uuid> \
--allowedOperations "view,create,edit,delete,export" --json
# Archive a rule (soft disable — still visible with --includeArchived)
docyrus acl rules update --ruleId <uuid> --archived true --json
# Restore an archived rule
docyrus acl rules update --ruleId <uuid> --archived false --json
# Hard-delete a rule
docyrus acl rules delete --ruleId <uuid> --json
Key fields:
--roleId is required on create.
--targetType defaults to data_source; valid values: data_source, field, ai, settings, devtools, app, ai_tool.
--allowedOperations comma-separated list of operation slugs; must match real slugs for the target type.
- FK fields are mutually exclusive per rule row: set
--dataSourceId for data_source targets, --appId for app targets, --aiToolId for ai_tool targets. Leave all three null for settings, devtools, ai, field targets.
Critical rules
- All payload keys are camelCase.
--roleId, --dataSourceId, --allowedOperations, --roleIds, --targetType — never snake_case. The backend ACL DTOs are camelCase and GlobalValidationPipe does NOT transform snake_case → camelCase.
- One rule per (role × target FK). A unique database constraint prevents two rules for the same
(tenant, role, dataSource), (tenant, role, app), or (tenant, role, aiTool). Attempting to create a duplicate returns a 500 constraint error. Check with rules list --roleId <id> first.
targetType defaults to data_source on rules create — always pass it explicitly when creating non-data-source rules to avoid accidentally creating a data_source rule with null FK.
--allowedOperations is comma-separated on the CLI — it becomes a string[] in the request. Spaces around commas are stripped.
--roleIds is comma-separated for role queries (same pattern).
--query must be a JSON string for role queries — wrap in single quotes: --query '{"field":"owner","operator":"eq","value":"{{userId}}"}'.
- Operations are read-only. You cannot create or modify
core_acl_operation rows — only a superadmin can. Use acl operations list to discover slugs; pass them into --allowedOperations.
- Hierarchy unit delete rejects units with children. Delete leaves first, then parents.
- Archive ≠ delete.
rules update --archived true soft-disables a rule (the row stays and is hidden from normal list results). rules delete hard-removes it. Prefer archive when you may want to restore later.
--targetType uses underscores (data_source, ai_tool), not hyphens.
--restrictionLevel for role queries uses hyphens (read-only, not-deletable), not underscores.
- Validate then test. After configuring roles + rules, log in as a user with that role and confirm the access behaves as expected.
Validate
After authoring, confirm each object landed correctly:
Roles:
docyrus acl roles list --json # count matches
docyrus acl roles get --roleId <id> --json # slug, name, ownership, tenantAppId
Hierarchy units:
docyrus acl hierarchy-units list --json # tree structure
docyrus acl hierarchy-units list --parentId <id> --json # children of a node
Role queries:
docyrus acl role-queries list --roleId <id> --json # confirm query + restrictionLevel
Rules:
docyrus acl rules list --roleId <id> --json # all rules for the role
docyrus acl rules get --ruleId <id> --json # confirm allowedOperations, targetType, FK
Confirm allowed_operations matches the slugs you passed. Check target_type is correct and exactly one of tenant_data_source_id, tenant_app_id, tenant_ai_tool_id is set (rest null) for FK-targeted types.
References
- references/operation-catalog.md — All operation slugs grouped by target type, with display names and intended use.
- references/workflow-examples.md — End-to-end worked example: create two roles with data-source and settings rules, add a role query, validate, and test.
1---2name: docyrus-acl-design3description: Design, configure, and validate a Docyrus tenant ACL (Access Control Layer) end-to-end using the `docyrus acl` CLI commands. Use when the user wants to define permission roles, assign operation-level permissions to roles for data sources / apps / AI tools / settings / devtools, set up row-level record filters (role queries), build an organizational hierarchy (hierarchy units), or look up available system operations. Triggers on "create a role", "set permissions for a role", "grant access to a data source", "role query", "row-level filter", "hierarchy unit", "org-chart access", "acl rules", "what operations", `docyrus acl roles`, `docyrus acl rules`, `docyrus acl role-queries`, `docyrus acl hierarchy-units`, `docyrus acl operations`, or any ACL role/permission design + configuration task in Docyrus.4---5
6# Docyrus ACL Design
7
8Configure tenant access control with `docyrus acl`, then **validate** the setup before handing it off. The Docyrus ACL system has five concepts:
9
10| Concept | What it is |
11|---|---|
12| **Role** | Named permission group assigned to users |
13| **Hierarchy Unit** | Org-tree node for org-chart-aware row-level security (RLS) |
14| **Role Query** | Row-level filter attached to one or more roles for a data source |
15| **Operation** | System-defined permission slug (read-only — you can't create these) |
16| **Rule** | Binds a role to a target (data source / app / AI tool / settings) with a list of allowed operation slugs |
17
18For platform concepts see the **docyrus-platform** skill. For CLI flag tables see the **docyrus-cli-app** skill. This skill is the ACL-specific workflow.
19
20## Workflow
21
22Follow in order. A role without rules grants nothing useful.
23
241. **Confirm auth.**
25 ```bash
26 docyrus auth who --json # confirm session + tenant
27 ```
28 No session → stop and ask the user to run `docyrus auth login`.
29
302. **Survey available operations.** Before creating rules, know which operations exist per target type:
31 ```bash
32 docyrus acl operations list --targetType data_source --json
33 docyrus acl operations list --targetType settings --json
34 docyrus acl operations list --targetType devtools --json
35 ```
36 The full catalog is in [references/operation-catalog.md](references/operation-catalog.md).
37
383. **Create roles.** See [Roles](#roles). One role per logical access level (e.g. "Viewer", "Editor", "Admin"). If the role is app-scoped pass `--tenantAppId`.
39
404. **Create hierarchy units** (skip if org-chart RLS is not needed). See [Hierarchy Units](#hierarchy-units). Build parent units before children.
41
425. **Create role queries** (skip if row-level record filtering is not needed). See [Role Queries](#role-queries). Each role query narrows which records a role can see in a specific data source.
43
446. **Create rules.** Each rule grants a role a set of operations on one specific target. See [Rules](#rules). Start with `data_source` rules, then `settings`, `devtools`, `app`, `ai_tool` as needed.
45
467. **Validate.** Re-read each object to confirm it landed with the right values. See [Validate](#validate).
47
48A full worked example (two-role CRM setup with data-source rules, a settings rule, and a role query) is in [references/workflow-examples.md](references/workflow-examples.md).
49
50## Roles
51
52```bash
53# List roles (optionally filter by name/slug)
54docyrus acl roles list --json
55docyrus acl roles list --search "editor" --json
56
57# Get one role
58docyrus acl roles get --roleId <uuid> --json
59
60# Create a role
61docyrus acl roles create --slug "crm-viewer" --name "CRM Viewer" --json
62docyrus acl roles create --slug "crm-editor" --name "CRM Editor" \
63 --tenantAppId <app-uuid> --ownership CUSTOM --json
64
65# Update a role (PATCH — any subset of fields)
66docyrus acl roles update --roleId <uuid> --name "CRM Viewer (Read-Only)" --json
67
68# Delete a role and all its assignments
69docyrus acl roles delete --roleId <uuid> --json
70```
71
72Key fields:
73- `--slug` and `--name` are **required** on create.
74- `--ownership` ∈ `SYSTEM | CUSTOM | APP | USER | PRODUCT` (default `CUSTOM`).
75- `--tenantAppId` scopes the role to a specific app.
76- `--disableLogin` (int 0/1) prevents login when the user only holds this role.
77- `--activitySummaryReportQueryId` points to a custom query UUID for the role's activity summary dashboard.
78- `--data '<json>'` / `--from-file ./payload.json` override individual flags.
79
80## Hierarchy Units
81
82Hierarchy units form an org-chart tree. Users are then assigned to units, and data-source `data_access`/`unit_peer_access` rules use that tree for RLS.
83
84```bash
85# List units (optionally filter by parent or name)
86docyrus acl hierarchy-units list --json
87docyrus acl hierarchy-units list --parentId <uuid> --json
88docyrus acl hierarchy-units list --search "sales" --json
89
90# Get one unit
91docyrus acl hierarchy-units get --unitId <uuid> --json
92
93# Create (build parents before children)
94docyrus acl hierarchy-units create --name "Sales" --json
95docyrus acl hierarchy-units create --name "Sales East" --parentId <sales-unit-uuid> --json
96
97# Update
98docyrus acl hierarchy-units update --unitId <uuid> --name "Sales West" --json
99
100# Delete (fails if the unit has children — delete children first)
101docyrus acl hierarchy-units delete --unitId <uuid> --json
102```
103
104- `--name` is **required** on create.
105- `--parentId` is optional; omit for a root unit.
106
107## Role Queries
108
109A role query is a DSQL-style filter object attached to one or more roles for a specific data source. Users whose active role matches are restricted to only the rows that match the query.
110
111```bash
112# List role queries
113docyrus acl role-queries list --json
114docyrus acl role-queries list --dataSourceId <uuid> --json
115docyrus acl role-queries list --roleId <uuid> --json
116docyrus acl role-queries list --restrictionLevel hidden --json
117
118# Get one
119docyrus acl role-queries get --roleQueryId <uuid> --json
120
121# Create
122docyrus acl role-queries create \
123 --roleIds "<role-uuid-1>,<role-uuid-2>" \
124 --dataSourceId <ds-uuid> \
125 --query '{"field":"status","operator":"eq","value":"active"}' \
126 --restrictionLevel "read-only" \
127 --json
128
129# Update
130docyrus acl role-queries update --roleQueryId <uuid> \
131 --query '{"field":"status","operator":"in","value":["active","pending"]}' --json
132
133# Delete
134docyrus acl role-queries delete --roleQueryId <uuid> --json
135```
136
137Key fields:
138- `--roleIds` comma-separated UUIDs — **required** on create.
139- `--query` JSON string of the filter object — **required** on create.
140- `--dataSourceId` scopes the query to one data source (optional — omit for a global filter).
141- `--restrictionLevel` ∈ `hidden | read-only | not-deletable`.
142- `--filterChildRelations` boolean — also apply the filter to child-relation queries.
143
144## Operations
145
146Operations are system-defined and **read-only** — you can list them but cannot create, modify, or delete them.
147
148```bash
149# List all operations
150docyrus acl operations list --json
151
152# Filter by target type
153docyrus acl operations list --targetType data_source --json
154docyrus acl operations list --targetType settings --json
155docyrus acl operations list --targetType devtools --json
156docyrus acl operations list --targetType ai --json
157docyrus acl operations list --targetType ai_tool --json
158docyrus acl operations list --targetType field --json
159
160# Search by name or slug
161docyrus acl operations list --search "delete" --json
162docyrus acl operations list --search "manage" --targetType settings --json
163```
164
165`--targetType` values: `data_source`, `field`, `ai`, `settings`, `devtools`, `app`, `ai_tool`.
166The full operation catalog (slugs + names per target type) is in [references/operation-catalog.md](references/operation-catalog.md).
167
168## Rules
169
170A rule grants a role a set of operations on exactly one target. One rule = one (role × target) binding.
171
172```bash
173# List rules
174docyrus acl rules list --json
175docyrus acl rules list --roleId <uuid> --json
176docyrus acl rules list --targetType settings --json
177docyrus acl rules list --dataSourceId <uuid> --json
178docyrus acl rules list --appId <uuid> --json
179docyrus acl rules list --aiToolId <uuid> --json
180docyrus acl rules list --includeArchived --json # default: archived rules are hidden
181
182# Get one rule
183docyrus acl rules get --ruleId <uuid> --json
184
185# Create a rule
186# data_source target (default)
187docyrus acl rules create \
188 --roleId <role-uuid> --dataSourceId <ds-uuid> \
189 --allowedOperations "view,create,edit,delete" --json
190
191# settings target (no FK — omit dataSourceId/appId/aiToolId)
192docyrus acl rules create \
193 --roleId <role-uuid> --targetType settings \
194 --allowedOperations "manage_users,manage_teams" --json
195
196# devtools target
197docyrus acl rules create \
198 --roleId <role-uuid> --targetType devtools \
199 --allowedOperations "cody,studio" --json
200
201# ai_tool target
202docyrus acl rules create \
203 --roleId <role-uuid> --targetType ai_tool --aiToolId <tool-uuid> \
204 --allowedOperations "allow" --json
205
206# Update a rule (PATCH — supply only what changes)
207docyrus acl rules update --ruleId <uuid> \
208 --allowedOperations "view,create,edit,delete,export" --json
209
210# Archive a rule (soft disable — still visible with --includeArchived)
211docyrus acl rules update --ruleId <uuid> --archived true --json
212
213# Restore an archived rule
214docyrus acl rules update --ruleId <uuid> --archived false --json
215
216# Hard-delete a rule
217docyrus acl rules delete --ruleId <uuid> --json
218```
219
220Key fields:
221- `--roleId` is **required** on create.
222- `--targetType` defaults to `data_source`; valid values: `data_source`, `field`, `ai`, `settings`, `devtools`, `app`, `ai_tool`.
223- `--allowedOperations` comma-separated list of operation slugs; must match real slugs for the target type.
224- FK fields are mutually exclusive per rule row: set `--dataSourceId` for `data_source` targets, `--appId` for `app` targets, `--aiToolId` for `ai_tool` targets. Leave all three null for `settings`, `devtools`, `ai`, `field` targets.
225
226## Critical rules
227
228- **All payload keys are camelCase.** `--roleId`, `--dataSourceId`, `--allowedOperations`, `--roleIds`, `--targetType` — never snake_case. The backend ACL DTOs are camelCase and `GlobalValidationPipe` does NOT transform snake_case → camelCase.
229- **One rule per (role × target FK).** A unique database constraint prevents two rules for the same `(tenant, role, dataSource)`, `(tenant, role, app)`, or `(tenant, role, aiTool)`. Attempting to create a duplicate returns a 500 constraint error. Check with `rules list --roleId <id>` first.
230- **`targetType` defaults to `data_source`** on `rules create` — always pass it explicitly when creating non-data-source rules to avoid accidentally creating a `data_source` rule with null FK.
231- **`--allowedOperations` is comma-separated** on the CLI — it becomes a `string[]` in the request. Spaces around commas are stripped.
232- **`--roleIds` is comma-separated** for role queries (same pattern).
233- **`--query` must be a JSON string** for role queries — wrap in single quotes: `--query '{"field":"owner","operator":"eq","value":"{{userId}}"}'`.
234- **Operations are read-only.** You cannot create or modify `core_acl_operation` rows — only a superadmin can. Use `acl operations list` to discover slugs; pass them into `--allowedOperations`.
235- **Hierarchy unit delete rejects units with children.** Delete leaves first, then parents.
236- **Archive ≠ delete.** `rules update --archived true` soft-disables a rule (the row stays and is hidden from normal list results). `rules delete` hard-removes it. Prefer archive when you may want to restore later.
237- **`--targetType` uses underscores** (`data_source`, `ai_tool`), not hyphens.
238- **`--restrictionLevel` for role queries uses hyphens** (`read-only`, `not-deletable`), not underscores.
239- **Validate then test.** After configuring roles + rules, log in as a user with that role and confirm the access behaves as expected.
240
241## Validate
242
243After authoring, confirm each object landed correctly:
244
2451. **Roles:**
246 ```bash
247 docyrus acl roles list --json # count matches
248 docyrus acl roles get --roleId <id> --json # slug, name, ownership, tenantAppId
249 ```
250
2512. **Hierarchy units:**
252 ```bash
253 docyrus acl hierarchy-units list --json # tree structure
254 docyrus acl hierarchy-units list --parentId <id> --json # children of a node
255 ```
256
2573. **Role queries:**
258 ```bash
259 docyrus acl role-queries list --roleId <id> --json # confirm query + restrictionLevel
260 ```
261
2624. **Rules:**
263 ```bash
264 docyrus acl rules list --roleId <id> --json # all rules for the role
265 docyrus acl rules get --ruleId <id> --json # confirm allowedOperations, targetType, FK
266 ```
267 Confirm `allowed_operations` matches the slugs you passed. Check `target_type` is correct and exactly one of `tenant_data_source_id`, `tenant_app_id`, `tenant_ai_tool_id` is set (rest null) for FK-targeted types.
268
269## References
270
271- **[references/operation-catalog.md](references/operation-catalog.md)** — All operation slugs grouped by target type, with display names and intended use.
272- **[references/workflow-examples.md](references/workflow-examples.md)** — End-to-end worked example: create two roles with data-source and settings rules, add a role query, validate, and test.