# Domain 4 — Verification & Credentials [← Database Model](index.md) **Related:** business requirements — [Nurse verification](../business/02-nurse-verification.md). The pipeline stays **data-driven**: step types are rows, so a new regulatory requirement (e.g. professional liability insurance) is one INSERT. This revision adds a **structured credential registry** because the brand *is* "verified trust" and renewal tracking needs queryable license numbers, not opaque PDFs. ### `nurse_verifications` [CORE] **Role:** The master per-nurse verification record; aggregates step outcomes into one status (the single source of truth for verification state). **Why a header table:** one place to drive the overall lifecycle and the `is_verified` flip. Fields unchanged: `id`, `nurse_id` (unique), `status` (`not_started`/`pending`/`in_review`/`approved`/`rejected`/`suspended`), `submitted_at`, `approved_at`, `rejected_at`, `suspended_at`, `rejection_reason`, `reviewed_by_admin_id`, `internal_notes`, timestamps. **Relations:** 1:1 → `nurse_profiles`; 1:N → `verification_steps`. ### `verification_step_types` [CORE] **Role:** Admin catalog of pipeline steps with stable machine `code`s (`identity_kyc`, `shahkar_match`, `moh_competency_license`, `ino_membership`, `criminal_record`, `bank_account_verification`). **Why rows + `is_automated`/`automation_provider`:** the Iranian credential reality is fragmented across regulators and partly automatable (Shahkar, liveness) and partly manual (license PDF) — data-driving it absorbs that without code changes. Fields unchanged. **Relations:** 1:N → `verification_steps`. ### `verification_steps` [CORE] **Role:** One row per step per nurse; tracks status, the raw `external_response_json` (KYC vendor audit), and `expires_at` for time-limited steps (the عدم سوء پیشینه certificate expires → step reverts to `pending` + raises a `support_alert`). **Why snapshot `is_automated`:** historical records survive later step-type edits. Fields unchanged, with `UNIQUE(nurse_verification_id, step_type_id)`. **Relations:** N:1 → `nurse_verifications`, `verification_step_types`; 1:N → `verification_documents`. ### `verification_documents` [CORE] **Role:** Uploaded evidence metadata (object-storage key + integrity hash); files live in S3-compatible storage behind signed URLs, never public. **Why metadata-only:** keeps PII bytes out of the DB and access controlled. Fields unchanged. **Relations:** N:1 → `verification_steps`. ### `nurse_credentials` [MVP] — **NEW** **Role:** Structured, queryable registry of the actual Iranian credentials — beyond the opaque document uploads. **Why:** no public B2B API exists for MoH/INO, so an admin manually verifies an uploaded credential against the official portal — but the old model gave them **nowhere to record the verified license number** for renewal alerts, the public trust badge, or cross-check. This makes the badge and expiry monitoring real and survives a future INO/MoH API. | Field | Type | Notes | |---|---|---| | `id` | BIGINT PK | | | `nurse_id` | BIGINT FK → nurse_profiles | | | `credential_type` | NVARCHAR(50) | `moh_competency_license` (پروانه صلاحیت حرفه‌ای) / `ino_membership` (نظام پرستاری) / `criminal_record` (عدم سوء پیشینه) | | `credential_number` | NVARCHAR(100) (enc) | License/membership number | | `holder_name_snapshot` | NVARCHAR(200) | Name as printed, for ID cross-check | | `issuing_authority` | NVARCHAR(200) | | | `issued_at`, `expires_at` | DATE NULL | Drives renewal alerts | | `verification_source` | NVARCHAR(300) NULL | Portal URL / method | | `verification_method` | NVARCHAR(20) | `manual` / `portal` / `api` | | `verified_by_admin_id` | BIGINT FK → users NULL | | | `created_at`, `updated_at` | … | | **Relations:** N:1 → `nurse_profiles`. Cross-referenced by the relevant `verification_steps`.