Authorization matrix — EduRegie
Formal record of who is allowed to see and do what, aligned with the roles from docs/product-blauwdruk.md and as actually enforced in the web dashboard (role-based navigation in components/DashboardNav.tsx, server-side role checks per page, and Row Level Security per school in the database).
| Role | Overview | Report sick | Timetable & substitution | Team status | Absence reports | Statistics | Staff | Users | Settings |
|---|---|---|---|---|---|---|---|---|---|
| Employee | ✓ | ✓ (own report) | — | — | — | — | — | — | — |
| Call center/operator | ✓ | — | — | — | — | — | — | — | — |
| Scheduler | ✓ | — | ✓ | — | ✓ | — | — | — | — |
| Team leader | ✓ | — | — | ✓ | ✓ | ✓ | — | — | — |
| HR/absence coordinator | ✓ | — | — | — | ✓ | ✓ | ✓ | — | — |
| Substitute | ✓ | — | — | — | — | — | — | — | — |
| School administrator | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Enforcement (technical, not just procedural)
- Database level (Row Level Security): every query is server-side limited to the school itself via
current_school_id()— a user can never retrieve data from another school, regardless of what the application layer allows (supabase/migrations/0002_auth_and_rls.sql). - Application level (role check per page): every dashboard page itself checks the role of the logged-in user (e.g.
app/dashboard/rooster/page.tsxdenies access to everyone exceptscheduler/admin), not just by hiding the navigation item. - Account management: new accounts are only created via invitation by a school administrator (
app/api/internal/gebruikers/uitnodigen/route.ts) — no self-serve registration, so no uncontrolled role assignment.
Not yet implemented
- Granular roles within a school (for example HR limited to one location within a school group) — deliberately postponed to phase 3 (enterprise/multi-location), see
docs/mvp-roadmap.md.
MFA for HR and admin has since been enforced (
middleware.ts,/dashboard/beveiliging) — see Security Annex.