Draft: feat(validation): complete zod migration and align ids with backend contracts
## Overview
This MR is a branch-wide consolidation of the `zod-validations` work. It hardens frontend validation and API contract handling across EHRS, migrates major forms to shared Zod schemas with `react-hook-form`, adds book-number-based password recovery, and integrates Corpus audio recording/upload into the KYP flow.
The main problem this solves is inconsistent page-level validation and weak runtime guarantees at the API boundary. Before this change, validation rules were duplicated across screens, several flows relied on ad-hoc parsing, and backend response drift could surface late as UI bugs. This MR centralizes those rules, makes failures explicit, and adds regression coverage around the affected flows.
## What does this MR do and why?
The goal was to finish the validation migration and use it to stabilize the remaining auth, volunteer, and admin flows that were still relying on local/manual checks.
Approach taken:
- Centralize domain schemas under `src/lib/validations/*`
- Validate API responses in `src/lib/api.ts` using shared Zod schemas
- Migrate forms to `react-hook-form` + `zodResolver`
- Split Corpus upload concerns into dedicated service/hooks/components
- Back the refactor with broader page, component, hook, and API tests
This approach was chosen because it reduces duplication, keeps validation logic close to domain models instead of individual UI components, and gives the frontend a single place to enforce request/response contracts.
Trade-offs:
- This MR is large and mixes feature work, refactors, tests, and config changes, so review scope is high
- Stricter runtime validation may surface pre-existing backend inconsistencies that were previously ignored
- Corpus upload depends on a separate service and browser microphone/location permissions
## Changes Made
- Added shared Zod validation modules for auth, patient, doctor, camp, consultation, prescription, medicine, family, role request, queue, vitals, KYP, attendance, donation, and volunteer camp flows under `src/lib/validations/`
- Added runtime API response validation in `src/lib/validations/api-responses.ts` and applied it across `src/lib/api.ts`
- Added reusable validation hook `src/hooks/useFormValidation.ts`
- Added auth recovery pages `src/pages/ForgotPasswordPage.tsx` and `src/pages/ResetPasswordPage.tsx`, and updated routing in `src/App.tsx`
- Updated `src/pages/LoginPage.tsx` for book-number login, phone lookup, and OTP-based password reset flow
- Migrated major forms to `react-hook-form` + Zod across login, volunteer registration, manage doctors, assign roles, camp analytics, medical camps, donation, KYP, patient registration, vitals, counseling, prescription/medicine verification, profile, and shared volunteer/admin components
- Added Corpus integration for KYP:
- `src/services/corpusApi.ts`
- `src/types/corpus.ts`
- `src/hooks/useCorpusSession.ts`
- `src/hooks/useCorpusUpload.ts`
- `src/hooks/useRecorder.ts`
- `src/components/CorpusAudioRecorder.tsx`
- `src/components/CorpusUploadForm.tsx`
- Updated config/tooling:
- `.env.example` adds `VITE_CORPUS_SERVER_URL`
- `.husky/pre-commit` now runs i18n validation, changelog enforcement, tests, coverage, knip, and build
- `package.json` adds `i18n:migrate:*` and `i18n:validate`
- `scripts/merge-locales.cjs` and `scripts/migrate-locales.cjs` support `--check` / `--write`
- Expanded automated coverage across pages, hooks, components, services, API helpers, and validation modules
- Removed the old unit-level patient registration test in favor of newer page-level coverage
## Technical Details
### Root cause / motivation
- Validation rules were spread across pages and diverged over time
- Many API responses were trusted without runtime parsing
- Auth recovery and several admin/volunteer flows were brittle during contract/i18n changes
- KYP audio upload logic was not isolated into reusable pieces
### Implementation approach
- Domain schemas are now centralized in Zod modules and re-exported from `src/lib/validations/index.ts`
- `validateApiResponse(...)` is used at the API boundary so malformed responses fail fast with explicit context
- Forms use `react-hook-form` + `zodResolver` for consistent field and submit validation
- Server state remains in TanStack Query; auth state remains in `AuthContext`
- Corpus session, upload, and recorder logic are isolated into dedicated hooks/services/components to keep page logic thinner
### API / endpoint notes
- No backend API contract is intentionally changed by this MR
- The frontend now validates and consumes existing EHRS auth/patient/admin endpoints more strictly
- This MR also integrates the external Corpus API for login and chunked audio upload
## Type of Change
- [x]
- [x]
- [ ]
- [ ]
- [x]
- [x]
- [ ]
- [x] 🧪 Test update
- [x]
- [ ]
## Related Issues / References
- No linked GitLab issue number was found in the branch history
- Related to the ongoing validation hardening, auth recovery, and KYP/corpus integration work on `zod-validations`
## Screenshots or Screen Recordings
UI changes are included in this MR, but screenshots are not attached in this draft.
Recommended screenshots before merge:
- Login + phone lookup + forgot/reset password flow
- KYP page with recorder/upload states
- Updated admin form flows
- Patient registration / vitals / verification flows
## How to Set Up and Validate Locally
1. Checkout this branch and install dependencies:
```bash
git checkout zod-validations
bun install
```
2. Set env vars:
```bash
VITE_SERVER_URL=http://localhost:8000
VITE_SOCKET_URL=http://localhost:8000
VITE_CORPUS_SERVER_URL=https://api.corpus.swecha.org
```
3. Start the app:
```bash
bun dev
```
4. Validate the main flows:
- `/login`: test phone lookup, book-number login, and error handling
- `/forgot-password` -> `/reset-password`: send OTP by book number and submit new password
- Volunteer flows: patient registration, KYP, record vitals, counseling, verify medicines, quick search, family grouping
- Admin flows: manage doctors, medical camps, assign roles, camp analytics
- KYP Corpus flow: login to Corpus, record or upload audio, allow location permission, and verify upload progress / retry / success states
5. Run checks:
```bash
bun run lint
bun run i18n:validate
bun run test:run
bun run test:coverage
bun run build
```
## Testing Done
- [x] Manual testing completed
- [x] Unit/integration tests added or updated
Local verification on this branch includes:
- `bun run lint` -> passes with 2 existing warnings and no errors
- `bun run i18n:validate` -> passes
- `bun run build` -> passes
- Pre-commit verification on this branch also ran `test:run` and `test:coverage` successfully while creating the latest validation refactor commit
### Test Cases Covered
| Scenario | Expected Result | Status |
| -------- | --------------- | ------ |
| Shared Zod schemas and API response validators | Invalid payloads are rejected and valid contracts are parsed consistently |
| Login / forgot-password / reset-password flows | Book-number-based auth and OTP reset flow validate and handle errors correctly |
| KYP, patient registration, vitals, counseling, medicine verification, admin forms | Updated pages render, validate, submit, and handle success/error states without regression |
| Corpus recorder / upload hooks and components | Session, recording, upload, retry, and error states are covered |
## Code Quality / Reviewer Notes
- Shared validation logic is centralized instead of duplicated across pages
- API response validation is now explicit at the client boundary
- `.env.example`, changelog, locale scripts, and pre-commit hooks were updated as part of the workflow hardening
- Current lint/build/i18n validation pass; build still shows the existing large-chunk warning
- `knip` remains non-blocking, so unused-file/export cleanup is still follow-up work
## Known Limitations / Technical Debt
- This MR is large and spans multiple workstreams, so it is harder to review than it should be
- Runtime validation may expose backend response mismatches that were previously hidden
- Existing bundle size warnings are still present and not addressed here