fix(team): hide invite role picker until RBAC is complete (PMS-513) #347

Merged
nrupard merged 1 commit from fix/PMS-513-disable-role-assignment-ui into main 2026-06-25 18:32:45 +02:00
Owner

What

Hides role assignment in the team invite form (src/pages/team.rs, route /admin/team) behind a single module-level flag ROLE_ASSIGNMENT_ENABLED (currently false), so new invitations go out as the lowest-privilege role (Technician) until full RBAC is complete. Implements PMS-513.

Why

The invite form offered all six assignable roles, but role-based access is only partially enforced server-side: RequireAdmin (super_admin/admin), RequireManager (+manager) and RequireFinance (+finance) gate specific routes, while technician, dispatcher and sales carry no distinct authority at all. Offering roles whose permission semantics are incomplete is misleading and risks granting unexpected access the moment the rest of RBAC lands.

Change

UI-only. While the flag is false: the invite form renders email + submit only (grid collapses sm:grid-cols-3 to sm:grid-cols-2), the role signal keeps its existing "technician" default so handle_invite posts { email, role: "technician" }, and role_options is built only when the flag is true so it does not warn as unused. Re-enabling the picker is a one-line flag flip; the markup and full taxonomy are kept. The mokosh-server invite endpoint is untouched (the client simply never sends a non-default role), and the role-based access checks (is_admin / can_manage_billing) are unchanged.

Server-side clamping of the invite role was deliberately deferred: mokosh-apps is the only invite client and the goal is to stop exposing the choice, not to harden against crafted requests (YAGNI; tracked as a possible follow-up if the API gains other clients).

Verification

  • Confirmed the invite form is the ONLY role-assignment surface in mokosh-apps. The approver_role field in tickets.rs is approval routing ("pick a specific approver OR enter a role"), not an RBAC role grant; auth.rs / models.rs only parse/read roles.
  • just check parity via the rust-builder image: cargo clippy --all-targets -- -D warnings clean, cargo fmt --check clean, theme-token scan clean, cargo check --target wasm32-unknown-unknown clean.

Docs

  • dev-docs/codebase-state.md: catalogue the previously-missing /admin/team route with the gating noted.
  • YouTrack KB PMS-A-3 ("mokosh roles and RBAC: what is actually enforced today") documents the current enforcement reality and this gating decision.

Acceptance criteria

  • The team invite form shows no role selector while the feature is disabled.
  • New invitations are created with the Technician role.
  • Re-enabling the role picker is a single-line change (flip the const), with PMS-513 referenced inline.
  • The role-based access checks (is_admin / can_manage_billing) are unchanged.
  • No other mokosh-apps surface exposes role assignment or role editing while disabled (verified).
  • The invite form renders cleanly without the role column (grid adjusted to two columns).
## What Hides role assignment in the team invite form (`src/pages/team.rs`, route `/admin/team`) behind a single module-level flag `ROLE_ASSIGNMENT_ENABLED` (currently `false`), so new invitations go out as the lowest-privilege role (Technician) until full RBAC is complete. Implements PMS-513. ## Why The invite form offered all six assignable roles, but role-based access is only partially enforced server-side: `RequireAdmin` (super_admin/admin), `RequireManager` (+manager) and `RequireFinance` (+finance) gate specific routes, while `technician`, `dispatcher` and `sales` carry no distinct authority at all. Offering roles whose permission semantics are incomplete is misleading and risks granting unexpected access the moment the rest of RBAC lands. ## Change UI-only. While the flag is `false`: the invite form renders email + submit only (grid collapses `sm:grid-cols-3` to `sm:grid-cols-2`), the `role` signal keeps its existing `"technician"` default so `handle_invite` posts `{ email, role: "technician" }`, and `role_options` is built only when the flag is `true` so it does not warn as unused. Re-enabling the picker is a one-line flag flip; the markup and full taxonomy are kept. The mokosh-server invite endpoint is untouched (the client simply never sends a non-default role), and the role-based access checks (`is_admin` / `can_manage_billing`) are unchanged. Server-side clamping of the invite role was deliberately deferred: mokosh-apps is the only invite client and the goal is to stop exposing the choice, not to harden against crafted requests (YAGNI; tracked as a possible follow-up if the API gains other clients). ## Verification - Confirmed the invite form is the ONLY role-assignment surface in mokosh-apps. The `approver_role` field in `tickets.rs` is approval routing ("pick a specific approver OR enter a role"), not an RBAC role grant; `auth.rs` / `models.rs` only parse/read roles. - `just check` parity via the rust-builder image: `cargo clippy --all-targets -- -D warnings` clean, `cargo fmt --check` clean, theme-token scan clean, `cargo check --target wasm32-unknown-unknown` clean. ## Docs - `dev-docs/codebase-state.md`: catalogue the previously-missing `/admin/team` route with the gating noted. - YouTrack KB `PMS-A-3` ("mokosh roles and RBAC: what is actually enforced today") documents the current enforcement reality and this gating decision. ## Acceptance criteria - [x] The team invite form shows no role selector while the feature is disabled. - [x] New invitations are created with the Technician role. - [x] Re-enabling the role picker is a single-line change (flip the const), with PMS-513 referenced inline. - [x] The role-based access checks (`is_admin` / `can_manage_billing`) are unchanged. - [x] No other mokosh-apps surface exposes role assignment or role editing while disabled (verified). - [x] The invite form renders cleanly without the role column (grid adjusted to two columns).
fix(team): hide invite role picker until RBAC is complete
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 10m17s
Create release / Create release from merged PR (pull_request) Has been skipped
c7e0581ab6
The team invite form offered all six assignable roles (Technician, Manager, Admin, Dispatcher, Sales, Finance) while role-based access is only partially enforced server-side: RequireAdmin (super_admin/admin), RequireManager (+manager) and RequireFinance (+finance) gate specific routes, but technician, dispatcher and sales carry no distinct authority. Offering roles whose permission semantics are incomplete is misleading and risks granting unexpected access the moment full RBAC lands.

Gate role assignment behind a single module-level flag `ROLE_ASSIGNMENT_ENABLED` (false). While disabled the invite form renders email + submit only (grid collapses sm:grid-cols-3 -> sm:grid-cols-2), the `role` signal keeps its "technician" default, and every invitation goes out as the lowest-privilege role. The role_options taxonomy is built only when enabled so it does not warn as unused; re-enabling the picker is a one-line flag flip. The server invite endpoint is untouched (the client simply never sends a non-default role) and the role-based access checks are unchanged. Verified the invite form is the only role-assignment surface in mokosh-apps (tickets' approver_role is approval routing, not a role grant).

Also catalogue the previously-missing /admin/team route in dev-docs/codebase-state.md with the gating noted.

#PMS-513
nrupard scheduled this pull request to auto merge when all checks succeed 2026-06-25 18:29:07 +02:00
nrupard deleted branch fix/PMS-513-disable-role-assignment-ui 2026-06-25 18:32:45 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-apps!347
No description provided.