Appearance
JSON-DAT: groupMembership.restrictions
JSONB element of: groupMembership.restrictions and permissionSetUserAssignment.restrictions
This shape is shared verbatim between the two columns above: it narrows what a holder's granted access actually applies to, beyond the Permission Set's own rules. A holder with no entries in this collection is unrestricted (subject only to the Permission Set's own rules).
Decided: building and clientGroup are the two dimensions, final for now. Every tenant-side restriction uses building. A platform-level direct grant (permissionSetUserAssignment with tenantId = null) uses clientGroup instead — e.g. an external "Admin-manažer" role restricted to acting only on clients within one or more named clientGroups (values being clientGroup IDs). A future dimension can still be added the same way (a new value on this column, unenforced until a feature reads it), but none is planned today.
Combining dimensions on one holder
A holder carries at most one dimension in practice, so this does not arise today. The column shape technically allows more than one entry (multiple restriction dimensions at once), but building only ever appears on a tenant-scoped row (tenantId set) and clientGroup only ever appears on a platform-level direct grant (tenantId = null) — the two dimensions are confined to mutually exclusive scopes by Breadth and restriction ceiling rules elsewhere in this model, so no holder's restriction collection ever needs to combine the two. If a future dimension is added that could coexist with an existing one on the same row, combining them is a fresh design question at that point — not something this shape needs to answer now.
Combining the same dimension across more than one of a holder's own sources is resolved, for one specific purpose: several permissionSetUserAssignment rows (direct or propagated) contributing values in the same dimension combine as a plain union, wherever the holder is themselves acting as the granter of a new restriction — see permission-model. This is scoped to that one ceiling check; it does not decide how a holder's own effective access is computed for evaluation purposes generally.
Cascade through linked resources: a restriction is not limited to the record type named by its dimension — it reaches through relationships to that record. A resource "linked" to a restricted target is inaccessible unless the holder's restriction includes that target: e.g. a document attached to building A is inaccessible to a building-restricted holder who isn't restricted to include building A; a tenant created from a client is only creatable by a clientGroup-restricted holder if that client belongs to one of their allowed client groups. Decided: a cascade can walk more than one relationship hop before reaching the restricted dimension — e.g. a reading → gauge → building — not only a single, direct reference. Evaluation must follow the chain of relationships to whatever depth is needed to reach the restricted target, rather than assuming one hop; see Permission Evaluation.
Enforcement differs by operation, not just by dimension — the three modes (list filter, single-record membership check, create-time constrain) and how they interact with the winning rule and deny-first precedence: see Permission Evaluation.
Decided — "Select All" UI convention: the building-selection UI cannot allow a submission with nothing selected (an accidental blank list must not be possible to submit), yet the data model treats the absence of a building entry in this collection as "unrestricted for buildings," not as an error. The UI reconciles this with a distinct "Select All" control, separate from the individual building checkboxes, which omits the building entry from the restrictions array entirely rather than submitting a list of every building that currently exists. This distinction is load-bearing, not cosmetic: omitting the entry stays correct as new buildings are added to the tenant later (an unrestricted holder automatically gains access to them), while a manually-checked list of every building that exists today would silently freeze and exclude anything added afterward. The UI must make "Select All" visibly and functionally distinct from manually checking every listed building — it is not implemented as "check every checkbox currently rendered."
Data Attributes Table
| Attribute Name | Description | Data Type | Default Value | Required (= Nullable) | Unique | Format | Validations | Index | Example |
|---|---|---|---|---|---|---|---|---|---|
| dimension | The kind of restriction this entry expresses. Not a fixed enum — building (tenant-side) and clientGroup (platform-level, direct grants only) are the two dimensions, final for now (see above); a future dimension is added as a new value on this column. | String | - | Yes | No | lowerCamelCase token | Non-empty | - | building |
| values | The specific records this restriction limits access to, within the stated dimension. What entity these IDs reference depends on dimension (e.g. building IDs for the building dimension). A dimension with no restriction (e.g. "Select All" buildings) is expressed by omitting its entry from the array, never by an entry with an empty values. | Array<UUID> | - | Yes | No | UUID v7 | Non-empty | - | ["018fa51f-fda1-79f4-8461-2cb8f1cabc14"] |