Files
baya-monorepo/archive/build-chain/working-context/reports/frontend-phase-5-report.md
T
2026-08-02 18:48:32 +03:30

8.9 KiB
Raw Blame History

Frontend Phase 5 — Nurse verification flow (trust engine) — Report (2026-07-09)

Builds the trust engine's front end: the staged, platform-owned verification a nurse walks before any service can go live. A nurse lands on a status checklist (B3), submits identity (B4), submits professional credentials (B5), and waits on under-review (B6) until an admin decides — then a trust badge renders and the publish gate unlocks. Consumes the b6 verification contract. Unlocks a bookable verified nurse + the <TrustBadge> f6 reuses.

What was built

services/verification domain (client/src/services/verification/)

  • types.ts — DTOs mirrored from verification.md (camelCase wire): VerificationStatus (aggregate status + isBookable + blockingSteps + ordered steps[]), VerificationStep, RunStepResult, UploadUrlResult, DocumentConfirmedResult, VerificationDocument (metadata only), NurseCredential, TrustBadge, the VerificationApi seam, and the string-literal enums (aggregate/per-step status, the six step codes, credential type, verification method, BadgeState). Helpers: isApproved, ownBadgeState (own-profile, computes expired), publicBadgeState (public/search — verified/unverified only), SPECIALTY_PRESETS.
  • validation.tsisValidNationalId (10-digit mod-11 checksum; rejects all-same-digit).
  • keys.tsverificationKeys.status() (the single cached source B3+B6 read), .documents(code), .badge(nurseId).
  • constants.tsUSE_VERIFICATION_MOCK (default true), the status staleTime (30 s) + badge staleTime/gcTime, the document type/size caps (jpg/png/pdf, 5 MB), NATIONAL_ID_LENGTH.
  • apis/clientApi.ts (real HTTP, action-style routes, XHR signed-URL PUT for upload progress + SHA-256 integrity hash), mockApi.ts (primary, full journey + dev-only admin sim), selecting index.ts. Both implement VerificationApi; swap is one line.
  • hooks/ — one per file: useVerificationStatus (query), useStartVerification (setQueryData), useSubmitIdentity (runs KYC → chained Shahkar), useRunBankVerification, useUploadVerificationDocument (progress via vars), useSubmitCredentials, useNurseTrustBadge. Every mutation invalidates status() (badge where relevant), so the checklist re-renders from cache with no manual refetch.

Screens — nurse verification route subtree (app/[locale]/(private-routes)/nurse/verification/)

  • B3 page.tsx — the hub: loading skeleton, error+retry, not_started start-CTA, the in-progress "X از Y" meter + data-driven checklist (VerificationChecklist reusing the shared StatusChip), a blocking summary, a single continue CTA that routes to the next actionable step (calls useStartVerification first when not_started), and the terminal approved state (publish link).
  • B4 identity/page.tsx — national-ID field (checksum) + national-ID card + liveness selfie local captures (identity stores no server document — they feed the automated KYC), the honest auto-registry note, submit → useSubmitIdentity. Handles national-ID mismatch (failed) and the non-accusatory shared-SIM Shahkar failure distinctly.
  • B5 credentials/page.tsx — INO number + specialty chips (presets + add-your-own) + a <DocumentUpload> per manual credential step (data-driven from status) each moving its step to in_review, + an optional education-cert local upload + optional registry fields; submit → useSubmitCredentials, lands on B6. Copy reflects manual review, never an automated authority check.
  • B6 review/page.tsx — the under-review resting screen: "در حال بررسی" + the 2448h note + a condensed mini-checklist (reusing StatusChip) — a focused second view of the same cached status() query, not a second fetch. CTA back to B3.
  • verificationSteps.ts — the data-driven glue: displaySteps (prepends a synthetic passed mobile step), progressCounts, stepLabelKey/stepDescriptionKey, stepStatusChip (the green/amber/grey/red legend), routeForStep, nextActionRoute/nextActionableIndex.
  • Journey stepper: B4/B5/B6 reuse the shared StepperHeader (identity → credentials → review).

Shared components (with co-located tests)

  • <DocumentUpload> — the reusable uploader: client type/size validation before upload, the full idle → uploading(%) → success(✓ + name / local image preview) → error(retry) machine, re-upload on reject, server-metadata as the "uploaded" truth, and a local-capture mode (B4). Its state chrome uses the verification namespace; the caller passes the field label/hint.
  • <TrustBadge state=…> — verified / unverified / expired off --bal-* tokens. Rendered on the nurse's own profile; exported so f6 reuses it in search results + the public profile.

Wiring

  • Publish gatenurse/services/PublishGate.tsx (in MyServicesList): the go-live CTA is disabled with a blocked-until-verified explanation (+ link to B3) until the aggregate is approved. Mirrors the server's guarded is_verified flip.
  • Trust badge on the nurse profile — sourced from the own VerificationStatus via ownBadgeState; the unverified banner now shows only until verified.
  • 6 AppIcons (upload/document/refresh/identity/license/publish), 4 route constants, the verification i18n namespace (123 keys) in both locales in sync.

What is now testable, and exactly how

Run npm run dev, sign in as a nurse (mock auth code 123456 if USE_AUTH_MOCK), open /nurse/verification:

  1. Checklist: B3 shows "X از Y" with the mobile step already green, the rest not_started. The continue CTA calls start (seeds steps) then routes to B4.
  2. Identity (B4): a valid کد ملی + card image (watch the uploader progress → ✓) + selfie → submit → the identity_kyc + shahkar_match steps update on B3 without a refresh. National-ID 0000000000 → failed KYC; national-ID 1111111111 → the non-accusatory shared-SIM Shahkar message.
  3. Credentials (B5): INO number + upload each manual document (→ in_review) + specialty chips → submit → lands on B6 ("در حال بررسی", 2448h, mini-checklist).
  4. Approval flips verified: the dev-only "Simulate admin review" panel on B3/B6 (mock-flag-gated — stands in for the deferred f15 admin queue) → Approve all → B3 shows approved, the trust badge on the nurse profile shows verified, and the publish CTA on /nurse/services is enabled.
  5. Rejected step: Reject a document → the step shows its rejection reason + a working re-upload path; the publish CTA stays blocked.
  6. React Query Devtools shows one verification.status query feeding B3 + B6 and invalidating on each mutation. Toggle /en/fa (RTL) and dark mode — strings + layout flip.

What is mocked / waiting on a real service

services/verification runs behind verificationMockApi (USE_VERIFICATION_MOCK = true) — b6 isn't reachable in this environment, so the mock drives the full journey (identity/Shahkar/bank runs, document uploads, admin-decision sim). The swap is one line (USE_VERIFICATION_MOCK = false): verificationClientApi is wired to every b6 route (nurse_verification/*, nurses/{id}/trust_badge), same hook signatures + query keys, no call-site change. See the mocks-registry row for the deterministic test triggers. Vendor calls (KYC/Shahkar/credential/IBAN/object-storage) are mocked server-side by b6 — the front end consumes them as if real.

Contracts consumed + gaps filed

  • Consumed: verification.md + openapi/swagger.v1.json (b6).
  • Filed: REQ-011 — a nurse-facing endpoint for the structured credential details (INO number, specialties, license fields) B5 collects; the contract records these only on the admin decide, so the real submitCredentialDetails no-ops until it lands (the document uploads are contract-backed). Also flagged: VerificationStepDto has no isRequired (the client treats every seeded step as required).

Follow-ups for later phases

  • f6 reuses <TrustBadge> (import from @/components) on search results (C2) + the public nurse profile (C3), sourced from useNurseTrustBadge(nurseId) / publicBadgeState. The expired state is own-profile only (the public badge payload carries isVerified only).
  • f12 payout depends on the bank_account_verification step (this phase deep-links it to the f2 bank screen).
  • The admin verification review queue (pass/reject, doc viewer, credential entry) is f15 — the dev-only mock sim here is a stand-in, gated on USE_VERIFICATION_MOCK.
  • Deliver REQ-011 then wire submitCredentialDetails + flip USE_VERIFICATION_MOCK=false.