Skip to content

Management role and permission adjustments


1. Problem distillation

  • Add an admin-assignable, non-parametric management preset with key administrative_assistant, stored English label Administrative Assistant, and Italian localized label Assistente Amministrativo.
  • Give the new role the exact functional union of the current secretary (Front Office) and hr (HR Manager) presets: the stronger access wins for a scope (WRITE > READ > NONE) and actions are the set union.
  • Make Director (principal) read-only on attendance. The recommended complete interpretation downgrades attendance.register from WRITE to READ and removes all three attendance mutation actions: take, manage_communications, and justify.
  • Give Curriculum Coordinator READ on student health only (students.health). Teacher, Staff, and Referent health remain excluded.
  • Apply the changed baselines to the global presets and every existing tenant clone, so deployments do not leave stale environments.

Success criteria (observable behavior that proves this works): - Global and tenant role catalogues contain administrative_assistant; the role is assignable to Teacher or Staff people without parameters and is localized as Administrative Assistant / Assistente Amministrativo. - For every scope, the new role equals max(secretary, hr); for every action, it equals secretary ∪ hr. It also receives the same school-wide record-policy reach and service-level behavior as whichever source role supplies a function. - Director sees attendance data tenant-wide but cannot create/correct register cells, manage attendance communications, or submit attendance justifications. - Curriculum Coordinator can read the health block of students already visible through its existing curriculum/related-student policy, without gaining health visibility for teachers, staff, or referents. - The authoritative data migration updates global presets and all existing tenant clones while leaving custom roles and unrelated preset grants intact. - The manual db:reconcile-rbac tool recognizes the new preset and converges every environment to the same code matrix after the deploy seed.

Non-goals (in-scope-shaped things this iteration is explicitly not doing): - No new permission entity, scope, action, route, DTO, or database model. - No parameter dimension for Administrative Assistant; it is school-wide like Front Office and HR. - No change to Front Office or HR themselves. - No health access for Curriculum Coordinator outside students.health. - No change to tenant-authored custom roles.


2. Patterns survey

Analogous module/spec What we'd borrow What doesn't fit
prisma/seed/roles.ts + prisma/seed/helpers/expected-preset-grants.ts Existing *_WRITE_SCOPE_KEYS, *_EXCLUDED_SCOPE_KEYS, and *_ACTION_KEYS preset definitions plus the independent DB-vs-code drift oracle The new role combines two presets; derive its write set and action set by union and its exclusion set by intersection so future HR/Front Office changes cannot silently leave it stale
prisma/migrations/20260820120000_realign_management_preset_v3_grants_and_labels/migration.sql Data-only, key-scoped reconciliation of editable management presets across the global baseline and every tenant clone This change also adds a new preset; role creation remains in the Tier-1 seed plus backfillMissingPresetRoles, while the migration owns the two existing-role deltas
src/permissions/role-clone.ts Tier-1 backfillMissingPresetRoles already creates any newly authored global preset in every existing tenant, including production It is intentionally additive-only for existing editable presets, so it cannot roll out the Director downgrade or Coordinator grant; those need the explicit migration
docs/superpowers/specs/2026-08-20-role-matrix-v3-preset-realignment-design.md Precedent for pairing grant changes with record-policy/service behavior, localized labels, an authoritative migration, tests, and docs The new role must follow both HR and Front Office hard-coded functional branches rather than changing one existing role's matrix
src/common/i18n/role-labels.catalog.ts + src/common/i18n/role-descriptions.catalog.ts Bilingual product copy for every management preset, guarded against the seed's exact management-role key set Stored role metadata is English while the requested Italian name belongs in it_IT; both surfaces must be updated together
src/attendance/attendance-access.service.ts + src/attendance/attendance.policy.ts Existing distinction between school-wide READ roles, school-wide WRITE roles, qualified writers, and policy admission Removing the scope alone is incomplete if mutation actions remain; the baseline should not advertise inert or still-effective mutation grants

On-axis/off-axis assessment (chapter 16 §§4–5): adding a role, changing existing grants, adding policy branches, and applying a data-only preset reconciliation are all on-axis. The only maintainability wrinkle is that the new role composes two existing functional identities. This design keeps that composition explicit through shared functional-role key constants and derived seed sets rather than scattering an untracked third copy of the two matrices.


3. Architecture mapping

Primitive Apply? How Justify
Tenant scope yes Author one tenantId = null global preset, backfill one clone per tenant, and key-scope the data migration to isPreset = true global/tenant roles Preset definitions are platform metadata, while effective assignments reference tenant clones
Academic-year scope no data change Role/grant rows are not year-scoped; existing student and attendance policies continue to apply their current dated/year-aware narrowing No new record reach is introduced beyond existing policy branches
RBAC entity key existing only attendance and students; no entity-keys.ts change Requested changes map to existing entities
Scopes existing only Director: attendance.register WRITE→READ. Coordinator: add students.health: READ. Administrative Assistant: derived HR/Front Office union No new scope vocabulary is needed
Actions existing only Administrative Assistant gets HR∪Front Office actions. Recommended Director baseline removes attendance.take, attendance.manage_communications, and attendance.justify Read/update remain implicit, but these explicit actions authorize attendance mutations
Service base existing services No CRUD base changes. Add the new functional role key to existing policy branches, role gates, and service-level semantic checks wherever HR or Front Office currently supplies the corresponding function Grants alone do not establish record-level or service-level access
queries.ts shape existing only No new queries. Existing tenant/policy filters remain authoritative New role is school-wide and non-parametric
Error codes existing only Existing insufficient-scope/action and policy errors apply No new failure condition or wire contract
DTO conventions existing only Role catalogue and permissions DTO shapes already accept arbitrary role keys No response-shape change
File-backed sub-resources existing Administrative Assistant follows HR for teacher/staff document functions and Front Office for student/referent document functions No new file usage or owner type
Custom fields no All presets continue with no others grants and no custom-field management grant Existing platform-wide hidden decision remains intact
Profile completeness no n/a — role grants do not change completeness fields

4. Data model plan

Schema deltas

  • None. Role, RolePermission, RoleActionPermission, assignments, enums, and indexes already represent the requested state.

Migration shape

  • Additive/destructive/renaming: one data-only migration, 20260828xxxxxx_realign_management_roles.
  • New-role rollout: seedGlobalRolePresets authors administrative_assistant; the existing Tier-1 backfillMissingPresetRoles creates it with grants in every existing tenant after migrations in every environment. No fixture tenant creation is needed.
  • Existing-role backfill: the migration updates principal's attendance.register to READ, deletes the approved attendance actions, and upserts curriculum_coordinator students.health: READ for every global and tenant preset clone.
  • The manual reconciliation CLI is updated with the new non-parametric key. It remains an exact-code fallback and post-deploy verifier for all environments.
  • Hazards from chapter 12: data-only writes on small RBAC tables; no DDL, table rewrite, enum change, or domain-table backfill. The migration must use SET LOCAL row_security = off, is_preset = true, exact role/entity/scope/ action keys, idempotent UPSERT/DELETE operations, and comments documenting the hazard audit. A clean worktree currently contains no uncommitted migration; re-check immediately before authoring or running prisma migrate dev.

Indexes and uniqueness

  • None added. Existing uniqueness on (tenantId, key), (roleId, scopeId), and (roleId, actionId) supports the seed/backfill/upserts.

5. API surface

No new routes or DTOs.

Verb Path Decorators Request DTO Response DTO
GET /roles, /roles/presets existing tenant-admin/platform-admin gates n/a existing role catalogue DTO; includes administrative_assistant
POST/PATCH/DELETE /role-assignments existing admin-only assignment gates existing assignment DTOs; role key administrative_assistant, no parameter ids existing assignment DTO
GET /permissions existing authentication/scope compilation n/a existing entity-grouped map with the new role's unioned effective grants
existing domain routes unchanged paths existing scope/action/policy decorators unchanged unchanged; new role is admitted where its HR/Front Office functions require it

Swagger considerations

  • No schema change. Update role/attendance descriptions only where they enumerate the management behavior; the role catalogue supplies localized name and description at runtime.

6. RBAC seed plan

Seed file Delta
PermissionScope (rbac-catalogue.ts) none
PermissionAction (rbac-catalogue.ts) none
ScopeFieldMapping (rbac-catalogue.ts) none
Role grants (roles.ts) Add administrative_assistant as the exact HR/Front Office union; remove attendance.register from PRINCIPAL_WRITE_SCOPE_KEYS; remove the approved attendance actions from PRINCIPAL_ACTION_KEYS; remove students.health from CURRICULUM_COORDINATOR_EXCLUDED_SCOPE_KEYS so it resolves to READ
expected-preset-grants.ts Add administrative_assistant from the same derived constants so DB drift coverage remains bidirectional
*_SCOPES runtime constant none — no scope-field mapping changes

Runtime authorization deltas: - Add administrative_assistant to every school-wide policy/read branch that currently admits HR or Front Office. - Add it to Front Office functional write branches/checks (students, enrolment/curriculum selection, departments/grades/rooms, homerooms/subject groups, attendance, disciplinary notes, school-side assignments, referent contact editing). - Add it to HR functional write branches/checks (teacher/staff management and deletion, personnel documents/health). - Prefer shared role-key constants for HR_FUNCTION_ROLE_KEYS, FRONT_OFFICE_FUNCTION_ROLE_KEYS, and their school-wide union so future changes cannot omit the combined role from one of the two functions.


7. Divergence ledger

Pattern We diverge by Reason Tradeoff accepted
Each management preset has a hand-authored independent matrix Administrative Assistant derives its scope/action matrix from HR and Front Office “Functions of Front Office and HR” is a composition invariant; hand-copying creates immediate and future drift risk A future product request to diverge the assistant must replace the derived sets with explicit rules and update this decision
Editable tenant preset clones normally preserve historical customization The migration authoritatively changes the named Director/Coordinator pairs in all tenant clones The user explicitly requires no stale tenants across environments Only the listed scope/action pairs are overwritten; unrelated preset edits and every custom role remain untouched
Policies list role branches explicitly Closely related checks use shared functional-role key constants that include the assistant The same new key must follow two established functional identities across many modules Small indirection in exchange for making the union mechanically reviewable

8. Pushback log

US says Conflicts with Proposed instead Status
“Assistente Amministrativo con funzioni di Front Office e HR” Scope/action grants alone do not confer record-policy or service-level behavior Implement the exact grant union and add the role to both functional authorization paths; key administrative_assistant, stored English label plus requested Italian localization Proposed — approve with design
“Rimuovere write su attendance” for Director Keeping attendance actions would either advertise inert grants (take/manage_communications require WRITE) or retain a real mutation (justify requires only READ) Downgrade the scope to READ and remove all three attendance mutation actions Open — user confirmation required
“Read permission on health for cv coord” health is four distinct scopes: students, teachers, staff, referents Grant only students.health: READ, matching the student-centric coordinator matrix; keep the other three excluded Open — user confirmation required

9. Deferrals

  • No generalized role-composition engine in the database or UI — one derived code preset is sufficient; revisit only if product introduces additional composite roles.
  • No per-tenant customization provenance/baseline version — this rollout is an explicit authoritative exception for named grant pairs, following role-matrix v3; broader three-way merge remains a separate concern.

10. Open questions

  • Confirm Director becomes fully read-only for attendance: downgrade attendance.register and revoke take, manage_communications, and justify. Resolved by user approval in chat on 2026-08-28.
  • Confirm “health for Curriculum Coordinator” means only students.health: READ (not teacher, staff, or referent health). Resolved by user approval in chat on 2026-08-28.

11. Verification plan

  • Unit specs:
  • Extend policy/service specs for students, teachers, staff, referents, departments/grades, curricula/selection windows, homerooms/subject groups, attendance, disciplinary notes, and assignments to assert administrative_assistant follows the appropriate HR/Front Office branch.
  • Extend attendance access tests to assert Director qualifies for READ but not WRITE/action slices under the baseline.
  • Extend role label/description drift specs with the new bilingual copy.
  • Update the reconciliation CLI's role metadata guard with the new key.
  • E2E specs:
  • Extend rbac-presets.e2e-spec.ts with the complete assistant union, Director attendance read-only state, and Coordinator student-health READ.
  • Extend role-presets.e2e-spec.ts expected management keys and role-assignment coverage for the new non-parametric preset.
  • Add/extend a migration E2E that starts with stale global and tenant clones, applies the data migration, and proves exact changed pairs plus preservation of custom roles/unrelated grants.
  • Keep rbac-grants.db-sync.e2e-spec.ts as the bidirectional full-matrix oracle for every global/tenant preset.
  • Manual verification:
  • After deploy/seed, dry-run then apply npm run db:reconcile-rbac -- ... in dev, stage, and prod; expect 11 global preset keys and one assistant clone per tenant.
  • Assign Administrative Assistant to a Staff person, switch to that role view, and smoke-test one Front Office write, one HR write, and both health/ attendance restrictions.
  • Documentation sync: update docs/04-rbac.md, docs/15-seeding.md, docs/19-attendance.md, and the RBAC pointers in docs/REFERENCE.md.
  • Per repository rules, builds, lint, tests, and migrations run only when the user explicitly requests those commands.

12. Sign-off

  • Approved by: user
  • Date: 2026-08-28
  • Chat reference: “approved” in chat after confirming the §10 Director attendance and Curriculum Coordinator health interpretations.

Until this section is filled, no implementation code is written. When it is approved, set frontmatter status: Approved, fill this section, commit the spec, and add the ordered implementation plan separately under docs/superpowers/plans/ before implementation.