Skip to main content
Levels are stored on User.level (1–5) and copied onto the JWT. Route handlers should reload User from MongoDB (especially Super Admin mutations) rather than trusting session.user.level alone. Dashboard by role Caption: Add screenshot showing Super Admin sidebar (Submissions, Users, Goals, Question bank, System, Audit logs, Year setup) versus a principal sidebar.

Form authorization

A user may open a form if any of:
  • Super Admin
  • Form owner (userId)
  • principalEmail matches the session email
  • Same schoolName and level 2 or 4
  • Listed in User.assignedForms for that formId
  • Listed in FormSubmission.sharedWithEmails
Assistant Principal is a collaborator, not a second owner. If Preview as AP cannot edit, share the plan from Collaboration. That is expected, not a 403 bug.

School users (canManageTarget)

src/lib/canManageUser.js:
  • Nobody manages themselves
  • Actor level must be strictly higher than the target
  • Principals only see/manage people at their school with level ≤ 3 (list filter is level: { $lt: 5 } so Super Admins at that school do not appear)
  • Principals cannot create or promote to level 4 or 5

Collaboration fields

On User.assignedForms[]:
Empty assignedSections means all steps. permissions is view | edit | admin. In-app how-to copy lives in src/lib/roleGuides.js (dashboard How to, /dashboard?view=howto).