# Module Audit — v3

Audit date: 21 August 2026

## Verification summary

The v3 source was reviewed and corrected specifically for:

- frontend responsiveness/overflow risk
- popup/modal behavior
- Super Admin question creation with answer keys
- Reasoning / Quantitative Aptitude / English Reading / English Writing / English Speaking / Coding content paths
- stable random question assignment
- candidate-safe question delivery
- scoring against the exact assigned question snapshot
- company tenant isolation retained from v2

### Automated checks performed

`qa/run_checks.sh` passes all checks:

1. all backend PHP files pass `php -l`
2. all 23 frontend JS/JSX files parse successfully using the installed TypeScript parser
3. all 41 frontend API references map to implemented backend route patterns
4. objective-answer comparison tests pass for single choice, multiple choice, true/false and numeric types
5. secure shuffle returns valid permutations and multiple distinct orders
6. candidate delivery and score maximum use the frozen `assignment_questions` snapshot
7. candidate response payload excludes answer keys and evaluator-only metadata
8. Platform Question Bank, responsive modal layer, dashboard counts and role permissions pass source consistency checks
9. requested seeded categories, answer examples and randomized demo sections are present

## Frontend / layout audit

### Fixed

- Replaced browser-native confirmation/prompt dialogs with reusable `Modal` / `ConfirmModal` components.
- Modal overlay uses `position: fixed`, full-screen inset and `z-index: 1000`.
- Modal card has viewport-constrained maximum height and an independently scrollable body.
- Mobile modal aligns from the bottom and stacks footer buttons at very small widths.
- Long question text uses safe wrapping.
- Tables remain inside horizontal scroll wrappers.
- Question pools use bounded vertical scrolling rather than expanding indefinitely.
- Option-answer rows collapse to two columns on mobile.
- Question paper builder becomes one column below 1100px.
- Candidate exam questions collapse to a one-column card layout on mobile.
- Exam header truncates long titles on very small screens rather than overlapping the timer.
- Results review layout becomes vertical on mobile.

### Environment limitation

A true screenshot/browser click-through could not be completed in this execution environment because Chromium local navigation is blocked by the environment administrator and Playwright's bundled browser is not installed. `npm install` also exceeded the environment timeout, so a Vite production bundle could not be executed here.

This means the frontend has passed **source syntax, route/API consistency review, responsive CSS review and popup/overflow hardening**, but final visual acceptance should still be run after `npm install && npm run build` in your deployment/dev environment.

## Platform Super Admin

### Dashboard

Status: source-verified.

Added counts for:

- global categories
- global questions

Company dashboard `Available Questions` now counts both the company-private bank and reusable Platform-global questions, matching what the paper builder can actually use.

Added direct navigation to the Platform Question Bank.

### Platform Question Bank

Status: added and source-verified.

Route:

```text
/admin/questions
```

Functions:

- create global category
- create objective question
- create options
- select correct single answer
- select multiple correct answers
- set true/false answer
- set numeric answer
- create writing/coding/speaking prompts
- store reference response/evaluator guidance
- store scoring rubric
- list global questions and answer-key state

Backend validates that choice-answer keys point to actual non-empty options.

## Company Question Bank

Status: source-verified.

A company receives:

```text
its own questions + Platform global questions
```

It does not receive another company's private questions.

Platform questions are marked `Platform`; tenant-created questions are marked `Company` in the UI.

## Category coverage

The demo seed now creates global categories for:

- Reasoning
- Quantitative Aptitude
- English Reading
- English Writing
- English Speaking
- Coding

The seed includes multiple objective questions with answers for Reasoning, Quantitative Aptitude and English Reading. Writing, Speaking and Coding include evaluator/reference guidance and rubrics because those question types should not be scored using a single fixed string answer.

## Question paper builder

Status: corrected.

Each section now supports:

```text
selection_mode = manual | random
question_count = N (random mode)
shuffle_questions = true | false
question_ids = question pool
```

Company users can select tenant-private or Platform-global questions as long as the category is available to that tenant.

The backend rejects:

- empty question pools
- invalid/foreign-company questions
- random count greater than pool size
- categories unavailable to the company

## Random question assignment

### Previous v2 behavior

Not random. Candidate delivery read directly from `paper_questions ORDER BY sort_order`.

### v3 behavior

Fixed.

At assignment creation:

```text
paper_questions (pool)
       ↓ secure sample/shuffle
assignment_questions (candidate snapshot)
```

`assignment_questions` is then used for:

- candidate session question delivery
- answer membership validation
- speaking-answer membership validation
- section scoring
- total maximum score

This avoids the common bug where a refresh creates a new random exam.

Example:

```text
Reasoning pool: Q1 Q2 Q3 Q4 Q5 Q6
Random count: 3

Candidate A snapshot: Q5 Q1 Q3
Candidate B snapshot: Q2 Q6 Q4

Candidate A refresh: Q5 Q1 Q3 (unchanged)
```

The shuffle algorithm uses PHP `random_int()` rather than a predictable browser shuffle.

## Candidate exam

Status: source-verified.

- assigned paper only
- candidate/company/assignment match required
- section timer enforced server-side
- answer auto-save endpoint validates that the question is in the active candidate snapshot
- correct answers are not selected by the candidate session query
- section auto-submit remains present
- custom submit confirmation modal added
- objective question components remain supported
- writing textarea supported
- coding editor supported
- speaking MediaRecorder upload supported

## Scoring

Status: source/unit-verified for objective comparison logic.

Tested source logic:

- single-choice match/mismatch
- multiple-choice answer order independence
- true/false
- numeric string vs numeric correct value
- numeric mismatch

Maximum score now sums only candidate-assigned questions, which is required for random papers.

## Results/evaluation

Status: corrected.

- result list remains company-scoped
- detail endpoint remains company-scoped
- Recruiter result detail no longer receives evaluator-only correct answers, rubrics, reference guidance, or internal explanation
- manual scoring remains company-scoped
- writing/coding/speaking score entry now uses an in-app modal instead of sequential browser prompts
- score field has min/max validation
- reviewer remarks are entered in the same dialog

## Tenant isolation regression check

v2 protections remain:

- candidate belongs to one company
- company staff derive tenant from login
- external API derives tenant from API credential
- assignments have tenant composite FKs
- candidate cannot access another company's assignment
- manual evaluator cannot score another company's answer
- company paper creation cannot reference another company's private question

Global Platform questions are the only intentional cross-tenant reusable content and are represented by `company_id IS NULL`.

## Database verification limitation

No MySQL/MariaDB server binary exists in the execution environment, so the schema, migrations, seed and SQL-backed request flows could not be executed against a live MySQL instance here.

Before production release, run the checklist in `PRODUCTION_CHECKLIST.md` against MySQL 8+ and a real built React frontend.

## v4 Desktop-only examination enforcement

Candidate examinations now require a desktop/laptop browser with a minimum 1024px viewport. The restriction is enforced both by the React exam route and by PHP candidate-exam endpoints. Login, OTP, and the candidate dashboard remain responsive; Admin and Company portals are unchanged. See `DESKTOP_ONLY_UPDATE.md` and `QA_RESULTS_V4.txt`.
