Role Hierarchy & Permissions

Multi-tier role system with top-down permission inheritance across the platform.

NexusOne uses a strict top-down inheritance model. Every role automatically inherits all permissions of roles below it in the hierarchy — no manual re-assignment needed.

Role Hierarchy

platform_admin ← cross-platform, inherits ALL roles

└── super_admin (school) ← school-group director

└── admin ← inherits all staff roles

├── accountant

├── facilities_admin

├── librarian

└── teacher

└── student ←── parent

Effective Permissions Per Role

RoleInherits from
platform_adminAll roles on the entire platform
super_adminadmin, accountant, facilities_admin, librarian, teacher (within assigned schools)
adminaccountant, facilities_admin, librarian, teacher (within their school)
teacherOwn permissions only
accountantOwn permissions only
facilities_adminOwn permissions only
librarianOwn permissions only
studentOwn permissions only
parentOwn permissions only
driverTransportation endpoints only

What This Means in Practice

  • An admin can manage fees, raise maintenance tickets, manage the library, and take attendance — without being assigned those roles explicitly
  • A super_admin can step into any school-level role across any of their assigned schools
  • platform_admin can do anything, anywhere across the platform
  • Leaf roles (accountant, facilities_admin, librarian, teacher) remain siloed from each other

Platform-Only Restricted Routes

These routes are restricted to specific roles only and cannot be inherited:

POST /api/schoolsplatform_admin only — school creation is a platform-level act
DELETE /api/schools/:idplatform_admin only
POST /api/platform-admin/super-adminsplatform_admin only — only platform can create super_admins
POST /api/users/:id/schools (grant multi-school)platform_admin + super_admin only

Implementation

The hierarchy is enforced via a ROLE_HIERARCHY constant in utils/roleHierarchy.js and the authorize() middleware in middleware/auth.js. Every existing authorize('accountant', ...) call automatically grants access to admin, super_admin, and platform_admin as well — no route file changes needed for inheritance to work.