Role System & Separation of Duties
Nine roles. Separation of duties enforced at the API. The Dean can’t move money. Finance can’t change grades. Registrar can’t wire payments. Audit-ready out of the box.
Why this matters
Most university software grants “administrator” access generously and trusts people not to misuse it. That works until an audit asks who can do what.
UniversitasAI enforces role boundaries at the API layer, not just the UI. A registrar logging in as themselves cannot — even via direct API call — modify a payroll record. A finance officer cannot post a grade change. A dean cannot wire money to a vendor. The check runs server-side on every protected endpoint via require_dean(), require_registrar(), require_finance(), and similar dependencies.
This isn’t a permissions screen. It’s the architecture: roles are baked into the data layer and enforced before any handler runs.
The 9 roles
Each role admits its own scope plus admin. ADMIN starts with wildcard during rollout and narrows organically as endpoint-level role checks land.
Dean
Can: approve academic escalations, read OBEF and governance dashboards, view executive briefings.
Cannot: touch finance writes, modify transcripts, wire money.
Default landing page: /executive-briefing
Registrar
Can: own transcripts, graduation workflows, government reports (CAA / MOHESR / ADEK / KHDA).
Cannot: wire money, modify financial records, change grades on behalf of faculty.
Default landing page: /students
Finance
Can: own accounting, procurement, payroll, vendor payments, financial reporting.
Cannot: modify academic records, transcripts, or grades.
Default landing page: /budget
Faculty
Can: grade entry, attendance, office hours, course materials — scoped to assigned sections only.
Cannot: see other faculty’s sections, modify finance records, access HR data.
Default landing page: faculty portal dashboard
Support
Can: own tickets, knowledge base, conversations, public-facing chat.
Cannot: see financial PII, modify academic records, access government-report drafts.
Default landing page: /support
Admin
Can: wildcard access during platform rollout.
Long-term: ADMIN narrows organically as every endpoint moves to a role-specific dependency. The goal is a small ADMIN scope, with day-to-day work routed through the specialised roles.
Staff
General institutional staff who don’t fit Dean / Registrar / Finance / Faculty / Support. Read access to most operational dashboards; limited writes.
Student
Self-service portal access. Sees own grades, schedule, financial aid, registration. Cannot see anyone else’s records.
Applicant
Pre-enrollment access. Application status, document upload, admission communications. Promoted to Student on enrollment confirmation.
Capability matrix
Who can write what.
| Capability | Dean | Registrar | Finance | Faculty | Support |
|---|---|---|---|---|---|
| Approve academic escalation | Yes | No | No | No | No |
| Modify transcript | No | Yes | No | No | No |
| Post journal entry | No | No | Yes | No | No |
| Submit grades for assigned section | No | No | No | Yes | No |
| Resolve support ticket | No | No | No | No | Yes |
| Read OBEF dashboard | Yes | Yes | Read-only | No | No |
| Submit government report (CAA / MOHESR / ADEK) | Approve | Submit | No | No | No |
| Wire vendor payment | No | No | Yes | No | No |
| Run payroll | No | No | Yes | No | No |
| View financial PII | No | No | Yes | No | No |
How it’s enforced
API-layer dependencies
FastAPI dependencies (require_dean(), require_registrar(), require_finance(), require_support(), require_faculty()) run before any handler. A wrong role gets 403 before the SQL query is even constructed.
JWT-claim-based
The user’s role is encoded in their JWT and verified per request. No role lookup on each call — the check is constant-time. Token rotation invalidates old roles immediately.
Audit-logged
Every privileged action writes to an audit table with user, role, action, and timestamp. The audit log is read-only post-write. Compliance teams get the trail they ask for.