You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Question order is write-once. There is no way to reorder questions — for global questions or for position questions — anywhere in the product.
Confirmed in code:
order is assigned at creation only, as max(order) + 1 (prisma/actions/global-questions.ts:40-49, prisma/actions/position-question-actions.ts:46-59)
Neither update action accepts or writes order. baseQuestionSchema carries label, type, required, options and allowOther — order is not in it (prisma/actions/global-questions.ts:78-81, position-question-actions.ts:92-95)
No reorder action exists in prisma/actions/
The value is displayed and sortable in the admin table, which makes it look editable when it is not
The only current workaround is to delete and recreate questions in the desired sequence — which is destructive:
Global questions:GlobalAnswer is unique on (userId, globalQuestionId), so recreating a question orphans every user's stored answer to it and silently resets that field across the whole user base
Position questions: existing PositionApplicationAnswer rows keep pointing at the soft-deleted question, so submitted applications and in-progress drafts diverge
Soft deletion also leaves permanent gaps in the sequence, since nothing renumbers.
Server side
A single reorder action per question type, taking the full ordered list of ids and rewriting order inside one transaction — rather than per-item swap actions, which are racy and produce inconsistent intermediate states.
Validate that the submitted id set exactly matches the current live set for that scope, so a stale client cannot drop or inject a question.
UI — drag and drop
Reordering is drag-and-drop, on both /global-questions and the position edit page.
Recommended library: @dnd-kit (@dnd-kit/core + @dnd-kit/sortable). It is the current standard for React 19, ships a keyboard sensor and screen-reader announcements out of the box, and does not depend on react-dom internals the way the deprecated react-beautiful-dnd does. Radix provides no drag primitive, so something has to be added.
Adding a dependency is a bundle decision (.claude/docs/ENGINEERING.md §6). Worth noting the net effect here is favourable: #390 removes @tanstack/react-table (zero references) and @tanstack/react-query (zero useQuery/useMutation consumers, yet wrapping the whole app in a client provider), so this can land without growing the bundle overall.
Keyboard operability is not optional. A pointer-only reorder is inaccessible and would fail .claude/docs/ENGINEERING.md §5. Every question must be reorderable via keyboard — pick up, move, drop, cancel — with the position change announced to assistive tech.
Keep the drag handle a distinct control rather than making the whole card draggable, so the existing Edit and Delete buttons stay clickable and the card is still selectable text.
Acceptance criteria
Behaviour
Admins can drag to reorder global questions at /global-questions
Admins and position managers can drag to reorder questions on a position's edit page
Order persists on drop via the reorder action, with an optimistic update
A failed save reverts the list to its previous order and shows an error toast — the UI must never show an order the server rejected
Order is renumbered contiguously, closing gaps left by soft-deleted questions
The applicant-facing form and the profile page reflect the new order immediately (both already order by order)
Server
Reordering is a single transactional write; no intermediate state where two questions share an order
The submitted id set is validated against the live set for that scope
Authorization matches the existing question actions — admin for global, checkPositionAccess for position
Accessibility and input
Full keyboard support: pick up, move, drop, and cancel
Position changes announced to screen readers ("Question moved to position 3 of 7")
Drag handle is a labelled control with a visible focus ring
Touch drag works, and the handle meets the ~44px target from .claude/docs/DESIGN.md §7
Verified at 375px as well as desktop
Decisions needed
Does reordering affect how existing applications display? Answers are currently rendered in createdAt order on the review page, not question order, so reordering will not re-sequence answers on already-submitted applications. That is arguably correct — it preserves the order the applicant actually saw — but it should be a deliberate choice rather than an accident.
There is no unique constraint on order ((positionId, order) or global). The comment at position-question-actions.ts:45 claims the transaction "prevents duplicate order values under concurrent inserts" — under READ COMMITTED it does not, and nothing catches the collision. Worth adding the constraint as part of this work, since reordering makes duplicates much easier to produce.
Problem
Question order is write-once. There is no way to reorder questions — for global questions or for position questions — anywhere in the product.
Confirmed in code:
orderis assigned at creation only, asmax(order) + 1(prisma/actions/global-questions.ts:40-49,prisma/actions/position-question-actions.ts:46-59)order.baseQuestionSchemacarrieslabel,type,required,optionsandallowOther—orderis not in it (prisma/actions/global-questions.ts:78-81,position-question-actions.ts:92-95)prisma/actions/The only current workaround is to delete and recreate questions in the desired sequence — which is destructive:
GlobalAnsweris unique on(userId, globalQuestionId), so recreating a question orphans every user's stored answer to it and silently resets that field across the whole user basePositionApplicationAnswerrows keep pointing at the soft-deleted question, so submitted applications and in-progress drafts divergeSoft deletion also leaves permanent gaps in the sequence, since nothing renumbers.
Server side
A single reorder action per question type, taking the full ordered list of ids and rewriting
orderinside one transaction — rather than per-item swap actions, which are racy and produce inconsistent intermediate states.Validate that the submitted id set exactly matches the current live set for that scope, so a stale client cannot drop or inject a question.
UI — drag and drop
Reordering is drag-and-drop, on both
/global-questionsand the position edit page.Recommended library:
@dnd-kit(@dnd-kit/core+@dnd-kit/sortable). It is the current standard for React 19, ships a keyboard sensor and screen-reader announcements out of the box, and does not depend onreact-dominternals the way the deprecatedreact-beautiful-dnddoes. Radix provides no drag primitive, so something has to be added.Adding a dependency is a bundle decision (
.claude/docs/ENGINEERING.md§6). Worth noting the net effect here is favourable: #390 removes@tanstack/react-table(zero references) and@tanstack/react-query(zerouseQuery/useMutationconsumers, yet wrapping the whole app in a client provider), so this can land without growing the bundle overall.Keyboard operability is not optional. A pointer-only reorder is inaccessible and would fail
.claude/docs/ENGINEERING.md§5. Every question must be reorderable via keyboard — pick up, move, drop, cancel — with the position change announced to assistive tech.Keep the drag handle a distinct control rather than making the whole card draggable, so the existing Edit and Delete buttons stay clickable and the card is still selectable text.
Acceptance criteria
Behaviour
/global-questionsorder)Server
ordercheckPositionAccessfor positionAccessibility and input
.claude/docs/DESIGN.md§7Decisions needed
createdAtorder on the review page, not question order, so reordering will not re-sequence answers on already-submitted applications. That is arguably correct — it preserves the order the applicant actually saw — but it should be a deliberate choice rather than an accident.Related
order((positionId, order)or global). The comment atposition-question-actions.ts:45claims the transaction "prevents duplicate order values under concurrent inserts" — under READ COMMITTED it does not, and nothing catches the collision. Worth adding the constraint as part of this work, since reordering makes duplicates much easier to produce.@tanstackdependencies — sequencing this first keeps the bundle flat)From the 2026-08-10 full platform audit.