backend phase 6: nurse verification & credentials (mocked vendors)
The trust engine. New `verif` schema (5 tables) + a data-driven verification pipeline: steps are rows (6 seeded step-types), not a code enum. - nurse_verifications.status is the single source of verification truth; nurse_profiles.is_verified is flipped ONLY inside the finalize transaction (VerificationAggregator: tracked verification + tracked profile -> one commit) and reversed on suspension/expiry — no in-between state. - is_automated snapshotted onto each step at submit; steps seeded from active required step-types; automated runs (identity-KYC, Shahkar, IBAN ownership) find their step by code. - users.national_id populated only on identity-KYC pass; Shahkar + IBAN owner compare against it (money-mule guard); shared-SIM -> shared_sim support alert. - Documents are metadata-only behind signed URLs; credential_number encrypted and never serialized; public trust badge exposes credential TYPES, not numbers; holder-name cross-checked against the verified identity before recording. - Admin-triggered credential-expiry scan reverts lapsed steps, re-gates bookability, raises a verification_expired alert + verification_expiry_prompt notification (scheduled cron deferred; config key verification_expiry_scan_cadence_hours). Three new mock vendor seams (IShahkarVerifier / IIdentityKycProvider / ICredentialVerifier) behind DI; reuses b3 IBankAccountOwnershipVerifier and b0 IObjectStorage/IFieldEncryptor. 15 endpoints across 4 controllers. Two migrations (tables + step-type seed). 154 tests pass, zero new warnings. Contract dev/contracts/domains/verification.md + swagger snapshot refreshed; handoff/report/mocks-registry updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,34 @@ One block per completed backend phase. Newest at the top. Backend lane writes he
|
||||
- **Notes for frontend:** <anything load-bearing>
|
||||
-->
|
||||
|
||||
## backend-phase-6 — Nurse verification & credentials (mocked vendors) — 2026-07-02
|
||||
- **Shipped:** the trust engine via one additive migration — new **`verif`** schema, **5 tables**:
|
||||
`NurseVerifications` (`status` = the **single source of verification truth**), `VerificationStepTypes`
|
||||
(seeded catalog — six stable codes `identity_kyc`/`shahkar_match`/`moh_competency_license`/`ino_membership`/
|
||||
`criminal_record`/`bank_account_verification`), `VerificationSteps` (one per required step-type; snapshots
|
||||
`is_automated`), `VerificationDocuments` (**metadata only** — bytes never in the DB), `NurseCredentials`
|
||||
(`credential_number` **encrypted, never serialized**). **15 endpoints across 4 controllers** —
|
||||
`nurse_verification` (submit/get/upload_url/documents + automated `identity_kyc`/`shahkar_match`/
|
||||
`bank_account_verification` `/run`), `admin_verification_step_types` (list/upsert/deactivate, dup code →
|
||||
409), `admin_verifications` (queue/detail/decide/suspend/scan_expiring), public `nurses/{id}/trust_badge`.
|
||||
`nurse_profiles.is_verified` is the **only derived boolean**, flipped **only inside the finalize
|
||||
transaction** (reversed transactionally on suspend/expiry). Three **new mock vendor seams**
|
||||
(`IShahkarVerifier`, `IIdentityKycProvider`, `ICredentialVerifier`); reuses b3
|
||||
`IBankAccountOwnershipVerifier` + b0 `IObjectStorage`/`IFieldEncryptor`. The expiry-scan logic ships as
|
||||
`ScanExpiringCredentialsCommand`; the **scheduled cron is deferred** (admin `scan_expiring` is the entry
|
||||
point; config `verification_expiry_scan_cadence_hours`, default 24).
|
||||
- **Contracts:** dev/contracts/domains/verification.md + openapi snapshot refreshed (yes — all 15 b6 paths).
|
||||
- **Mocked:** `IShahkarVerifier`, `IIdentityKycProvider`, `ICredentialVerifier` → 🟡 (deterministic mocks;
|
||||
see reports/mocks-registry.md). All vendor/money calls are mocked.
|
||||
- **Gate:** build clean (0 new code warnings) / tests green (**153 pass**). Swagger exposes all 15 b6 paths.
|
||||
- **Handoff:** backend/handoff/after-backend-phase-6.md
|
||||
- **Notes for frontend:** **`isBookable`/`isVerified` are read-only, server-derived** — never infer
|
||||
verification client-side. **Credential numbers never cross the wire** (trust badge = types only).
|
||||
`step.isAutomated` drives the UI (`/run` button vs upload flow). Prereqs enforced with **400** (Shahkar
|
||||
needs KYC; bank needs KYC + a primary b3 account). Shared-SIM / vendor fails are **200 with
|
||||
`stepStatus:"failed"` + `failureReason`**, not HTTP errors. Documents are short-lived signed URLs. Routes
|
||||
are action-style POST; refresh after `select_role`. Public trust badge (f6) is `[AllowAnonymous]`.
|
||||
|
||||
## backend-phase-5 — Service catalog & nurse pricing variants — 2026-07-02
|
||||
- **Shipped:** five tables via one additive migration (`ServiceCatalogAndNurseVariants`) — new **`catalog`**
|
||||
schema `ServiceCategories` / `ServiceOptionGroups` (nullable `service_category_id` = cross-category) /
|
||||
|
||||
Reference in New Issue
Block a user