Summary
Allow users to choose how many problems are selected when starting an exam. Clicking Start New Exam should open a configuration modal with synchronized numeric and slider controls, defaulting to 5 problems and constrained to 1–20.
Background / Context
The Exams page currently creates an exam immediately with a hard-coded request:
{ "maxProblemCount": 10 }
The existing create-exam API and frontend CreateExamRequest already support maxProblemCount. The frontend also has a shared Modal component that should be reused. Backend request validation currently permits values from 1 through 100, which does not match the new product limit.
Problem
Users cannot choose the size of a new exam. Every exam started from the Exams page requests 10 problems, and the API permits values above the intended maximum of 20.
Goal / Expected Behavior
- Clicking Start New Exam opens a modal instead of immediately sending a create request.
- The modal contains a numeric input and range slider representing the same problem count.
- Both controls default to 5 and remain synchronized.
- Valid values are whole numbers from 1 through 20, inclusive.
- Empty, decimal, or out-of-range numeric input displays concise validation feedback and disables exam creation.
- Confirming a valid value sends it as
maxProblemCount.
- Existing loading, navigation, query invalidation, and active-exam conflict behavior remains intact.
- The backend rejects
maxProblemCount values outside 1–20.
Scope
This issue should cover:
- Add the problem-count configuration modal to the Exams page.
- Add synchronized numeric and range inputs.
- Add client-side whole-number and range validation.
- Submit the selected count through the existing create-exam request.
- Change backend create-exam request validation to 1–20.
- Add focused frontend and backend automated tests.
Out of Scope
This issue should not cover:
- Persisting the previously selected count between modal openings or sessions.
- Changing problem-selection scoring or eligibility.
- Changing behavior when fewer eligible problems exist than requested.
- Redesigning exam history or the active exam experience.
- Introducing a reusable slider/input abstraction or broader form framework.
Chosen Implementation Approach
Reuse frontend/src/components/Modal.tsx for a local configuration dialog in ExamsPage. Keep the typed numeric value in a form state that can represent temporary invalid input, derive the validated integer separately, and disable submission until it is a whole number within 1–20. Keep the slider bound to valid numeric values and synchronize both controls when either changes.
Reset the selector to 5 each time the modal is newly opened. Provide explicit Cancel and Create Exam actions. During creation, disable submission and retain the existing Creating... feedback. If the API returns ACTIVE_EXAM_EXISTS, close the configuration modal before showing the existing continuation prompt.
Update the Pydantic boundary on CreateExamRequest.maxProblemCount from 1–100 to 1–20 so all API callers follow the same product rule.
Implementation Plan
The implementor should:
- Add modal visibility and problem-count form state to
ExamsPage.
- Change Start New Exam to reset the value to 5 and open the modal without issuing a POST request.
- Render labeled numeric and range inputs with
min=1, max=20, and step=1; synchronize them and expose accessible validation feedback.
- Add Cancel and Create Exam actions, disabling creation for invalid input or a pending mutation.
- Submit the validated value through the existing
{ maxProblemCount } request and preserve existing success behavior.
- Close the modal before showing the existing active-exam conflict prompt.
- Change backend request validation to reject values below 1 or above 20.
- Add the required frontend interaction tests and backend API boundary tests.
Relevant Files / Areas
Likely relevant areas:
frontend/src/pages/ExamsPage.tsx
frontend/src/pages/ExamsPage.test.tsx
frontend/src/components/Modal.tsx (reuse only; modification is not expected)
backend/app/presentation/exam_serialization.py
backend/tests/api/test_exams.py
Tests Required
The implementor must add or update automated tests covering:
- Clicking Start New Exam opens the modal without sending a POST request.
- Numeric and slider controls initially show 5 and expose limits 1–20.
- Changing either control updates the other.
- Empty, decimal, zero, negative, and above-20 typed values show validation and disable creation.
- Re-entering a valid whole number clears validation and enables creation.
- Confirming a valid value sends the corresponding
maxProblemCount.
- Cancel closes the modal without creating an exam.
- Reopening the modal resets the value to 5.
- Pending creation prevents duplicate submission and displays loading feedback.
ACTIVE_EXAM_EXISTS closes the configuration modal and shows the existing continuation prompt.
- Backend validation accepts boundary values 1 and 20.
- Backend validation rejects 0 and 21.
At minimum, tests should verify:
- The valid creation happy path.
- Both directions of input synchronization.
- Invalid typed-input behavior.
- API boundary enforcement.
- Existing active-exam conflict behavior.
If automated tests are genuinely not feasible, the implementor must explain why in the PR and provide stronger manual verification steps.
Manual Verification / Self-Check
Before claiming this issue is done, the implementor must:
- Open the Exams page and verify the modal, default value, synchronized controls, validation, Cancel action, and successful creation.
- Verify keyboard entry and slider operation at both boundaries.
- Verify that an existing active exam still produces the continuation prompt.
- Run the relevant automated tests and frontend build.
- Record the exact commands and results in the PR description, along with changes made, tests added, manual verification, known limitations, and follow-up work.
Suggested verification commands:
cd frontend
npm test -- --run src/pages/ExamsPage.test.tsx
npm run build
cd backend
uv run pytest tests/api/test_exams.py
Reviewer Acceptance Checklist
The reviewer should verify that:
Dependencies
None.
Follow-Up Work
None currently identified.
Definition of Done
This issue is done when:
- Users can configure and create an exam containing a requested maximum of 1–20 problems through synchronized controls.
- Invalid values cannot be submitted and receive accessible feedback.
- The backend rejects requests outside the same range.
- Existing exam creation and active-exam behavior remains functional.
- Required automated tests pass.
- The PR documents exact test commands, results, and manual verification.
Summary
Allow users to choose how many problems are selected when starting an exam. Clicking Start New Exam should open a configuration modal with synchronized numeric and slider controls, defaulting to 5 problems and constrained to 1–20.
Background / Context
The Exams page currently creates an exam immediately with a hard-coded request:
{ "maxProblemCount": 10 }The existing create-exam API and frontend
CreateExamRequestalready supportmaxProblemCount. The frontend also has a sharedModalcomponent that should be reused. Backend request validation currently permits values from 1 through 100, which does not match the new product limit.Problem
Users cannot choose the size of a new exam. Every exam started from the Exams page requests 10 problems, and the API permits values above the intended maximum of 20.
Goal / Expected Behavior
maxProblemCount.maxProblemCountvalues outside 1–20.Scope
This issue should cover:
Out of Scope
This issue should not cover:
Chosen Implementation Approach
Reuse
frontend/src/components/Modal.tsxfor a local configuration dialog inExamsPage. Keep the typed numeric value in a form state that can represent temporary invalid input, derive the validated integer separately, and disable submission until it is a whole number within 1–20. Keep the slider bound to valid numeric values and synchronize both controls when either changes.Reset the selector to 5 each time the modal is newly opened. Provide explicit Cancel and Create Exam actions. During creation, disable submission and retain the existing
Creating...feedback. If the API returnsACTIVE_EXAM_EXISTS, close the configuration modal before showing the existing continuation prompt.Update the Pydantic boundary on
CreateExamRequest.maxProblemCountfrom 1–100 to 1–20 so all API callers follow the same product rule.Implementation Plan
The implementor should:
ExamsPage.min=1,max=20, andstep=1; synchronize them and expose accessible validation feedback.{ maxProblemCount }request and preserve existing success behavior.Relevant Files / Areas
Likely relevant areas:
frontend/src/pages/ExamsPage.tsxfrontend/src/pages/ExamsPage.test.tsxfrontend/src/components/Modal.tsx(reuse only; modification is not expected)backend/app/presentation/exam_serialization.pybackend/tests/api/test_exams.pyTests Required
The implementor must add or update automated tests covering:
maxProblemCount.ACTIVE_EXAM_EXISTScloses the configuration modal and shows the existing continuation prompt.At minimum, tests should verify:
If automated tests are genuinely not feasible, the implementor must explain why in the PR and provide stronger manual verification steps.
Manual Verification / Self-Check
Before claiming this issue is done, the implementor must:
Suggested verification commands:
Reviewer Acceptance Checklist
The reviewer should verify that:
maxProblemCount.Dependencies
None.
Follow-Up Work
None currently identified.
Definition of Done
This issue is done when: