Files
baya-monorepo/archive/docs/integration/domains/verification.md
T
2026-08-02 20:01:31 +03:30

7.0 KiB

verification — the nurse trust pipeline

Client seam client/src/services/verification/ · USE_VERIFICATION_MOCK = true (mock is primary) · 17 server ops Last verified: 2026-07-30 against commit d3ec723 and swagger.v1.json (2026-07-29).

The largest domain, and the one the whole marketplace's trust claim rests on. A nurse is not bookable until this pipeline says so.

Endpoints

Nurse-facing

Method Path Verdict
GET /api/v1/nurse_verification wired — the one cached status query
POST /api/v1/nurse_verification/submit wired
POST /api/v1/nurse_verification/steps/{stepId}/upload_url wired — presigned PUT
POST /api/v1/nurse_verification/steps/{stepId}/documents wired — confirm the upload
POST /api/v1/nurse_verification/steps/identity_kyc/run wired
POST /api/v1/nurse_verification/steps/shahkar_match/run wired
POST /api/v1/nurse_verification/steps/bank_account_verification/run wired
POST /api/v1/nurse_verification/credential_details unwired — the write half of REQ-011; the client has no read-back (REQ-056)

Public

Method Path Auth Verdict
GET /api/v1/nurses/{nurseId}/trust_badge anonymous wired

Admin — all DynamicPermission + sensitive

Method Path Verdict
GET /api/v1/admin_verifications wired · paginated
GET /api/v1/admin_verifications/{nurseVerificationId} wired
POST /api/v1/admin_verifications/steps/{stepId}/decide wired — per-step decision
POST /api/v1/admin_verifications/{nurseVerificationId}/suspend unwired
POST /api/v1/admin_verifications/scan_expiring unwired — an ops one-shot; the scheduler runs it
GET /api/v1/admin_verification_step_types unwired — the step catalogue is data-driven; no editor
POST /api/v1/admin_verification_step_types unwired
DELETE /api/v1/admin_verification_step_types/{id} unwired

Phantom — 3

Client call REQ Note
GET /api/v1/admin_verifications/documents/{id}/url REQ-034 Deferred. No on-demand signed document URL, so the queue cannot open an uploaded document
POST /api/v1/admin_verifications/{id}/approve REQ-034 Deferred. Today approval is per-step only — the aggregate flips when the last required step passes
POST /api/v1/admin_verifications/{id}/reject REQ-034 Deferred

The two rules that must not be broken

  1. status is the source of truth; nurse_profiles.is_verified is derived. The boolean is written only by the finalize transaction when the aggregate reaches approved, as one guarded cross-aggregate flip: load both tracked, mutate through one pure domain helper, commit once. Never set is_verified from a profile write, a controller, or out of band. See profiles.md.
  2. The step catalogue is data, not code. verification_step_types rows define which steps exist, which are required, and which are automated. Adding a step is a data change. The client must not hardcode the step list — it renders whatever VerificationStatusDto.steps contains.

Shape rules the JSON does not express

  • VerificationStatusDto is { status, isBookable, blockingSteps, steps } — the server computes isBookable and names the blockingSteps. The client does not derive bookability from the step array. This is why the client keeps one cached status query and every screen reads it.
  • expiresAt on a step is real. MoH competency licences and INO membership lapse; scan_expiring reverts a lapsed step to expired, which re-gates bookability. expired is therefore a normal state, not an error.
  • Document upload is a two-step presign flow: upload_url returns a presigned PUT, the client uploads directly to storage, then documents confirms. The document bytes never transit the API. Seams:ObjectStorage:PresignExpirySeconds (900) bounds the window.
  • The three run steps are seams, each independently switchableSeams:IdentityKyc:Provider, Seams:Shahkar:Provider, Seams:BankOwnership:Provider, all mock by default, all finnotech for the real bridge (sharing Seams:Finnotech credentials). Designated test values make each failure path reachable: SharedSimPhone 09120000000, MismatchNationalId 1111111111, FailNationalId 0000000000, MismatchIban IR0000…0000.
  • shahkar_match failing as shared SIM is a distinct outcome from a plain phone↔national-id mismatch, and the UI must say which — a shared family SIM is a common, innocent case.
  • National id and licence numbers are encrypted at rest; the admin queue sees them only where the decision requires it.
  • The nurse's INO membership field is locked once submitted (it feeds the public trust badge).

Two vocabularies for one thing

GET /me reports a nurse verification summary using not_started in_progress pending_review verified rejected. This domain's aggregate uses not_started pending in_review approved rejected suspended. They are two read models over the same source of truth, not a drift — but they are not interchangeable strings. Map deliberately. See auth.md.

Enums

Vocabulary Values
VerificationStatus (aggregate) not_started pending in_review approved rejected suspended
VerificationStepStatus not_started pending in_review passed failed expired
StepTypeCode identity_kyc shahkar_match moh_competency_license ino_membership criminal_record bank_account_verification
CredentialType moh_competency_license ino_membership criminal_record
VerificationMethod manual portal api
BadgeState (client, from TrustBadgeDto) verified unverified expired

The first two are C# enums serialised as snake_case codes (Entities/Verification/VerificationStatus.cs, VerificationStepStatus.cs); the rest are string constants in VerificationStepTypeCodes.cs. All verified identical to the client's unions.

TrustBadgeDto is { nurseId, isVerified, approvedAt, credentialTypes } — a summary, with no per-step detail. That absence is REQ-043.

Open REQs

REQ Status Effect
REQ-034 deferred No nurse-grouped queue, no on-demand document URL, no whole-verification approve/reject → 3 phantom routes. This is the main reason the seam is mocked
REQ-043 open TrustBadgeDto has no per-step detail (step codes + decision dates), so the public verification panel shows a summary only
REQ-055 open No submittedAt on VerificationStatusDto — the real B6 screen omits the timestamp line
REQ-056 open No nurse-facing read-back of submitted credential details. credential_details writes; nothing reads. The real form degrades to blank
REQ-062 open No name/phone search and no per-status counts on the admin queue