Assign a scoped role to a team member
GRANTS one built-in RBAC role (owner / manager / cashier / viewer) to a member at an access scope — the REAL per-scope assignment the directory role label flattens. roleId is the built-in role id (NOT the free-text directory label); storeId narrows the grant to one store, and omitting it grants network-wide (the whole franchise, which covers every store). This widens what the account can do, so it is a security-posture change: only ever call it on an explicit instruction, never to ‘fix’ a missing permission. Idempotent-by-conflict: an identical (role, scope) is a 409; unknown roleId is a 404. PERMISSION TRAP (solya-pos#950): x-required-permissions says pos.team.manage, and that is what the router gate checks — but the use-case behind it additionally asserts the kernel permission config:manage, and the scope-to-kernel table (SCOPE_KERNEL_PERMISSIONS) maps pos.team.manage to NOTHING. A token-authenticated actor holding exactly the documented scope therefore passes the gate and then fails with a bare 403 from inside the use-case. Read a 403 here as a server-side grant gap, not as a malformed request, and do not retry it with a different body.
Authorizations
Authorization: Bearer <token>. Accepts EITHER a Keycloak access token (scopes-in-token) OR an opaque POS session token; both resolve to the same pos.* scope vocabulary the route guards enforce.
Path Parameters
The team-member id to act on, e.g. user-julie.
1
