A group is a named set of entities cutting across the structural trees: the tree handles config
by position and kind, groups by attribute or hand-picked set (“all AV displays”). One primitive
serves two jobs, a cascade overlay and an
access scope, which an anonymous predicate never could.
What is built is the principal arm: principal_group and its membership, a grant subject
(grants attach to the group and reach its members), not an access scope (scope_kind='group' is
refused today with a 422).
A group’s name is an ordinary entity name (^[a-z0-9][a-z0-9-]*$, 100 characters, a uuid refused),
enforced by the Storage Gateway on create and on rename rather than by the request schema alone
(ADR-0077).
Moving it is the :rename custom method, POST /principal-groups/{id}:rename gated by
principal_group:rename; the PATCH body does not carry a name at all
(ADR-0076).
The whole collection is addressed by the uuid, so a group is the one case where the rename route
takes an {id} rather than the name it is about to move; nothing inside the platform notices,
since membership and grants both key on that uuid.
principal_group (identity): generated from the migrated schema by make gen
Column
Type
Constraints
id
uuid
PK, default uuidv7()
name
text
not null
label
text
description
text
created_at
timestamp with time zone
not null, default now()
updated_at
timestamp with time zone
not null, default now()
CHECK constraints and unique indexes on principal_group
principal_group_name_key: CREATE UNIQUE INDEX principal_group_name_key ON public.principal_group USING btree (name)
principal_group_member (identity): generated from the migrated schema by make gen