Frontend Global Role Enum Centralization Design

Context

Frontend currently uses mixed role handling: a dashboard enum in one area and normalized string-based checks in others. This creates drift risk with backend role naming and weakens permission-check consistency.

Goal

Centralize all frontend role checks around one global enum whose values exactly match backend role identifiers.

Scope

In scope:

  • Introduce a shared frontend global role enum module.
  • Add strict role helpers (no soft normalization).
  • Migrate existing role comparisons to the shared enum/helpers.
  • Update affected tests.

Out of scope:

  • Refactoring all permission business logic into one authorization module.
  • Behavior changes unrelated to role-format strictness.

Source of Truth

Backend role format is authoritative. Frontend role values must match backend exactly (e.g. SUPER_ADMIN, ADMIN, OWNER, STAFF, TECHNICAL).

Design

1) Shared role module

Create a shared role module (proposed: frontend/src/shared/auth/roles.ts) that exports:

  • RoleEnum
  • isRole(value): value is RoleEnum
  • toRoleOrNull(value): RoleEnum | null
  • assertRole(value): RoleEnum (throws on invalid role)

Strict parsing only:

  • Accept only exact backend-formatted role strings.
  • Do not normalize casing, spacing, underscore/hyphen variants.

2) Migration strategy

2.1 Dashboard role type source

  • Update frontend/src/pages/dashboard/dashboard-role.ts to rely on the shared global role enum (re-export or thin wrapper) so there is no duplicated role source.

2.2 Role checks in call sites

Migrate role checks to RoleEnum in:

  • frontend/src/App.tsx
  • frontend/src/pages/organizations/components/OrganizationDevicesTab.tsx
  • dashboard hooks that currently reference page-local role enum values in query keys.

2.3 Organization capabilities strictness

  • Update frontend/src/pages/organizations/organizationUserCapabilities.ts to remove soft normalization-based comparisons.
  • Parse incoming role values via shared strict helpers.
  • Invalid roles become non-privileged values (no accidental elevation).

3) Error handling policy

  • At system boundaries (API/user-derived role strings), use strict parser.
  • Internal trusted flow should carry RoleEnum typed values.
  • Invalid external values should not grant permission; helper behavior remains explicit and deterministic.

Data Flow (after migration)

  1. Role value enters from API/auth state.
  2. Strict parse via shared helper.
  3. Permission checks compare only RoleEnum values.
  4. Invalid roles short-circuit to no privilege.

Testing Strategy

Targeted frontend tests only for impacted areas:

  • src/pages/organizations/components/OrganizationDevicesTab.spec.tsx
  • Any updated capability/role utility test files touched by migration.

Verification focus:

  • Valid backend-format roles still produce expected permissions.
  • Non-backend format roles (e.g. Super Admin, super_admin) are treated as invalid and do not elevate permissions.

Run command:

  • make frontend:test FILE=src/pages/organizations/components/OrganizationDevicesTab.spec.tsx

Risks and Mitigations

  • Risk: Existing fixtures/mock data use display-format roles.
    • Mitigation: Update fixtures to backend-format enum values where those paths represent backend-derived role data.
  • Risk: Hidden call sites compare raw strings.
    • Mitigation: Replace role checks incrementally and rely on type errors/import search during migration.

Success Criteria

  • Frontend uses one global role enum source aligned with backend.
  • No role string-literal checks remain in affected permission-check paths.
  • Strict role format is enforced at role-input boundaries.
  • Updated tests pass for both valid and invalid role formats.