@zealamic/payload-auth-rbac-plugin 1.0.0-beta.1 → 1.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +27 -31
  2. package/assets/cover-photo.jpg +0 -0
  3. package/dist/collections/permission-actions/default-data.d.ts +2 -0
  4. package/dist/collections/permission-actions/index.d.ts +3 -0
  5. package/dist/collections/permission-actions/types.d.ts +51 -0
  6. package/dist/collections/permission-features/default-data.d.ts +2 -0
  7. package/dist/collections/permission-features/index.d.ts +3 -0
  8. package/dist/collections/permission-features/types.d.ts +43 -0
  9. package/dist/collections/permissions/default-data.d.ts +2 -0
  10. package/dist/collections/permissions/index.d.ts +3 -0
  11. package/dist/collections/permissions/types.d.ts +54 -0
  12. package/dist/collections/roles/default-data.d.ts +2 -0
  13. package/dist/collections/roles/hooks/sync-permission-matrix-draft.d.ts +6 -0
  14. package/dist/collections/roles/index.d.ts +3 -0
  15. package/dist/collections/roles/types.d.ts +53 -0
  16. package/dist/collections/roles-permissions/default-data.d.ts +2 -0
  17. package/dist/collections/roles-permissions/index.d.ts +3 -0
  18. package/dist/collections/roles-permissions/types.d.ts +39 -0
  19. package/dist/collections/users/default-data.d.ts +2 -0
  20. package/dist/collections/users/index.d.ts +3 -0
  21. package/dist/collections/users/parent-path.d.ts +31 -0
  22. package/dist/collections/users/types.d.ts +23 -0
  23. package/dist/components/role-permission-matrix-client/default-data.d.ts +2 -0
  24. package/dist/components/role-permission-matrix-client/default-data.js +2 -1
  25. package/dist/components/role-permission-matrix-client/default-data.js.map +1 -1
  26. package/dist/components/role-permission-matrix-client/index.d.ts +1 -0
  27. package/dist/components/role-permission-matrix-client/index.js +18 -68
  28. package/dist/components/role-permission-matrix-client/index.js.map +1 -1
  29. package/dist/components/role-permission-matrix-client/matrix.module.scss +69 -0
  30. package/dist/components/role-permission-matrix-client/types.d.ts +18 -0
  31. package/dist/endpoints/customEndpointHandler.d.ts +2 -0
  32. package/dist/exports/client.d.ts +1 -0
  33. package/dist/exports/rsc.d.ts +1 -0
  34. package/dist/index.d.ts +5 -0
  35. package/dist/lib/constants/general.d.ts +1 -0
  36. package/dist/lib/constants/index.d.ts +14 -0
  37. package/dist/lib/constants/permission-action.d.ts +8 -0
  38. package/dist/lib/constants/permission-feature.d.ts +4 -0
  39. package/dist/lib/constants/permission.d.ts +4 -0
  40. package/dist/lib/constants/role.d.ts +9 -0
  41. package/dist/lib/constants/user.d.ts +1 -0
  42. package/dist/lib/utils/access.d.ts +76 -0
  43. package/dist/lib/utils/data.d.ts +6 -0
  44. package/dist/lib/utils/fields.d.ts +18 -0
  45. package/dist/lib/utils/index.d.ts +4 -0
  46. package/dist/lib/utils/localization.d.ts +27 -0
  47. package/dist/styles/variables.scss +1 -0
  48. package/dist/types.d.ts +38 -0
  49. package/docs/COLLECTIONS.md +440 -0
  50. package/docs/TRANSLATIONS.md +462 -0
  51. package/docs/UTILS.md +226 -0
  52. package/package.json +21 -4
@@ -0,0 +1,462 @@
1
+ # Translations guide
2
+
3
+ Customize Admin labels, placeholders, select options, and permission-matrix UI text via the plugin `translations` option.
4
+
5
+ ```ts
6
+ import type { RBACTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
7
+ import { payloadAuthRbacPlugin } from "@zealamic/payload-auth-rbac-plugin";
8
+
9
+ export default buildConfig({
10
+ i18n: {
11
+ supportedLanguages: { en, vi },
12
+ fallbackLanguage: "en",
13
+ },
14
+ plugins: [
15
+ payloadAuthRbacPlugin({
16
+ translations: {
17
+ en: {
18
+ /* partial overrides OK */
19
+ },
20
+ vi: {
21
+ /* provide full strings for vi */
22
+ },
23
+ },
24
+ }),
25
+ ],
26
+ });
27
+ ```
28
+
29
+ ---
30
+
31
+ ## How it works
32
+
33
+ Translations are used in **two places**:
34
+
35
+ | Layer | What it affects |
36
+ | ------------------------------ | ------------------------------------------------------------------------------------ |
37
+ | **Collection config** | Sidebar group, collection labels, field labels, placeholders, select option labels |
38
+ | **`config.i18n.translations`** | Permission matrix UI (`useTranslation` keys under `components.rolePermissionMatrix`) |
39
+
40
+ **Merge order when the plugin loads:**
41
+
42
+ ```
43
+ Plugin English defaults
44
+ → deep-merge your pluginOptions.translations
45
+ → deep-merge into existing config.i18n.translations
46
+ ```
47
+
48
+ You only pass RBAC strings to **`payloadAuthRbacPlugin({ translations })`**. The plugin registers them into Payload i18n automatically — do **not** duplicate the same keys in `config.i18n.translations`.
49
+
50
+ Your project's `config.i18n` still owns:
51
+
52
+ - `supportedLanguages`
53
+ - `fallbackLanguage`
54
+ - Non-RBAC app strings (optional)
55
+
56
+ ### Locale merge behavior
57
+
58
+ | Locale | Behavior |
59
+ | ----------------- | ------------------------------------------------------------------------------------------------------------ |
60
+ | `en` | Partial overrides OK — missing keys inherit plugin English defaults |
61
+ | Other (e.g. `vi`) | **No** auto-fill from `en` — provide complete strings for that locale, or rely on Payload `fallbackLanguage` |
62
+
63
+ ### Serializable values only (Payload 3 / Next.js)
64
+
65
+ Use **plain strings** (and nested objects of strings) only:
66
+
67
+ ```ts
68
+ // ✅
69
+ labels: { singular: "Role", plural: "Roles" }
70
+
71
+ // ❌ functions, i18n library calls, class instances
72
+ labels: { singular: () => "Role" }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Config shape
78
+
79
+ Top-level keys = **locale codes** (`en`, `vi`, …). Must match `i18n.supportedLanguages`.
80
+
81
+ ```ts
82
+ type RBACTranslations = {
83
+ [locale: string]: {
84
+ collections?: {
85
+ permissionActions?: CollectionTranslations;
86
+ permissionFeatures?: CollectionTranslations;
87
+ permissions?: CollectionTranslations;
88
+ roles?: CollectionTranslations;
89
+ rolesPermissions?: CollectionTranslations;
90
+ users?: UsersFieldTranslations; // fields only
91
+ };
92
+ components?: {
93
+ rolePermissionMatrix?: MatrixTranslations;
94
+ };
95
+ };
96
+ };
97
+ ```
98
+
99
+ ### Collection config keys (camelCase)
100
+
101
+ | Config key | Collection slug |
102
+ | -------------------- | -------------------------------------- |
103
+ | `permissionActions` | `permission-actions` |
104
+ | `permissionFeatures` | `permission-features` |
105
+ | `permissions` | `permissions` |
106
+ | `roles` | `roles` |
107
+ | `rolesPermissions` | `roles-permissions` |
108
+ | `users` | Your auth collection (plugin-modified) |
109
+
110
+ Every collection block supports:
111
+
112
+ ```ts
113
+ {
114
+ labels?: { singular?: string; plural?: string };
115
+ admin?: { group?: string };
116
+ fields?: { [fieldName]: FieldTranslation };
117
+ }
118
+ ```
119
+
120
+ ### Common field keys
121
+
122
+ | Key | Used on |
123
+ | ------------- | -------------------- |
124
+ | `label` | All fields |
125
+ | `placeholder` | Text, number, select |
126
+
127
+ ### Select option labels
128
+
129
+ Pattern: **`{value}Label`** where `{value}` is the stored option value.
130
+
131
+ ```ts
132
+ // status: active | inactive
133
+ status: {
134
+ label: "Status",
135
+ placeholder: "Select status",
136
+ activeLabel: "Active",
137
+ inactiveLabel: "Inactive",
138
+ }
139
+
140
+ // permission-actions type: main | sub
141
+ type: {
142
+ mainLabel: "Main",
143
+ subLabel: "Sub",
144
+ }
145
+
146
+ // roles dataScope: own | hierarchy | all
147
+ dataScope: {
148
+ ownLabel: "Own",
149
+ hierarchyLabel: "Hierarchy",
150
+ allLabel: "All",
151
+ }
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Per-collection field keys
157
+
158
+ All keys are optional. Defaults live in `src/collections/*/default-data.ts`.
159
+
160
+ ### `permissionActions`
161
+
162
+ | Field | Keys |
163
+ | ----------- | ------------------------------------------------------ |
164
+ | `code` | `label`, `placeholder` |
165
+ | `type` | `label`, `placeholder`, `mainLabel`, `subLabel` |
166
+ | `sortOrder` | `label`, `placeholder` |
167
+ | `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
168
+
169
+ ### `permissionFeatures`
170
+
171
+ | Field | Keys |
172
+ | ----------- | ------------------------------------------------------ |
173
+ | `code` | `label`, `placeholder` |
174
+ | `sortOrder` | `label`, `placeholder` |
175
+ | `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
176
+
177
+ ### `permissions`
178
+
179
+ | Field | Keys |
180
+ | ------------------- | ------------------------------------------------------ |
181
+ | `name` | `label`, `placeholder` |
182
+ | `permissionFeature` | `label`, `placeholder` |
183
+ | `permissionAction` | `label`, `placeholder` |
184
+ | `sortOrder` | `label`, `placeholder` |
185
+ | `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
186
+
187
+ ### `roles`
188
+
189
+ | Field | Keys |
190
+ | ----------------------------- | -------------------------------------------------------------------------------- |
191
+ | `code`, `name`, `description` | `label`, `placeholder` |
192
+ | `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
193
+ | `dataScope` | `label`, `placeholder`, `ownLabel`, `hierarchyLabel`, `allLabel` |
194
+ | `permissionMatrix` | `label`, `placeholder` — **label only** for schema field `permissionMatrixDraft` |
195
+
196
+ > **Field name vs translation key:** schema field = `permissionMatrixDraft`; translation key = `permissionMatrix`. For `collections.roles.fields` overrides, use schema name `permissionMatrixDraft`.
197
+
198
+ ### `rolesPermissions`
199
+
200
+ | Field | Keys |
201
+ | -------------------- | ---------------------- |
202
+ | `role`, `permission` | `label`, `placeholder` |
203
+ | `enabled` | `label`, `placeholder` |
204
+
205
+ ### `users` (fields only)
206
+
207
+ | Field | Keys |
208
+ | -------------- | ---------------------- |
209
+ | `isSuperAdmin` | `label` |
210
+ | `roles` | `label`, `placeholder` |
211
+ | `parent` | `label`, `placeholder` |
212
+
213
+ No collection `labels` — the users collection belongs to your app.
214
+
215
+ ---
216
+
217
+ ## Permission matrix UI
218
+
219
+ **Config path:** `translations.<locale>.components.rolePermissionMatrix`
220
+
221
+ Registered as Payload i18n keys: `components:rolePermissionMatrix:…`
222
+
223
+ | Key | Description |
224
+ | ------------------------------ | --------------------------------------------------------------- |
225
+ | `title` | Matrix heading |
226
+ | `viewInUpdateScreenOnly.label` | Shown on create screen |
227
+ | `loading.placeholder` | Loading state |
228
+ | `features.label` | Features column header |
229
+ | `features.{code}` | Label for main feature with matching `permission-features.code` |
230
+ | `actions.label` | Actions column header |
231
+ | `actions.{code}` | Label for main action with matching `permission-actions.code` |
232
+
233
+ ### Features (dynamic)
234
+
235
+ The matrix resolves feature row labels via:
236
+
237
+ ```
238
+ components:rolePermissionMatrix:features:{featureCode}
239
+ ```
240
+
241
+ `{featureCode}` must match **`permission-features.code` exactly** (case-sensitive).
242
+
243
+ Add one key per feature code under `translations.<locale>.components.rolePermissionMatrix.features`:
244
+
245
+ ```ts
246
+ payloadAuthRbacPlugin({
247
+ translations: {
248
+ en: {
249
+ components: {
250
+ rolePermissionMatrix: {
251
+ features: {
252
+ label: "Features",
253
+ users: "Users", // permission-features.code = "users" (plugin default)
254
+ posts: "Posts", // permission-features.code = "posts"
255
+ },
256
+ },
257
+ },
258
+ },
259
+ },
260
+ });
261
+ ```
262
+
263
+ If a key is missing, the UI falls back to `feature.id` (not `feature.code`).
264
+
265
+ ### Main action labels (dynamic)
266
+
267
+ Main actions (`type: "main"`) resolve checkbox labels via:
268
+
269
+ ```
270
+ components:rolePermissionMatrix:actions:{actionCode}
271
+ ```
272
+
273
+ `{actionCode}` must match **`permission-actions.code` exactly**.
274
+
275
+ ```ts
276
+ payloadAuthRbacPlugin({
277
+ translations: {
278
+ en: {
279
+ components: {
280
+ rolePermissionMatrix: {
281
+ actions: {
282
+ label: "Actions",
283
+ create: "Create", // permission-actions.code = "create" (plugin default)
284
+ read: "Read",
285
+ update: "Update",
286
+ delete: "Delete",
287
+ publish: "Publish", // permission-actions.code = "publish" (custom)
288
+ },
289
+ },
290
+ },
291
+ },
292
+ },
293
+ });
294
+ ```
295
+
296
+ If a key is missing, the UI falls back to `action.id` (not `action.code`).
297
+
298
+ ### Sub-action labels (limitation)
299
+
300
+ Sub-actions (`type: "sub"`) **do not** use `useTranslation` — the UI shows raw `permission-actions.code`.
301
+
302
+ **Workaround:** use readable codes when creating sub-actions (`approveDraft`, not `ad`).
303
+
304
+ ---
305
+
306
+ ## Examples
307
+
308
+ ### Partial English override
309
+
310
+ ```ts
311
+ payloadAuthRbacPlugin({
312
+ translations: {
313
+ en: {
314
+ collections: {
315
+ permissionActions: {
316
+ admin: { group: "Access Control" },
317
+ fields: {
318
+ code: {
319
+ label: "Action Code",
320
+ placeholder: "e.g. create, read, update, delete",
321
+ },
322
+ },
323
+ },
324
+ roles: {
325
+ fields: {
326
+ permissionMatrix: { label: "Permission Matrix" },
327
+ },
328
+ },
329
+ },
330
+ components: {
331
+ rolePermissionMatrix: {
332
+ title: "Permission Matrix",
333
+ },
334
+ },
335
+ },
336
+ },
337
+ });
338
+ ```
339
+
340
+ ### Bilingual (`en` + `vi`)
341
+
342
+ ```ts
343
+ import { en } from "@payloadcms/translations/languages/en";
344
+ import { vi } from "@payloadcms/translations/languages/vi";
345
+
346
+ export default buildConfig({
347
+ i18n: {
348
+ supportedLanguages: { en, vi },
349
+ fallbackLanguage: "en",
350
+ },
351
+ plugins: [
352
+ payloadAuthRbacPlugin({
353
+ translations: {
354
+ en: {
355
+ collections: {
356
+ roles: { labels: { singular: "Role", plural: "Roles" } },
357
+ },
358
+ },
359
+ vi: {
360
+ collections: {
361
+ permissionActions: {
362
+ labels: { singular: "Quyền thao tác", plural: "Quyền thao tác" },
363
+ admin: { group: "Hệ thống" },
364
+ fields: {
365
+ code: { label: "Mã quyền thao tác" },
366
+ status: {
367
+ activeLabel: "Hoạt động",
368
+ inactiveLabel: "Ngừng hoạt động",
369
+ },
370
+ },
371
+ },
372
+ roles: {
373
+ labels: { singular: "Vai trò", plural: "Vai trò" },
374
+ fields: {
375
+ permissionMatrix: { label: "Ma trận quyền" },
376
+ dataScope: {
377
+ ownLabel: "Của mình",
378
+ hierarchyLabel: "Phân cấp",
379
+ allLabel: "Tất cả",
380
+ },
381
+ },
382
+ },
383
+ users: {
384
+ fields: {
385
+ isSuperAdmin: { label: "Siêu quản trị" },
386
+ roles: { label: "Vai trò" },
387
+ parent: { label: "Quản lý trực tiếp" },
388
+ },
389
+ },
390
+ },
391
+ components: {
392
+ rolePermissionMatrix: {
393
+ title: "Ma trận quyền",
394
+ loading: { placeholder: "Đang tải..." },
395
+ features: { label: "Tính năng" },
396
+ actions: {
397
+ label: "Hành động",
398
+ create: "Tạo",
399
+ read: "Xem",
400
+ update: "Sửa",
401
+ delete: "Xóa",
402
+ },
403
+ },
404
+ },
405
+ },
406
+ },
407
+ }),
408
+ ],
409
+ });
410
+ ```
411
+
412
+ Working demo: `dev/rbac.ts`.
413
+
414
+ ---
415
+
416
+ ## TypeScript
417
+
418
+ ```ts
419
+ import type { RBACTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
420
+
421
+ // Per-collection types (value for one locale):
422
+ import type { RolesCollectionTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
423
+ import type { RolePermissionMatrixClientTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
424
+ ```
425
+
426
+ ---
427
+
428
+ ## Default English strings
429
+
430
+ Shipped defaults (override via `translations.en`):
431
+
432
+ | Source file | Content |
433
+ | -------------------------------------------------------------- | --------------------- |
434
+ | `src/collections/permission-actions/default-data.ts` | Permission actions |
435
+ | `src/collections/permission-features/default-data.ts` | Permission features |
436
+ | `src/collections/permissions/default-data.ts` | Permissions |
437
+ | `src/collections/roles/default-data.ts` | Roles + dataScope |
438
+ | `src/collections/roles-permissions/default-data.ts` | Role permissions join |
439
+ | `src/collections/users/default-data.ts` | User fields |
440
+ | `src/components/role-permission-matrix-client/default-data.ts` | Matrix UI |
441
+
442
+ ---
443
+
444
+ ## Quick reference
445
+
446
+ | Goal | Path |
447
+ | ------------------------ | --------------------------------------------------------------------------- |
448
+ | Sidebar group | `translations.<locale>.collections.<key>.admin.group` |
449
+ | Collection name | `…labels.singular` / `…labels.plural` |
450
+ | Field label | `…fields.<fieldName>.label` |
451
+ | Select option | `…fields.<fieldName>.<value>Label` |
452
+ | Matrix title | `…components.rolePermissionMatrix.title` |
453
+ | Matrix action column | `…components.rolePermissionMatrix.actions.<code>` |
454
+ | Override field in schema | Use **schema field name** (`permissionMatrixDraft`, not `permissionMatrix`) |
455
+
456
+ ---
457
+
458
+ ## Related docs
459
+
460
+ - [README](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/README.md) — install and quick start
461
+ - [COLLECTIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/COLLECTIONS.md) — collection schemas and customization
462
+ - [UTILS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/UTILS.md) — access helpers
package/docs/UTILS.md ADDED
@@ -0,0 +1,226 @@
1
+ # Utils reference
2
+
3
+ This document lists only utilities that are currently exported.
4
+
5
+ Export sources:
6
+
7
+ - `@zealamic/payload-auth-rbac-plugin`
8
+ - `@zealamic/payload-auth-rbac-plugin/utils`
9
+
10
+ > Barrel file: `src/lib/utils/index.ts`
11
+
12
+ ---
13
+
14
+ ## Exported modules
15
+
16
+ `src/lib/utils/index.ts` exports from:
17
+
18
+ 1. `access`
19
+ 2. `data`
20
+ 3. `fields`
21
+ 4. `localization`
22
+
23
+ ---
24
+
25
+ ## Access exports
26
+
27
+ ### `type DataScopeOptions`
28
+
29
+ ```ts
30
+ type DataScopeOptions = {
31
+ createdByField?: string; // default: "createdBy"
32
+ usersCollectionSlug?: string; // default: "users"
33
+ };
34
+ ```
35
+
36
+ Use this to configure ownership field and users slug for hierarchy logic.
37
+
38
+ ### `getPermissionAccess({ featureCode, actionCode, mode?, collectionSlug?, options? })`
39
+
40
+ Unified access helper for Payload `access` config.
41
+
42
+ You can use one function for all common access cases:
43
+
44
+ - permission-only (`create`, `readVersions`, `unlock`, ...)
45
+ - read with data-scope filter
46
+ - modify (`update` / `delete`) with per-document scope check
47
+
48
+ Parameters:
49
+
50
+ - `featureCode` (`string`): feature code in `permission-features.code`
51
+ - `actionCode` (`string`): action code in `permission-actions.code`
52
+ - `mode` (`"none" | "modify"`, optional):
53
+ - `"none"` (default) = permission check only
54
+ - `"modify"` = check one target document by `id`
55
+ - `collectionSlug` (`string`, optional): required when `mode: "modify"`
56
+ - `options` (`DataScopeOptions`, optional): data-scope config
57
+
58
+ What it returns:
59
+
60
+ - In permission-only mode: Payload access function returning `boolean`
61
+ - In read-scope mode (`options` provided): Payload access function returning `boolean | Where`
62
+ - In modify mode: Payload access function returning `boolean`
63
+
64
+ ```ts
65
+ // 1) permission-only (best for create/readVersions/unlock/etc.)
66
+ create: getPermissionAccess({
67
+ featureCode: "posts",
68
+ actionCode: "create",
69
+ });
70
+
71
+ // 2) read + scope (read mode inferred when options exists)
72
+ read: getPermissionAccess({
73
+ featureCode: "posts",
74
+ actionCode: "read",
75
+ options: {
76
+ createdByField: "createdBy",
77
+ usersCollectionSlug: "users",
78
+ },
79
+ });
80
+
81
+ // 3) update/delete + document scope (requires mode + collectionSlug)
82
+ update: getPermissionAccess({
83
+ featureCode: "posts",
84
+ actionCode: "update",
85
+ mode: "modify",
86
+ collectionSlug: "posts",
87
+ options: { createdByField: "createdBy" },
88
+ });
89
+ ```
90
+
91
+ How it works internally:
92
+
93
+ 1. deny when `req.user` is missing
94
+ 2. allow immediately for super admin
95
+ 3. check RBAC by `featureCode` + `actionCode`
96
+ 4. if read-scope mode: return scope filter (`true` or `Where`)
97
+ 5. if modify mode: load target document by `id`, then enforce data scope
98
+
99
+ When to use each mode:
100
+
101
+ - **Permission-only**: operations that do not depend on document ownership/hierarchy
102
+ Example: `create`, `readVersions`, `unlock`
103
+ - **Read-scope**: list/read access that must be filtered by owner/hierarchy/all
104
+ - **Modify**: `update` and `delete` where permission depends on the specific document
105
+
106
+ Common mistakes to avoid:
107
+
108
+ - `mode: "modify"` without `collectionSlug` -> always denied
109
+ - expecting read-scope behavior without passing `options`
110
+ - `featureCode` / `actionCode` not matching values in your permission collections
111
+
112
+ ### `getSuperAdminAccess`
113
+
114
+ Allow only super admins.
115
+
116
+ ### `getAuthenticatedOrSuperAdminAccess`
117
+
118
+ Allow current document owner or super admin.
119
+
120
+ ### `resolveEffectiveDataScope(req, options?)`
121
+
122
+ Resolve effective scope from roles: `own | hierarchy | all`.
123
+ Widest scope wins: `all > hierarchy > own`.
124
+
125
+ ### `getHierarchyVisibleUserIds(req, options?)`
126
+
127
+ Return visible user IDs in hierarchy scope (self + descendants).
128
+
129
+ ### `getDataScopeReadWhere(req, options?)`
130
+
131
+ Build data-scope read filter as `Where | true`.
132
+
133
+ ### `isProtectedSuperAdminUserDoc(doc)`
134
+
135
+ Guard helper for user docs with `isSuperAdmin: true`.
136
+
137
+ ### `canAccessDocumentByDataScope({ req, doc, featureCode, actionCode, collectionSlug, options? })`
138
+
139
+ Low-level per-document RBAC + data-scope check.
140
+
141
+ ### `mergeDataScopeWhere(base, scopeWhere)`
142
+
143
+ Merge existing `where` with scope constraints.
144
+
145
+ ```ts
146
+ const scopeWhere = await getDataScopeReadWhere(req, {
147
+ createdByField: "createdBy",
148
+ });
149
+ const where = mergeDataScopeWhere(
150
+ { status: { equals: "published" } },
151
+ scopeWhere,
152
+ );
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Data exports
158
+
159
+ ### `toID(value)`
160
+
161
+ Normalize relationship/id values to string id.
162
+
163
+ ```ts
164
+ toID("507f1f77bcf86cd799439011"); // "507f1f77bcf86cd799439011"
165
+ toID({ id: "507f1f77bcf86cd799439011" }); // "507f1f77bcf86cd799439011"
166
+ toID(undefined); // ""
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Fields exports
172
+
173
+ ### `getMergedFieldAffectingData({ fields, defaultField })`
174
+
175
+ Merge one plugin default field with a user override by matching field name.
176
+
177
+ ### `getArrayOfMergedFieldAffectingData({ fields, defaultFields })`
178
+
179
+ Build final fields list:
180
+
181
+ - merge defaults by matching names
182
+ - append unmatched custom fields
183
+
184
+ ---
185
+
186
+ ## Localization exports
187
+
188
+ ### `toLocaleRecord(locales, getValue)`
189
+
190
+ Build `{ [locale]: string }` records from locale list.
191
+
192
+ ### `toSelectPlaceholder(locales, getValue)`
193
+
194
+ Build serializable select placeholders (safe across Payload v3 server/client boundary).
195
+
196
+ ### `getMergedTranslations({ defaultTranslations, translations })`
197
+
198
+ Deep-merge translation objects.
199
+
200
+ ### `getAllTranslationsOfSpecificObject({ translations, path, locales? })`
201
+
202
+ Extract nested translation branch by path (example: `"collections.roles"`).
203
+
204
+ ---
205
+
206
+ ## Commonly paired constant export
207
+
208
+ Not from `lib/utils`, but often used with access helpers:
209
+
210
+ ```ts
211
+ import { CONSTANTS } from "@zealamic/payload-auth-rbac-plugin";
212
+
213
+ CONSTANTS.ROLE.DATA_SCOPE;
214
+ CONSTANTS.ROLE.STATUS;
215
+ CONSTANTS.PERMISSION.STATUS;
216
+ CONSTANTS.PERMISSION_ACTION.TYPE;
217
+ CONSTANTS.USER.PARENT_PATH_SEPARATOR;
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Related docs
223
+
224
+ - [README](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/README.md) — install and quick start
225
+ - [COLLECTIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/COLLECTIONS.md) — collection schemas and customization
226
+ - [TRANSLATIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/TRANSLATIONS.md) — i18n keys