add build development phases
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
# Frontend Phase 5 — Nurse verification flow (mocked vendors)
|
||||
|
||||
> **Mission:** build the trust engine's front end — the staged, platform-owned verification flow a nurse
|
||||
> walks through before any of their services can go live. A nurse lands on a **status checklist** (B3),
|
||||
> submits **identity** (B4: national-ID + card image + liveness selfie), submits **professional
|
||||
> credentials** (B5: نظام پرستاری number + license + education + specialties), and waits on the
|
||||
> **under-review** screen (B6) until an admin decides. Documents upload to the object-storage-backed
|
||||
> endpoint with type/size validation and progress; each step shows its own status (and its rejection
|
||||
> reason); and a **trust badge** (verified / unverified / expired) renders on the nurse profile. Verified
|
||||
> trust is the entire brand — a nurse is **not bookable and cannot publish until verified**, and the UI
|
||||
> must say so honestly and never advertise a check the platform doesn't actually perform.
|
||||
>
|
||||
> **Track:** frontend · **Depends on:** [`frontend-phase-4-b5.md`](./frontend-phase-4-b5.md) (catalog browse + nurse service builder) and the **b6** verification contract · **Unlocks:** a bookable verified nurse + the search **trust badge** consumed in [`frontend-phase-6-b7.md`](./frontend-phase-6-b7.md)
|
||||
> **Before you start, read [`../_shared/agent-operating-rules.md`](../_shared/agent-operating-rules.md).** It is not optional.
|
||||
|
||||
---
|
||||
|
||||
## 1. Context — where this sits
|
||||
|
||||
This is the fifth feature slice of the customer/nurse front end and the **nurse side's gating step**.
|
||||
By f4 a nurse can build service variants, but those variants are **inert** — they cannot surface in
|
||||
search or be booked until `nurse_profiles.is_verified` is true. This phase builds the screens that flip
|
||||
that switch: the data-driven verification pipeline (six step types, all vendor calls **mocked** server-side
|
||||
behind DI seams in b6) rendered as a nurse-facing checklist, the two submission forms, the waiting state,
|
||||
the document uploader, and the public trust badge. When this lands, a nurse can go from "registered" to
|
||||
"verified and publishable", which is the prerequisite for everything downstream — search (f6), booking
|
||||
(f7), and ultimately payout (f12, gated on the bank-account verification step).
|
||||
|
||||
**What already exists (do not rebuild) — built by prior phases:**
|
||||
- **f0 foundations** ([`frontend-phase-0.md`](./frontend-phase-0.md)): the three actor app shells +
|
||||
route groups, the **nurse shell** ("نمای پرستار"), the `services/{domain}` + TanStack Query caching
|
||||
pattern (`keys.ts` factory, `apis/clientApi.ts`, one-hook-per-file), the contracts→`types.ts` pattern,
|
||||
the money/format utils, and the **shared composite components** — most importantly the **stepper/
|
||||
progress header** and the **status chip** (verified/pending/…). **Reuse both here; do not re-implement
|
||||
a stepper or a status chip.** The `verification` i18n namespace was reserved in f0 — fill it.
|
||||
- **f1-b2 auth** ([`frontend-phase-1-b2.md`](./frontend-phase-1-b2.md)): phone-OTP login, the role router,
|
||||
roles in `AuthContext`. The nurse arrives here already authenticated with the `nurse` role. **Step 1 of
|
||||
the checklist (شماره موبایل — mobile verified) is already satisfied at login** — render it as `passed`,
|
||||
don't ask for it again.
|
||||
- **f2-b3 onboarding** ([`frontend-phase-2-b3.md`](./frontend-phase-2-b3.md)): the nurse profile bootstrap
|
||||
(`CreateNurseProfileCommand` → an unverified `nurse_profiles` row, `is_verified=false`) and the nurse
|
||||
**bank-account settings** screen (IBAN entry → ownership inquiry). The verification pipeline's
|
||||
`bank_account_verification` step couples to that bank account — **link to the existing bank-account
|
||||
screen for that step; do not rebuild the IBAN form here.**
|
||||
- **f3-b4 addresses/geo** ([`frontend-phase-3-b4.md`](./frontend-phase-3-b4.md)): the nurse coverage-area
|
||||
editor and the cascading geo dropdowns (not used here, but the nurse shell nav points to them).
|
||||
- **f4-b5 catalog** ([`frontend-phase-4-b5.md`](./frontend-phase-4-b5.md)): the nurse "add a service"
|
||||
builder (B7) and `services/catalog`. **The "انتشار پروفایل / go live" action that f4 stubs must be
|
||||
gated on verification by this phase** — wire the blocked-until-verified state into the publish CTA.
|
||||
|
||||
> **Honesty constraint (load-bearing, from the product doc and GTM notes):** vetting is platform-owned and
|
||||
> performed at the authoritative source. **Never word the UI to advertise a check that isn't performed.**
|
||||
> The MoH/INO license and criminal-record steps are *manual admin review of an uploaded document* at
|
||||
> launch — copy must say "در حال بررسی" (under review), not "تاییدشده توسط نظام پرستاری" until an admin
|
||||
> actually passes it. The civil-registry/Shahkar/liveness checks are real (vendor-mocked) — those may say
|
||||
> "استعلام خودکار".
|
||||
|
||||
## 2. Required reading (do this first)
|
||||
|
||||
- [`../_shared/agent-operating-rules.md`](../_shared/agent-operating-rules.md) and
|
||||
[`../_shared/frontend-conventions-checklist.md`](../_shared/frontend-conventions-checklist.md) — how you
|
||||
work, the gate, the contract/handoff lanes, the mock-then-swap rule (§6).
|
||||
- [`../../../client/CLAUDE.md`](../../../client/CLAUDE.md) — the engineering contract (RSC/client boundary,
|
||||
layouts, the `services/{domain}` shape, i18n, theme, cookies, the fetch services). Non-negotiable.
|
||||
- **Invoke the `frontend-designer` skill** before any visual work — it is the design/brand contract
|
||||
(palette, tokens, typography, the `App*` library, layout shells, the hard UI rules). Every screen,
|
||||
chip, uploader, and badge in this phase goes through it. The wireframe's status legend is **green =
|
||||
automatic/verified, amber = pending, grey = manual/next, terracotta = financial** — encode those as
|
||||
token-driven chip variants.
|
||||
- **Product — the source of truth for the rules:**
|
||||
- [`../../../product/business/02-nurse-verification.md`](../../../product/business/02-nurse-verification.md) —
|
||||
the six steps, what each verifies, why it's manual vs automated, the structured-credential-registry
|
||||
rationale, continuous re-verification, and **the "never advertise a check you don't perform" rule**.
|
||||
- [`../../../product/wireframes/index.html`](../../../product/wireframes/index.html) — **Section B,
|
||||
screens B3–B6** are the visual baseline you implement: B3 status meter "۲ از ۵" + stepped checklist
|
||||
with status badges; B4 identity (کد ملی field, upload national-ID card, liveness selfie, "استعلام
|
||||
خودکار از ثبت احوال" note); B5 professional credentials (شماره نظام پرستاری, license upload, education
|
||||
cert shown uploaded ✓, specialty chips سالمندان/ICU/+افزودن); B6 "در حال بررسی" (24–48h, mini-checklist).
|
||||
Also note B7's "انتشار پروفایل" — the publish gate this phase enforces, and C2/C3's "✓ تاییدشده" badge
|
||||
this phase's trust-badge component feeds.
|
||||
- **The contract you consume (the authoritative server shapes):**
|
||||
- [`../../contracts/domains/verification.md`](../../contracts/domains/verification.md) — written by
|
||||
**backend-phase-6**. The exact request/response shapes, routes, status enums, and the per-step status
|
||||
codes. **Do not guess shapes** — derive `types.ts` from this doc + the published `swagger.json`. If a
|
||||
shape you need is missing, append a request to
|
||||
[`../../shared-working-context/frontend/requests/for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md)
|
||||
and mock behind the `services/verification` seam meanwhile (operating-rules §6).
|
||||
- [`../../contracts/conventions/api-conventions.md`](../../contracts/conventions/api-conventions.md) and
|
||||
[`money-and-types.md`](../../contracts/conventions/money-and-types.md) — the envelope (`OperationResult`
|
||||
→ `ApiResult`, already unwrapped by `clientFetch`), `snake_case` routes/properties, pagination, **enums
|
||||
as stable string codes** (mirror them as string-literal unions; labels are i18n keys, never derived
|
||||
from the code), UTC timestamps with **Shamsi display client-side** (credential issue/expiry dates).
|
||||
- **Code to mirror:**
|
||||
- The `services/catalog` and `services/onboarding` domains from f4/f2 — the exact `types.ts`/`keys.ts`/
|
||||
`apis/clientApi.ts`/`hooks/use*.ts`/`index.ts` layout your `services/verification` copies.
|
||||
- The shared **stepper/progress header** and **status chip** from f0 (`src/components/…`) — extend, don't
|
||||
fork. The nurse-profile bank-account screen from f2 — you deep-link into it for the bank step.
|
||||
- The existing document/image handling, if any, in `App*` (`AppImage`); the `clientFetch` multipart path.
|
||||
|
||||
## 3. Scope — build this
|
||||
|
||||
A new **`services/verification`** domain, the **nurse verification route subtree** under the nurse shell,
|
||||
a reusable **document-upload** component, a **trust-badge** component, and the publish-gate wiring. Build
|
||||
RTL-first, both locales, query-cached, minimal re-renders.
|
||||
|
||||
### 3.1 `services/verification` domain (the data layer)
|
||||
Copy the f0/f4 service shape exactly. Types come from
|
||||
[`../../contracts/domains/verification.md`](../../contracts/domains/verification.md) — do not invent.
|
||||
- **`types.ts`** — string-literal unions mirroring the contract enums: the **aggregate status**
|
||||
(`not_started` | `pending` | `in_review` | `approved` | `rejected` | `suspended`), the **per-step
|
||||
status** (`not_started` | `pending` | `in_review` | `passed` | `rejected`), the **step `code`s**
|
||||
(`identity_kyc` · `shahkar_match` · `moh_competency_license` · `ino_membership` · `criminal_record` ·
|
||||
`bank_account_verification`), `verification_method` (`manual` | `portal` | `api`), and the
|
||||
badge state (`verified` | `unverified` | `expired`). Plus the DTOs the contract returns:
|
||||
`VerificationStatus` (aggregate + ordered `steps[]` each with `code`, `status`, `is_automated`,
|
||||
`rejection_reason?`, `expires_at?`), `VerificationStep`, `VerificationDocument` (storage key, file name,
|
||||
uploaded-at — **metadata only, never bytes**), `NurseCredential` (type, masked number, holder name,
|
||||
issuing authority, `issued_at`/`expires_at`).
|
||||
- **`keys.ts`** — a query-key factory: `verificationKeys.status()`, `.documents(stepCode)`,
|
||||
`.badge(nurseId)`. Deliberate `staleTime` (status is moderately fresh — e.g. 30s — because submitting a
|
||||
step changes it; the badge is longer-lived).
|
||||
- **`apis/clientApi.ts`** wrapping `clientFetch` — one function per contract endpoint (see §3.2). The
|
||||
document upload uses the multipart path against the `IObjectStorage`-backed endpoint.
|
||||
- **`hooks/` — one hook per file:**
|
||||
`useVerificationStatus` (query), `useStartVerification`, `useSubmitIdentity`, `useSubmitCredentials`
|
||||
(or per-credential submit if the contract splits MoH/INO/criminal), `useUploadVerificationDocument`
|
||||
(mutation with progress), `useNurseTrustBadge` (query). **Every mutation invalidates
|
||||
`verificationKeys.status()`** (and the badge where relevant) so the checklist re-renders from cache
|
||||
without a manual refetch. Don't toast 401/403/5xx (the fetch layer does) — only domain 4xx (e.g.
|
||||
"ownership mismatch", "shared-SIM", "national-ID format").
|
||||
|
||||
### 3.2 Endpoints consumed (per the b6 contract — confirm exact routes/shapes there)
|
||||
Wire each via `clientApi`; the names below are the expected commands/queries from the digest — bind to
|
||||
whatever the contract publishes:
|
||||
- `GET .../nurse/verification` → `GetVerificationStatusQuery` — the aggregate + per-step list driving B3/B6.
|
||||
- `POST .../nurse/verification/start` → `StartNurseVerificationCommand` — seeds the steps (call from the
|
||||
B3 "start / continue" CTA when status is `not_started`).
|
||||
- `POST .../nurse/verification/identity` → `RunIdentityKycCommand` — national-ID + card image + liveness
|
||||
selfie; drives B4. (Server also runs `shahkar_match` off the bound national-ID — surface both steps.)
|
||||
- `POST .../nurse/verification/moh-license` (+ `.../ino`, `.../criminal-record` if split) →
|
||||
the credential-submit commands behind B5.
|
||||
- `POST .../nurse/verification/document` (or a presigned-URL flow) → the `IObjectStorage`-backed upload
|
||||
used by every document step.
|
||||
- The **bank step** (`bank_account_verification`) is submitted on the **existing f2 bank-account screen** —
|
||||
this phase only renders its status in the checklist and **deep-links** to that screen.
|
||||
- `GET .../nurse/{id}/badge` (public) → `GetVerifiedBadgeQuery` — feeds the trust badge.
|
||||
|
||||
### 3.3 Screens (under the nurse shell `(private-routes)` nurse subtree)
|
||||
Invoke `frontend-designer` for each. RTL-first; the screens live under the nurse route group from f0.
|
||||
|
||||
- **B3 · وضعیت احراز هویت — status checklist** (the hub).
|
||||
- Overall progress meter **"X از Y"** (X = passed required steps, Y = total required) — reuse the f0
|
||||
stepper/progress header.
|
||||
- An **ordered, stepped checklist**, one row per step from `steps[]`, each with a **status chip** (reuse
|
||||
the f0 status chip) in the five per-step states: `not_started`/locked-next (grey "بعدی"), `pending`
|
||||
(amber "در انتظار"), `in_review` (amber "در حال بررسی"), `passed` (green "تاییدشده"), `rejected`
|
||||
(red "رد شد" + the reason). Render **step 1 (mobile) as `passed`** from auth state.
|
||||
- A **"what's blocking go-live" summary** + a single **continue CTA** ("ادامه مرحله N") that routes to
|
||||
the next actionable step. When `not_started`, the CTA calls `useStartVerification` first.
|
||||
- States: loading skeleton, error, and the terminal **`approved` state** (all passed → "احراز هویت
|
||||
تکمیل شد، میتوانید پروفایل را منتشر کنید" with a link to publish).
|
||||
|
||||
- **B4 · تایید هویت — identity submit.**
|
||||
- **کد ملی (national-ID)** field with format validation (10-digit, checksum); **upload national-ID card
|
||||
image** (camera/gallery via the document uploader §3.4); **liveness selfie** capture (camera; handle
|
||||
permission-denied / retry / vendor-timeout states honestly).
|
||||
- The honest auto note "استعلام خودکار از ثبت احوال" (auto civil-registry query) — this check *is*
|
||||
performed (vendor-mocked), so the copy is allowed.
|
||||
- Submit → `useSubmitIdentity`; on success the `identity_kyc` (and server-run `shahkar_match`) steps move
|
||||
to `pending`/`in_review`, the cache invalidates, and the user returns to B3. Surface the **shared-SIM**
|
||||
Shahkar failure as a clear, **non-accusatory** message, and the national-ID-mismatch failure on its step.
|
||||
|
||||
- **B5 · مدارک حرفهای — professional credentials.**
|
||||
- **شماره نظام پرستاری (INO number)** field; **upload پروانه/کارت نظام پرستاری** (the MoH competency
|
||||
license — the single most important credential) via the uploader; **education certificate** upload
|
||||
(shown with the uploaded-✓ state when present); **specialty chips** (multi-select: سالمندان, ICU, +
|
||||
افزودن — an add-your-own chip input).
|
||||
- Structured fields the registry needs where the contract asks for them (license number, issuing
|
||||
authority, holder name as printed, issue/expiry date — **Shamsi date picker, stored UTC**).
|
||||
- Submit → `useSubmitCredentials`; the credential steps move to `in_review` (manual admin review). Copy
|
||||
must reflect manual review, not an automated authority confirmation.
|
||||
|
||||
- **B6 · در حال بررسی — under review.**
|
||||
- The waiting state: "مدارک شما در حال بررسی است" + the **24–48h** expectation + a **mini-checklist**
|
||||
summarizing which steps are passed vs in-review (identity verified / professional docs in review /
|
||||
bank account pending). Reuses the same per-step chips as B3, condensed. CTA "مشاهده وضعیت" → B3.
|
||||
- This is the post-submission resting screen; B3 is the canonical source — B6 is a focused view of the
|
||||
same `VerificationStatus`, not a second fetch with different state.
|
||||
|
||||
- **Trust badge on the nurse profile.** Render the **verified / unverified / expired** badge (the
|
||||
"✓ تاییدشده" mark) on the **nurse's own profile** (f2) and export a small `<TrustBadge status=…/>`
|
||||
shared component so **search results (C2) and the public nurse profile (C3) in f6 reuse it**. Source it
|
||||
from `GetVerifiedBadgeQuery`. `expired` (a required credential lapsed) shows distinctly from `unverified`.
|
||||
|
||||
- **Publish gate.** Wire the f4 "انتشار پروفایل / go-live" action: when the aggregate status is not
|
||||
`approved`, the publish CTA is **disabled with a blocked-until-verified explanation** ("برای انتشار،
|
||||
احراز هویت را کامل کنید") that links to B3. This is the front-end enforcement of "not bookable until
|
||||
verified" — the server enforces it too; the UI must not let a nurse *believe* they're live when they're not.
|
||||
|
||||
### 3.4 Document uploader (shared composite component)
|
||||
Build a reusable **`<DocumentUpload>`** at the shared level (`src/components/…`, co-located `*.test.tsx`)
|
||||
composed from MUI/`App*` primitives — used by every document step (national-ID card, license, education,
|
||||
criminal record):
|
||||
- **Client-side validation** before upload: file **type** (jpg/png/pdf per the contract) and **size cap**;
|
||||
reject with a clear field error.
|
||||
- **Upload states:** idle → selecting → **uploading (progress %)** → processing/hashing → success
|
||||
(thumbnail/✓ + file name) → **error (retry)**. Wire progress from the upload mutation.
|
||||
- **Re-upload on reject:** when a step is `rejected`, the uploader shows the prior file's status and a
|
||||
re-upload affordance.
|
||||
- Returns the server's stored **document metadata** (storage key, name) — never holds or displays raw
|
||||
bytes beyond a local preview.
|
||||
|
||||
### 3.5 i18n namespace `verification` (both locales)
|
||||
Fill the f0-reserved `verification` namespace in **both** `messages/en.json` and `messages/fa.json`, in
|
||||
sync: step labels and per-step status labels (one key per `code` and per status — **never** derive a label
|
||||
from the enum string), the B3/B4/B5/B6 screen copy, the uploader states, the honesty-sensitive copy
|
||||
(manual-review vs auto-query), the blocked-until-verified message, the trust-badge labels, and the
|
||||
shared-SIM / mismatch / format error messages. `fa` is default and RTL.
|
||||
|
||||
### Deferred (do not build here)
|
||||
- The **admin verification review queue** (pass/reject a manual step, the doc viewer, credential-entry
|
||||
form) → **(DEFERRED to [`frontend-phase-15-b15.md`](./frontend-phase-15-b15.md))**, the admin backoffice.
|
||||
This phase only triggers the mock approval to *observe* the state change (see §7); it does not build the
|
||||
admin UI.
|
||||
- **Credential renewal/expiry prompts** beyond rendering the `expired` badge state → the nurse renewal
|
||||
prompt UI is **(DEFERRED)**; the server's `CredentialExpiryScannerJob` (b6) raises the alert.
|
||||
- **Video interview** (B6 mentions it) — not a built step at MVP; reflect it only as a grey "next" row if
|
||||
the contract returns it; otherwise omit. Do not invent an interview-scheduling flow **(DEFERRED)**.
|
||||
- Customer national-ID KYC — out of scope (the product gates only nurses) **(DEFERRED)**.
|
||||
|
||||
## 4. Mocks & seams in this phase
|
||||
|
||||
This phase **introduces no new front-end seam of its own** beyond the standard `services/{domain}` data
|
||||
seam — the verification *vendors* (identity KYC, Shahkar, MoH/INO license, criminal record, IBAN ownership,
|
||||
object storage) are **mocked server-side** behind DI seams owned by **backend-phase-6** (`IIdentityKycProvider`,
|
||||
`IShahkarVerifier`, `ICredentialVerifier`, `IBankAccountOwnershipVerifier`, `IObjectStorage`) — the front
|
||||
end consumes them only through the b6 contract, exactly as if they were real. **Reuse the `services/{domain}`
|
||||
mock-`clientApi` pattern from f0:** if the b6 contract or a specific shape isn't published when you start,
|
||||
build a **mock `clientApi`** behind the `services/verification` seam that returns realistic, contract-shaped
|
||||
`VerificationStatus` (e.g. identity → `in_review`, then flippable to `passed`), record it in your phase
|
||||
report + the [mock registry](../../shared-working-context/reports/mocks-registry.md), and **append the gap
|
||||
to [`for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md)**. The swap to the real
|
||||
endpoint must be implementation-only (same hook signatures, same `queryKey`s) — no call-site changes.
|
||||
|
||||
## 5. Critical rules you must not get wrong
|
||||
|
||||
- **A nurse is NOT bookable and cannot publish until verified.** When the aggregate status is not
|
||||
`approved`, the publish/go-live CTA is disabled with the blocked-until-complete explanation, and every
|
||||
service variant stays inert. This front-end gate mirrors the server's guarded `is_verified` flip — never
|
||||
let the UI imply a nurse is live before verification completes.
|
||||
- **Honest copy — never advertise a check that isn't performed.** Manual steps (MoH/INO license, criminal
|
||||
record) say "در حال بررسی / آپلود شد"; only the genuinely-performed automated checks (identity liveness,
|
||||
civil-registry, Shahkar) may say "استعلام خودکار". A step is "تاییدشده" only when its status is `passed`.
|
||||
This is a product constraint, not a style preference.
|
||||
- **Per-step rejected-with-reason.** A `rejected` step renders its `rejection_reason` and a clear
|
||||
re-submit/re-upload path — never a dead end. The shared-SIM Shahkar failure is an explicit, handled,
|
||||
**non-accusatory** state, not a generic error.
|
||||
- **The data is data-driven — render `steps[]` from the contract, don't hardcode the six steps.** The
|
||||
pipeline is rows server-side; the UI iterates the returned ordered list and maps each `code`/`status` to
|
||||
a label + chip. A new step type appearing in the response must render without a code change.
|
||||
- **Reuse the shared stepper and status chip from f0** — do not re-implement them. Concrete MUI primitives
|
||||
stay MUI; the new shared pieces (`<DocumentUpload>`, `<TrustBadge>`) live at the shared level with tests.
|
||||
- **Caching is a feature.** B3 and B6 read the *same* `VerificationStatus` query — one cached source, two
|
||||
views; every submit/upload mutation **invalidates** the status (and badge) so the checklist updates from
|
||||
cache, never an extra manual refetch. Minimise re-renders (stable refs, `select` for slices).
|
||||
- **RSC/client boundary + RTL + both locales + tokens.** No `next/headers`/`next-intl/server` in client
|
||||
components; design RTL-first (`fa` default); every string a key in both locale files; colours from
|
||||
`tokens.css` (the chip variants map to the wireframe's green/amber/grey/red legend); MUI v9 API only.
|
||||
- **Document bytes are never shown from the API** — uploads return metadata only; a local preview before
|
||||
upload is fine, but the rendered "uploaded" state is driven by server metadata, not retained bytes. The
|
||||
national-ID and credential numbers are sensitive — show **masked** values where the contract masks them.
|
||||
- **Dates:** credential issue/expiry are UTC on the wire, **Shamsi for display** (use the f0 date util).
|
||||
|
||||
## 6. Definition of Done
|
||||
|
||||
The shared [definition-of-done.md](../_shared/definition-of-done.md), plus:
|
||||
- [ ] `services/verification` exists with the f0/f4 shape; types derived from
|
||||
[`verification.md`](../../contracts/domains/verification.md) (not guessed); mutations invalidate the
|
||||
status/badge query; one hook per file; no raw `fetch()`.
|
||||
- [ ] B3 (status checklist), B4 (identity), B5 (credentials), B6 (under review) render under the nurse
|
||||
shell, RTL, both locales in sync, reusing the f0 stepper + status chip.
|
||||
- [ ] `<DocumentUpload>` and `<TrustBadge>` are shared components with co-located `*.test.tsx`; uploader
|
||||
enforces type/size, shows progress, and supports re-upload on reject.
|
||||
- [ ] The publish/go-live CTA from f4 is gated: disabled + blocked-until-verified message until `approved`.
|
||||
- [ ] Honesty copy verified: manual steps never claim an automated authority check; a step shows
|
||||
"تاییدشده" only when `passed`.
|
||||
- [ ] Rejected steps show their reason and a re-submit path; shared-SIM is a clear non-accusatory state.
|
||||
- [ ] `npm run check` green; `npm run test:ci` green (shared components added/touched); `en.json`/`fa.json`
|
||||
in sync.
|
||||
- [ ] `client/CLAUDE.md` *Project Structure* updated for the new route subtree + `services/verification`
|
||||
+ the new shared components.
|
||||
|
||||
## 7. How to test (what a human can verify after this phase)
|
||||
|
||||
Run `npm run dev` (and the b6 server, or the mock `clientApi` if b6 isn't merged). Sign in as a `nurse`.
|
||||
- **Checklist hub:** open the nurse verification screen → **B3** shows the "X از Y" meter, step 1 (mobile)
|
||||
already `passed`/green, the rest `not_started`. The continue CTA routes to the next step (calling
|
||||
`start` first when `not_started`).
|
||||
- **Submit identity:** **B4** → enter a valid کد ملی, upload a national-ID card image (watch the
|
||||
uploader's progress → success), capture a liveness selfie, submit → the `identity_kyc` and
|
||||
`shahkar_match` steps move to **`pending`/`in_review`** on B3 **without a manual refresh** (cache
|
||||
invalidation). Try an invalid national-ID → field error; trigger the mock shared-SIM number → a clear
|
||||
non-accusatory Shahkar message.
|
||||
- **Submit credentials:** **B5** → enter the نظام پرستاری number, upload the license + education cert, add
|
||||
specialty chips, submit → the credential steps move to **`in_review`**; the UI lands on **B6** showing
|
||||
"در حال بررسی", the 24–48h note, and the mini-checklist.
|
||||
- **Approval flips verified:** trigger the b6 mock admin approval (the mock provider/test endpoint, or set
|
||||
the mock `clientApi` to return `approved`) → re-open B3: aggregate is **`approved`**, all required steps
|
||||
`passed`, the **trust badge** shows **verified** on the nurse profile, and the **publish CTA is now
|
||||
enabled** (was blocked-until-verified before).
|
||||
- **Rejected step:** make a step return `rejected` (mock) → its row shows **the rejection reason** and a
|
||||
working re-upload/re-submit path; the publish CTA stays blocked.
|
||||
- **Quality:** `npm run check` and `npm run test:ci` pass; toggle locale → RTL/strings flip correctly;
|
||||
dark mode renders; React Query Devtools shows one `verification.status` query feeding both B3 and B6 and
|
||||
invalidating on each mutation.
|
||||
|
||||
## 8. Hand off & document (close the phase)
|
||||
|
||||
- **Docs:** update the *Project Structure* tree in [`../../../client/CLAUDE.md`](../../../client/CLAUDE.md)
|
||||
for the nurse verification route subtree, `services/verification`, and the new shared components
|
||||
(`<DocumentUpload>`, `<TrustBadge>`); add a one-line note that the trust badge is the reusable component
|
||||
f6 consumes. If you discover a verification rule the product docs don't capture, record it in
|
||||
[`../../../product/business/02-nurse-verification.md`](../../../product/business/02-nurse-verification.md)
|
||||
(don't invent — record decisions).
|
||||
- **Contracts:** **consume** [`../../contracts/domains/verification.md`](../../contracts/domains/verification.md)
|
||||
(frontend produces none). Any missing/ambiguous shape (e.g. whether credential submit is one endpoint or
|
||||
split, the exact document-upload flow, the badge payload) → append to
|
||||
[`../../shared-working-context/frontend/requests/for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md);
|
||||
do **not** edit backend files.
|
||||
- **Handoff & report:** append your phase summary to
|
||||
[`../../shared-working-context/frontend/STATUS.md`](../../shared-working-context/frontend/STATUS.md);
|
||||
write [`../../shared-working-context/reports/frontend-phase-5-report.md`](../../shared-working-context/reports/frontend-phase-5-report.md)
|
||||
— what was built, **what is now testable and exactly how** (the §7 steps), what is mocked client-side
|
||||
(the `services/verification` mock `clientApi`, if used) and how it swaps to the real b6 endpoint, the
|
||||
contract consumed + gaps filed, and the follow-up that f6 reuses the `<TrustBadge>`. Update the
|
||||
[mock registry](../../shared-working-context/reports/mocks-registry.md) for any client-side mock.
|
||||
- **Memory:** save a `project` memory note for the non-obvious decisions — the data-driven step rendering,
|
||||
the single-status-query-two-views (B3/B6) caching choice, the reusable `<TrustBadge>`/`<DocumentUpload>`
|
||||
seams, and the publish-gate wiring — with a one-line pointer in `MEMORY.md`.
|
||||
Reference in New Issue
Block a user