Skip to main content

Answer storage

Every field value is keyed by question id, not by title:
The editor loads questions from the published bank pinned by form.questionBankVersion (or the year pin on SchoolYearSettings). Titles can change; ids cannot.

Create → edit → submit

Form workspace Caption: Add screenshot showing FormWorkspace with section nav, autosave (“Editing · Saved 2:14 PM”), lock indicator, and attestation on a copied 2026-2027 plan.

Duplicate / rollover

  1. Single school: POST /api/forms/[id]/duplicate with { schoolYear, force? }.
  2. District: Super Admin POST /api/admin/forms/rollover with { sourceYear, targetYear, force? }.
duplicateForm():
  • Deep-clones formData (all data objects).
  • Sets completed when a step already has answers.
  • Creates a draft owned by the same principal.
  • Sets duplicatedFrom, schoolYear, needsUpdate flags for new/changed/revisit questions.
  • Does not copy comments, reviews, shares, or attestation.
  • After a successful bulk rollover, the source year is archived (SchoolYearSettings.archived = true). Archived years reject writes.
If a dashboard shows 0% on a copied plan, completions are derived from whether formData[stepKey].data has keys (deriveCompletedSteps). New copies keep completed: true when answers exist.

Compare years

GET /api/forms/[id]/compare?compareYear=2025-2026 diffs these step keys only:
  • attendancePlan
  • temporaryHousing
  • counselingPlan
UI: /form/[id]/compare.

Public snapshot

Unauthenticated GET /api/public/overview aggregates school count, section count, and submitted/under_review/approved totals for currentSchoolYear().