@schools.nyc.gov mailboxes. Super Admins still need to walk a principal and assistant principal UI. Role preview does that by rewriting the JWT claims to a seeded demo User without changing the Google identity of the actor.
Who can preview
Only level 5. The JWT callback loads the actor from MongoDB, then — iftoken.impersonateEmail is set — swaps session.user to the target only when:
- The actor’s stored level is 5
- The target exists, is active, and has level < 5
impersonateEmail and restores the actor.
Demo users
Constants:src/lib/demoUsers.js. Seed:
These addresses cannot sign in with Google. Use Preview as on Overview (
RolePreviewCard). The script assigns every plan at that school to the demo AP (assignedForms with permissions: "edit").
How the session changes
Client:session.update({ impersonateEmail }) or session.update({ stopImpersonation: true }).
After reload, getServerSession exposes:
string
Demo user’s email (APIs authorize as this user).
number
4 or 3 while previewing.string
Demo
User._id, not the Super Admin’s id.boolean
true while a preview is active.string
The real Super Admin mailbox (banner + stop-preview).
token.actorEmail). jti is unchanged. Sign-out revokes that jti as usual.
While previewing, mutating APIs use the demo email and level. A Super Admin sidebar is hidden. Stop preview from the yellow banner (
ImpersonationBanner in src/app/providers.js) before running district tools.What you should see
- Principal
- Assistant Principal
Same-school plans are editable without a share. School users (levels 1–3 at that school). Collaboration share. Create/duplicate/attest/submit for that school only. Super Admin pages redirect to
/dashboard.1
Sign in as Super Admin
Use your real
@schools.nyc.gov account (for example the Data Systems Administrator).2
Seed demo users if needed
node src/scripts/create-demo-users.js against the same MONGODB_URI as the app.3
Overview → Preview school roles
Choose Principal or Assistant Principal. Confirm the yellow banner.
4
Stop preview
Banner Stop preview, or
session.update({ stopImpersonation: true }).