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:
hamid
2026-07-05 14:39:32 +03:30
parent 687fbfc6d9
commit 1c266523bc
105 changed files with 13938 additions and 10 deletions
@@ -0,0 +1,38 @@
using Baya.Domain.Entities.Verification;
namespace Baya.Test.Foundation.Verification;
/// <summary>
/// Helpers for the verification handler/aggregator tests. Entity ids have a protected setter (they are
/// assigned by EF on save); these set them via reflection so a mocked repository can return graphs with
/// stable ids without a real DbContext.
/// </summary>
internal static class VerificationTestSupport
{
public static T WithId<T>(this T entity, long id)
{
var setter = typeof(T).GetProperty("Id")!.GetSetMethod(nonPublic: true)!;
setter.Invoke(entity, [id]);
return entity;
}
public static VerificationStepType StepType(long id, string code, bool automated, bool required = true)
=> new VerificationStepType
{
Code = code,
DisplayName = code,
IsAutomated = automated,
IsRequired = required,
IsActive = true,
SortOrder = (int)id
}.WithId(id);
public static VerificationStep Step(long id, VerificationStepType type, VerificationStepStatus status)
=> new VerificationStep
{
StepTypeId = type.Id,
StepType = type,
Status = status,
IsAutomated = type.IsAutomated
}.WithId(id);
}