Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

08 — Form Specifications (RBAC Module)

Field-by-field specs for the three RBAC forms. Validation mirrors the server DTOs (create-role.dto.ts, add-member.dto.ts) plus client-side guards the server does not enforce (flagged per field). Wire contract per 00-shared/07.


1. Create / Edit Role form (S3 top section)

Request shape: CreateRoleDto (create-role.dto.ts:10-38) — used for both POST /rbac/roles and PATCH /rbac/roles/:id (rbac.controller.ts:39-49).

#FieldControlServer validation (source)Client rules
1nameAppTextField, autofocus (create)@IsString required (create-role.dto.ts:12-13)required; max 60 chars; trim; unique-ish by display (slug is the real unique)
2slugAppTextField mono@IsString required (create-role.dto.ts:15-17)required; pattern ^[a-z0-9_]{2,40}$; generated suggestion from name (snake_case) editable; on 409 DUPLICATE_RESOURCE (rbac.service.ts:86-87) → inline error + focus; helper "Used in API & membership — can't be changed later" (update actually allows $set of slug, rbac.service.ts:96 — but changing breaks member role arrays; treat as immutable in UI)
3descriptionAppTextField multiline@IsOptional @IsString (create-role.dto.ts:19-22)optional; ≤ 200 chars; helper text; 2 lines
4priorityAppTextField number@IsOptional @IsNumber (create-role.dto.ts:29-32); schema default 0 (role.schema.ts:82)integer 0–1000; default 0; helper "Higher = listed first (Roles list sorts priority desc, rbac.service.ts:76). Display only — doesn't grant more power."
5isSystemhidden (never rendered)@IsOptional @IsBoolean (create-role.dto.ts:24-27); schema default true (role.schema.ts:78-79)always sends false (OQ-R2) — otherwise the new role locks itself
6permissionsPermissionMatrix (07 §1)@IsOptional @IsArray (create-role.dto.ts:34-37) — no whitelist checkclient-side only: every string must be in the catalog from GET /rbac/permissions (rbac.service.ts:79-81); empty set allowed (warning banner, e.g. student role)

Submit flow (both modes):

  • Edit: PATCH /rbac/roles/:id with the full doc {name, slug?, description?, priority?, isSystem?, permissions} — server $sets wholesale (rbac.service.ts:96); system roles → 400 "Cannot modify system roles." (rbac.service.ts:94-95) — unreachable via UI (editor hidden for system roles).
  • Create: POST /rbac/roles; duplicate slug → 409 (rbac.service.ts:87).
  • Errors: field-level for slug/name (400 VALIDATION_ERROR with details[].field), banner for 403; anti-double-submit; success → snackbar → pop to detail.

2. Add Member form (S5 sheet)

Request shape: AddMemberDto (add-member.dto.ts:4-12) for POST /rbac/members; same DTO reused by PATCH /rbac/members/:id (edit mode — rbac.controller.ts:71-72).

#FieldControlServer validation (source)Client rules
1userIdUserSearchPicker (07 §9), read-only tile once picked@IsMongoId required (add-member.dto.ts:6-7)required; must exist in user.read results; pre-check against loaded members → "Already a member" inline (server 500s on E11000, OQ-R5)
2rolesRolePickerChips (07 §8) multi-select@IsArray @IsString({each: true}) required (add-member.dto.ts:9-12)≥ 1 required for submit; ≤ 10 (UI cap, (proposed)); slugs must resolve in GET /rbac/roles (warn + strip unknown); system roles selectable (assign teacher is normal)

Submit flow:

  • Create: POST /rbac/members → 200/201 doc with status:"active", joinedAt server-set (rbac.service.ts:122-123); sheet closes; row appears top (list sorts joinedAt desc, rbac.service.ts:110).
  • Edit mode: PATCH /rbac/members/:id with {userId: <row's userId>, roles:[…]} (server ignores userIdrbac.controller.ts:72; client echoes the row's value for DTO compliance); success → tile chips refresh; 404 → "Member removed elsewhere" snackbar + remove row.
  • Remove: AppDialog destructive confirm → DELETE /rbac/members/:id (rbac.service.ts:138-140); silent 200 even if already gone (no 404) → optimistic removal.

3. Audit filter form (S6, non-mandatory)

FieldControlQuery param (audit.controller.ts:20-25)Notes
actionAppDropdown (free-text)actionsuggestions + RBAC presets (proposed) (OQ-R8)
entityTypeAppDropdown (free-text)entityTypee.g. roles, organization_members
actorIdUserSearchPickeractorIdvia user.read
page/limitimplicitpage, limit (default 50 server, audit.controller.ts:20)infinite scroll appends pages

Filters combine (all optional; server builds filter object audit.controller.ts:26-29); "Clear" resets all.


4. Validation summary table

RuleWhere enforced
slug unique per tenantserver 409 + unique index (rbac.service.ts:86-87, role.schema.ts:89) + client inline
system role immutableserver 400 (rbac.service.ts:94-95,104-105) + UI hides editor/delete
isSystem forced false on createclient only (OQ-R2)
permission names whitelistedclient only (server @IsArray, create-role.dto.ts:36)
member duplicateclient pre-check (server 500, OQ-R5)
member roles non-emptyclient only (server @IsArray allows [], add-member.dto.ts:10)
userId MongoIdserver 400 (add-member.dto.ts:6)