/login, or two people can edit the same step. Related: Errors and rate limits, Environment variables, Role preview.
FAQ
Google sign-in returns to /login
Google sign-in returns to /login
All of these must be true:
- Email ends with
@schools.nyc.gov. - A
usersdocument exists for that lowercase email. isActiveis notfalse.- Google OAuth redirect URI matches the origin (
/api/auth/callback/google). NEXTAUTH_URLis that same origin (http://localhost:3000locally).
npm run seed-users. Demo mailboxes (d79.demo.*) cannot Google-sign-in — preview them from a Super Admin session.403 on GET /api/forms/:id/editors (form page still opens)
403 on GET /api/forms/:id/editors (form page still opens)
The form GET allows a level 4 principal at the same school. Presence used to omit level 4 unless
principalEmail matched.Current rule: same-school levels 2, 3, and 4 may read editors/locks. Assistant Principals still need assignment to edit answers.If you preview as Principal on a plan owned by someone else at that school, editors should return 200. If you preview as AP on a plan you were never assigned, expect 403 on write.Assistant Principal cannot edit
Assistant Principal cannot edit
Intended. Level 3 is a collaborator. The principal (or Super Admin) must share/assign the plan (
User.assignedForms or sharedWithEmails). Same school is not enough. See Roles and access.401 immediately after Sign out, or session lasts after logout
401 immediately after Sign out, or session lasts after logout
Logout adds
sess:deny:{jti} in Redis. Without REDIS_URL, the JWT cookie remains valid until the 8-hour maxAge. Set Redis in production.429 Too many requests
429 Too many requests
Auth POSTs are limited to 20 / 60s per IP. User mutations and form create are limited per user. In production, if Redis is down those limits fail closed (you get 429 instead of unlimited traffic). Check
/admin/system → Redis, then Retry Redis.Autosave 409 or lock held by someone else
Autosave 409 or lock held by someone else
Step locks last 5 minutes (
form:{id}:step:{stepKey}). Presence heartbeats last 60s. Two serverless instances without Redis cannot see each other’s locks — configure REDIS_URL. Closing the tab should POST .../step/:n/unlock.NEXTAUTH_SECRET is required crash
NEXTAUTH_SECRET is required crash
src/lib/auth.js throws if the secret is missing. Copy .env.example to .env.local and run openssl rand -base64 32. Preview/impersonation also needs this secret on Vercel.Production build fails on page.js exports
Production build fails on page.js exports
Next.js 16 type-checks
page.js. Only the default page export (plus reserved fields such as metadata) is allowed. Keep helpers as local functions or move them to src/components.Mongoose schema change not visible
Mongoose schema change not visible
Restart
npm run dev. The connection is cached on global.mongoose.Public homepage counts look stale
Public homepage counts look stale
GET /api/public/overview is cached 60s in Redis. Super Admin → System → Flush caches.Diagnose a 403
1
Confirm who the API thinks you are
Session email and
level come from the JWT. During role preview they are the demo user, not your Super Admin mailbox.2
Compare with the form document
userId (owner), principalEmail, schoolName, assignedTo / collaborator assignedForms, sharedWithEmails.3
Match the handler
GET /api/forms/[id] allows same-school level 2 and 4. Writes also allow assigned level 3. Presence/locks also allow same-school level 3 to see who is editing.Local checklist
/admin/system should show MongoDB connected.