Skip to content

Admin Settings — show-decision + form config #502

Description

@adityapat24

Context

Last sprint shipped the three date singletons. What's missing is the show-decision singleton (needs the POST handler), the form-config service and endpoints, and admin gating on all four singleton writes.

Tasks

Complete the show-decision singleton

  • The GET handler exists from last sprint (or from sprint 1 scaffold — verify). Implement the POST handler in src/app/api/v1/show-decision/route.ts following the same pattern as the date singletons: parse { value } from the body, validate it's a boolean, call setSingleton('show-decision', value, updatedBy), return the response.
    • What this accomplishes: The admin settings UI's show-decision toggle now actually persists. Right now the toggle probably calls the endpoint and gets a 501 or does nothing.
  • Add a validateBooleanSingleton helper to src/lib/admin/singleton-service.ts for the value check.
    • What this accomplishes: Mirrors the pattern of validateDateSingleton for consistency. Prevents non-boolean values from being written.

Form config service

  • Design the form config document shape. Recommended: single document in singleton_data with key form-config, value shape { sections: [{ id, title, questions: [{ id, type, label, required, options?, order }] }] }.
    • What this accomplishes: One source of truth for what questions the application asks. Sections group related questions on the form.
  • Implement getFormConfig() in src/lib/admin/form-config-service.ts. Reads via getSingleton('form-config'), returns the config or a sensible default (the current frozen questions.ts structure).
    • What this accomplishes: Any part of the app can fetch the current form config. Falling back to questions.ts means a fresh install still works before an admin has customized anything.
  • Implement updateFormConfig(config, updatedBy). Validates config shape, enforces two rules — unique question IDs and no dropping IDs that already have responses — and writes via setSingleton.
    • What this accomplishes: Prevents admins from accidentally corrupting the applicant data by renaming, duplicating, or deleting questions that people have already answered.
  • For the "no dropping IDs in use" rule, before writing, query applicant_data and collect all question IDs referenced in existing applicationResponses objects. If the new config drops any of them, reject with 400.
    • What this accomplishes: Editing questions mid-application-cycle is a real admin need (typos, added clarifications), but it must not silently orphan applicant data.

Form config endpoints

  • Implement GET /api/v1/admin/form-config/route.ts. Calls getFormConfig(), returns the config.
    • What this accomplishes: The admin settings UI's form config editor loads the current config from here.
  • Implement POST on the same route. Parses the body, calls updateFormConfig, returns success or the validation error.
    • What this accomplishes: The "save form config" button writes the new config.

Consumer integration

  • The application form's frontend currently reads from a hardcoded questions.ts. This sprint's scope is just to make getFormConfig() and the endpoint work; wiring the applicant form to fetch from /api/v1/admin/form-config (or from the server) is Ticket 2's frontend concern and can slide to next sprint.
    • What this accomplishes: Keeps this ticket focused on the admin side. The applicant-side integration is a small follow-up.

Auth gating

  • Wire requireAdmin() into every write endpoint: POST on all three date singletons, POST on show-decision, POST on form-config.
    • What this accomplishes: Only admins can change configuration. Any authenticated user can still GET these values (needed by the applicant-side status machine).
  • Update the updatedBy field on writes to come from session.user.email instead of the placeholder.
    • What this accomplishes: Real audit trail. Every config change is traceable to a specific admin.

Definition of done

  • The show-decision toggle on /admin/settings persists on save.
  • Admins can add, edit, reorder, and delete questions via /admin/settings, and the changes persist.
  • Attempting to save a form config with duplicate question IDs or with a dropped-but-in-use ID returns a 400.
  • Every write endpoint under settings is requireAdmin()-gated.

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions