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,38 @@ public sealed class SeamOptions
|
||||
public ObjectStorageOptions ObjectStorage { get; set; } = new();
|
||||
public BankOwnershipOptions BankOwnership { get; set; } = new();
|
||||
public GeocodingOptions Geocoding { get; set; } = new();
|
||||
public ShahkarOptions Shahkar { get; set; } = new();
|
||||
public IdentityKycOptions IdentityKyc { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tunes the mock <c>IShahkarVerifier</c> (phone↔national-id binding). A submitted phone equal to
|
||||
/// <see cref="SharedSimPhone"/> returns the explicit shared-SIM failure; a national id equal to
|
||||
/// <see cref="MismatchNationalId"/> returns a plain mismatch; every other pair matches. The real vendor
|
||||
/// implementation ignores these.
|
||||
/// </summary>
|
||||
public sealed class ShahkarOptions
|
||||
{
|
||||
/// <summary>The designated test phone that returns the shared-SIM failure state.</summary>
|
||||
public string SharedSimPhone { get; set; } = "09120000000";
|
||||
|
||||
/// <summary>The designated test national id that returns a plain phone↔national-id mismatch.</summary>
|
||||
public string MismatchNationalId { get; set; } = "1111111111";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tunes the mock <c>IIdentityKycProvider</c>. A national id equal to <see cref="FailNationalId"/> fails
|
||||
/// KYC; every other (well-formed) national id passes with <see cref="MatchedName"/>. The real e-KYC vendor
|
||||
/// implementation ignores these.
|
||||
/// </summary>
|
||||
public sealed class IdentityKycOptions
|
||||
{
|
||||
/// <summary>The designated test national id that fails identity KYC.</summary>
|
||||
public string FailNationalId { get; set; } = "0000000000";
|
||||
|
||||
/// <summary>The name the mock reports as matched on a passing KYC (informational; the authoritative
|
||||
/// identity name for credential cross-check comes from the users row).</summary>
|
||||
public string MatchedName { get; set; } = "Verified Nurse";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user