EvalzoBuild with AI · design review
Design proposal · not implementedMapping is provisional

Developer handoff

What already exists, what this concept adds, and what has to be settled before building. Nothing in the ATS application or the shared Figma file was changed to prepare it.

How this was checked

The ATS repository folder was not readable from the design workspace, so no file was opened directly and no import path was verified against current source. Three kinds of evidence were available instead.

  • Snapshot read A saved copy of the source file was read in full: button.tsx, checkbox.tsx, ModalShell.tsx, StatusBadge.tsx, statusConfig.ts and PageHeader.tsx. Snapshot date 18 Aug 2026.
  • Indexed The file and its export appear in the ATS code index at the stated path. Contents, props and variants were not read.
  • Gap No reusable component was found. The concept follows the established pattern and flags it for a decision.

Tokens come from the Evalzo token snapshot, not from src/app/theme.css itself. The brief's inspected commit is 7edfd98 from 1 Sep 2026. Reconcile everything below against current main before implementation.

Component mapping

Concept elements mapped to repository components
Concept elementRepository sourceEvidenceNotes
Primary, secondary, tertiary, link and destructive buttonssrc/components/base/buttons/button.tsxSnapshot readColors primary, secondary, tertiary, link-color, primary-destructive. Sizes sm and md. isLoading for Replacing and Saving.
Checkboxes: sources, possible skills, library multi-selectsrc/components/base/checkbox/checkbox.tsxSnapshot readSize md.
Modal shellsrc/components/ModalShell.tsxSnapshot readUse maxWidth="max-w-[960px]". The shell always closes on Escape and backdrop click. It needs a way to block dismissal while selecting and saving. See open dependencies.
Host modal and method cardssrc/components/assessments/CreateWrittenAssessmentModal.tsxIndexedRemove the blurred Coming soon treatment. Rename the card to Build with AI.
Requisition selector and menusrc/components/job-descriptions/JDSelector.tsx, AnchoredDropdown.tsx, CustomSelect.tsxIndexedReuse reqLabel() for REQ ID plus title. Loading, empty, no results and error states must exist or be added.
Create requisitionsrc/components/CreateJDDrawer.tsxIndexedThe prototype drawer is a stand-in with fewer fields. Keep the real drawer's fields and validation. It already calls extractJdFields().
Edit requisition routesrc/components/job-descriptions/ViewJDDrawer.tsxIndexedOpened from the job description preview. Must return to the modal with inputs intact.
Requisition entry pointsrc/components/job-descriptions/LinkAssessmentModal.tsxIndexedShould open the same modal with the requisition preselected.
Editor page and question listsrc/app/create/page.tsx, components/QuestionsSection.tsxIndexedThe prototype editor is an approximation. Only the additions listed below are proposed.
Question rows, filters, library drawersrc/components/question-library/QuestionCard.tsx, QuestionFilters.tsx, QuestionLibraryDrawer.tsxIndexedReplace question reuses the drawer pattern. Library questions convert through convertLibraryQuestions().
Page header, breadcrumbs, statusPageHeader.tsx, Breadcrumbs.tsx, StatusBadge.tsxSnapshot readstatus="draft", variant with-dot. Breadcrumbs is indexed only.
Linked requisition card, change flowsrc/components/assessments/LinkedJdCard.tsx, ChangeJdModal.tsxIndexedUnchanged.
Create and upload questionsrc/app/create/components/AddMCQModal.tsx, AddCodingModal.tsxIndexedUnchanged. Shown as entry points only.
Unsaved changes confirmationsrc/app/create/components/UnsavedChangesModal.tsxIndexedPrototype copy is a stand-in. Keep the existing copy and buttons.
Toastssrc/components/Snackbar.tsxIndexedSuccess for replaced, removed, added and saved.
Loadingsrc/components/LoadingSkeleton.tsx, Loader.tsxIndexedSkeletons for requisition list and recommendation. Loader for selecting.
Inline errorssrc/components/ErrorAlert.tsxIndexedWarning, info and success variants are unverified.
Duration limitssrc/constants/assessmentDuration.tsIndexedMIN_DURATION_MINS, MAX_DURATION_MINS, clampDurationMins(). The brief reports 5 to 300.
Draft persistencesrc/app/create/hooks/useAssessmentFormSave.ts, useAssessmentPersistence.ts, services/assessment/assessmentService.tsIndexedcreateAssessment() and updateAssessment() exist. How AI selection plugs in is open.
Header, theme toggle, tooltipHeader.tsx, ThemeToggle.tsx, Tooltip.tsxIndexedShell stand-in only.
Icons@untitledui/iconsIndexedPrototype glyphs are stand-ins. Suggested names: Stars02, BookOpen01, SearchLg, XClose, Plus, Minus, SwitchHorizontal01, Trash01, Eye, Edit02, Lock01, AlertTriangle, AlertCircle, CheckCircle, RefreshCw01. Confirm each exists in the installed version.

Component gaps

These have no confirmed reusable component. None should be solved by adding a UI library. Each needs a decision within the repository-only component rule.

Controls without a verified component
ControlUsed forPattern followed in the concept
Gap Text inputAssessment title, requisition search, library searchThe 40px field in the Figma modal, 8px radius, gray-300 border.
Gap TextareaJob description in the requisition drawerSame field treatment. The real drawer's control takes precedence.
Gap Number stepperQuestion counts and durationThe minus, value, plus control in the Figma modal, with labelled buttons.
Gap Radio card groupMethod, replacement choiceThe Hovered/Selected card in Figma, plus a radio indicator. Built on native radios.
Gap Step indicatorJob details, Question setupTwo numbered marks. step_icon_selected.svg suggests a stepper exists somewhere. Locate it first.
Gap Filter chipReplace filters, library filtersQuestionFilters.tsx likely covers this. Confirm before building.
New Selection summaryAbove the question listCounts and tags only.
New Matches labelQuestion cards and alternativesA tag holding the mapped skill or topic. No generated prose.
New Stage list and result panelsSelecting, partial, failure statesComposed from existing buttons, alerts and tables.

Existing, proposed, open

Existing behavior kept

  • Centered modal as the entry, about 960px wide.
  • Manual path: empty draft, same validations.
  • Requisition is required for written assessments, per ticket 14ymvzwkx3k. This is product evidence, not verified deployed behavior.
  • Requisition creation and editing through the existing drawers.
  • Editor structure, Save, Preview and Publish as separate actions.
  • Create question, upload questions, candidate instructions.
  • Unsaved changes confirmation.

Proposed additions

  • Build with AI card enabled, with the label and helper text from the brief.
  • Two steps for the AI path, with Back preserving every input.
  • Job description preview with its source named.
  • Step two as a confirmation: one recommended mix and the duration.
  • The recommendation is shown in editable fields: two counts, a difficulty dropdown and a live total. Reset to recommendation appears after a change.
  • Non-dismissible selecting state and result panels.
  • Draft confirmation, selection summary and Matches label.
  • Remove, Replace and the replace drawer.

Open dependencies

  • Backend contract in 86d2cmctr: analysis, recommendation and selection as separate calls or one.
  • Which progress stages the service can report. Hide any it cannot.
  • Draft status lookup after a timeout, keyed so a retry cannot duplicate.
  • Whether replacement persists on its own or through the editor's Save.
  • Blocking dismissal in ModalShell during final persistence.
  • Whether question timing data exists. Without it, no estimate is shown.
  • Duplicate-content detection for alternatives.
  • Whether method cards open with nothing selected, as prototyped, or keep manual preselected.
  • Skills are never shown or edited in setup. Confirm that the backend needs no recruiter input on skills.

Open-ended questions. They appear in older designs and in a catalog enum, but the inspected editor and converter handle multiple choice and coding only. They are left out of every control here. Ticket 14ymvzwnf2r covers the authoring, persistence, attempt and scoring support they need before they can be offered.

Older ticket comments. References to the model authoring questions, to Vite and JSX, and to Express do not apply. The inspected app uses the Next.js App Router with React and TypeScript, and this concept selects from the repository.

Rules to revalidate

Rules encoded in the prototype and their status
RuleIn the prototypeStatus
Assessment title length3 to 70 characters after trimmingFrom inspected source. Revalidate. PageHeader allows 80 when editing in place, which conflicts.
Job descriptionMandatory on every requisition. The drawer blocks saving without one, and no missing-description state exists in the flow.Decided 28 Sep 2026. Confirm the existing drawer enforces it.
Title suggestionRole title plus Assessment. Follows the requisition until the recruiter types, then never changes.Proposed.
Duration5 to 300 minutes, default 60, steps of 5Range from inspected source. Default is a prototype value.
Question countsWhole numbers from 0. Zero of one type is valid. A total of zero is blocked.Proposed.
Maximum countThe stepper stops at 50 per typePrototype placeholder. The real limit is implementation configuration. Historical 5 to 20 and 1 to 30 limits are not carried forward.
DifficultyDropdown with Easy, Balanced, Hard. Opens on the recommended level. Maps to CustomSelect.tsx.Balanced is a mix. It is never stored on a question.
SourcesNo control in this version. Selection uses both permitted libraries.Decided 28 Sep 2026. Each question still shows its source in the editor.
Requisition changeClears role analysis and recommendation. Custom counts typed by the recruiter are kept.Proposed.
PublishDisabled with no questionsThe exact minimum is unverified.
CreditsNot shownNo verified billing contract exists for repository selection.

State inventory

Conditions, behavior and recovery actions
ConditionBehaviorRecovery
Requisitions fail to loadError inside the menu. Other fields untouched.Try again, Create new requisition
Role mapping unclearNo recommendation is shown and no skills are guessed.Edit requisition, Add questions manually
Recommendation unavailableRequirements stay. Mix is missing.Try again, Set up manually
Partial matchExact counts by type and coverage by skill. Nothing saved.Use these questions, Edit setup, Browse library
No matching questionsNo draft is created.Edit setup, Browse library
Selection unavailableSetup preserved.Try again, Back to setup, Browse library
Request timed outChecking draft status, then saved or not saved.Open draft, or Try again when nothing was saved
Draft save failedSelection kept in memory.Save draft again, Back to setup
Question became unavailableAffected question named before saving.Choose a replacement, or continue without it
Requisition archived mid-flowReturns to Job details. Other fields kept.Choose another requisition
No comparable alternativeEmpty state in the drawer.Change filters, Browse library
Replacement failedOriginal question stays in place.Try again, Cancel
Removals leave a gapActual composition and missing skill shown.Add from library
Leave with unsaved changesExisting confirmation.Keep editing, Discard changes

Accessibility

  • Method and difficulty are native radio groups inside fieldsets, so arrow keys and Space work without custom handling.
  • Requisition field is a combobox with a listbox. Arrow keys move, Enter selects, Escape closes the menu before the modal.
  • Focus moves to the heading when a modal, step or result opens, stays inside the top layer, and returns to the control that opened it.
  • Errors are text with an icon, linked through aria-describedby. Focus moves to the first invalid field.
  • Progress and results are announced through a polite live region. The live total is a status.
  • Steppers have labelled decrease and increase buttons and a labelled value.
  • Difficulty, selection and gaps always carry text and a shape, never color alone.
  • Reduced motion stops the spinner and removes transitions.
  • Touch targets are 44px at 390px. Desktop controls stay at the product's 40px.

Prototype deviations

  • Primary button fill. The prototype uses brand-700. The repository button uses brand-600, which gives 3.74:1 with white at 14px. This is a token question for the whole product, not part of this feature.
  • Editor and shell. Layout is approximated from component names and the July production audit. Treat only the additions as design intent.
  • Requisition drawer. Fewer fields than the real drawer. Upload attaches a sample document.
  • Selection. Simulated in the browser from 37 invented questions. It calls no production API.
  • Timings. Loading and progress delays are fixed for the demo. They say nothing about real latency.

Acceptance check

  • Existing library questions are being selected.Said in the card helper text, the step two description and the source on every question.
  • Both mixes are demonstrated.The recommendation fills the fields. The recruiter confirms it as is, or changes the counts and difficulty in place.
  • Job description is visible where it is chosen.Preview on step one and the linked requisition in the editor. Step two leaves it out by decision, to keep the confirmation quiet.
  • Creation yields a draft. Publication is separate.The footer note, the Draft status and a distinct Publish action.
  • Scope is truthful.Multiple choice and coding only. Open-ended is absent.
  • Partial results need a decision.Use these questions is explicit, and skill gaps persist into the editor.
  • Replace changes one question.Order is kept, and a failure leaves the original in place.
  • Evalzo layout and tokens are reused.Tokens are verbatim. Component reuse is mapped above and is provisional.
  • No invented claims.No credits, speed promises, confidence percentages or model name appear in any screen.
  • Every state connects.Each failure state has at least one recovery action that returns to the flow.