Files
baya-monorepo/dev/shared-working-context/reports/mocks-registry.md
T
hamid 39a979b1a7 @
backend phase 3: identity profiles, patients & nurse bank accounts

Add the role-attached identity layer on top of the b2 auth spine: nurse
seller profiles (guarded is_verified, read-only aggregates), thin customer
payer profiles, first-class patients (tenancy-scoped), and nurse payout bank
accounts hardened with an iban_hash uniqueness guard and an automated استعلام
شبا IBAN-ownership inquiry.

- Four usr tables via one migration (1:1 uniques, UNIQUE(iban_hash), filtered
  UNIQUE(nurse_id) WHERE is_primary=1, guarded is_verified, encrypted PII,
  soft-delete on nurse_profiles)
- 15 CQRS slices + 4 role-scoped controllers; reads projected + paginated,
  IBAN masked (last-4); ownership-inquiry endpoints rate-limited
- New IBankAccountOwnershipVerifier seam (mock deterministic شبا match) +
  per-domain repositories on IUnitOfWork + encrypted-PII value converters
- Activate FluentValidation repo-wide (validators were never registered)
- Handler unit tests + WebApplicationFactory integration tests (76 pass);
  contract identity-profiles.md + swagger snapshot; docs, handoff & report

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
2026-07-02 12:03:15 +03:30

8.4 KiB
Raw Blame History

Mock & integration registry

The master list of every external dependency that is mocked behind a DI seam in this build, and the exact steps to make each one real. Backend lane owns this file; every phase that introduces or touches a seam updates its row. This is the checklist the team works through to go from "MVP with mocks" to "production with real providers".

Status legend: 🔴 not built · 🟡 mocked (seam + fake impl in place) · 🟢 real integration live.

Seam (interface) Introduced in What it fakes Config keys Make it real → Status
ISmsSender backend-phase-2 OTP/SMS delivery — LoggingSmsSender (Baya.Infrastructure.CrossCutting/Seams/) logs the OTP code (phone shown as last-4 only) and returns success; registered singleton in AddCrossCuttingSeams none today; real client will need Seams:Sms:ApiKey + Seams:Sms:SenderLine (+ gateway base URL) 1) pick a gateway (Kavenegar/Ghasedak/SMS.ir), add its client package to Directory.Packages.props; 2) implement ISmsSender.SendOtpAsync/SendAsync against it (template/pattern-based OTP send); 3) bind the new Seams:Sms options; 4) swap the registration in AddCrossCuttingSeams (config-selected) — handlers unchanged; 5) keep the per-phone resend window + otp rate-limit policy exactly as-is; test with a real SIM 🟡
IObjectStorage backend-phase-0/6 File storage — local-disk store under a scratch root (LocalDiskObjectStorage, Baya.Infrastructure.CrossCutting/Seams/) Seams:ObjectStorage:RootPath (default: temp dir) Point at MinIO/S3/ArvanCloud; presigned upload/download; bucket + creds 🟡
ICacheService backend-phase-0 Caching — in-memory IMemoryCache (MemoryCacheService, Baya.Infrastructure.CrossCutting/Seams/) none Swap to Redis (StackExchange.Redis); keep key/TTL scheme 🟡
IDistributedLock backend-phase-10 Money-path locks — no-op/in-proc tbd Redis lock (RedLock); DB constraint remains the backstop 🔴
INurseSearch backend-phase-7 Search — SQL over nurse_search_index tbd Elasticsearch index + feeder; reimplement the interface 🔴
IPaymentProvider backend-phase-10 Card PSP/IPG — deterministic success tbd ZarinPal/Sadad/Vandar/Jibit + Shaparak; merchant/terminal/تسهیم 🔴
ISettlementSplitProvider backend-phase-10 تسهیم split — accepts any balanced legs tbd Provider split-by-ratio to registered Shebas 🔴
IWebhookVerifier backend-phase-10 Callback auth — always valid tbd Per-provider HMAC/signature + server-side re-verify 🔴
IBnplProvider backend-phase-12 BNPL — drives state machine, fake settle/revert tbd SnappPay/Digipay OAuth + verb set; encrypted creds in payment_gateways.config_json 🔴
ICurrencyNormalizer backend-phase-12 Toman↔IRR — ×10 tbd Config-driven per provider boundary 🔴
IBankTransferProvider backend-phase-13 PAYA/SATNA payout — fake transfer ref tbd Jibit/Vandar/Sadad payout; source account; PAYA vs SATNA 🔴
IHolidayCalendar backend-phase-1 Bank holidays — reads the seeded ops.IranianHolidays table; lookups cached (HolidayCalendarService, Persistence/Services/Holidays/); Iranian banking weekend = Friday none Add a sync job/feed that maintains the (partly lunar-Hijri) calendar table; the read interface stays 🟡
IAnalyticsSink backend-phase-1 Behavioural events — inserts an ops.SystemEvents row, fire-and-forget (AnalyticsSink, Persistence/Services/Analytics/) none Pipe to a warehouse/stream (e.g. Kafka→ClickHouse); keep fire-and-forget semantics 🟡
IJobScheduler (retention) backend-phase-1 Scheduling — in-process interval BackgroundService running PurgeOldReadNotifications daily (NotificationRetentionHostedService, Persistence/Services/Notifications/) none Swap to Hangfire/Quartz; register the job there; keep the purge predicate (is_read=1 AND age>90d) 🟡
IShahkarVerifier backend-phase-6 Phone↔national-id match — fake pass tbd Real Shahkar/KYC vendor; persist external_response_json 🔴
IIdentityKycProvider backend-phase-6 National-ID + liveness — fake pass tbd Finnotech/U-ID/Jibbit/Verify liveness+OCR 🔴
ICredentialVerifier backend-phase-6 MoH/INO/criminal-record — manual/fake tbd Manual admin today; API when a portal appears (verification_method=api) 🔴
IBankAccountOwnershipVerifier backend-phase-3 استعلام شبا IBAN-owner ↔ national-id inquiry — MockBankAccountOwnershipVerifier (Baya.Infrastructure.CrossCutting/Seams/) returns a deterministic fake: every IBAN matches (matched_national_id=true, echoes a holder name + MOCK-SHEBA-{sha} vendor ref) except the configured mismatch IBAN which returns false; registered singleton in AddCrossCuttingSeams. No real bank/KYC call, no money moves Seams:BankOwnership:MismatchIban (default IR000000000000000000000000), Seams:BankOwnership:MatchedHolderName, Seams:BankOwnership:MismatchHolderName 1) pick a Finnotech / banking-bridge استعلام شبا provider, add its client package to Directory.Packages.props; 2) add Seams:BankOwnership:{ApiKey,BaseUrl} options; 3) implement VerifyOwnershipAsync(iban, nurseNationalId) against the real Sheba-owner inquiry, mapping to OwnershipInquiryResult; 4) persist the real ownership_vendor_ref (+ raw response if a column is added); 5) swap the registration in AddCrossCuttingSeams (config-selected) — handlers unchanged; 6) test match/mismatch + that the b13 first-payout gate honours matched_national_id=true 🟡
IGeocoder backend-phase-4 Address→lat/lng — echo/static tbd Neshan/Google geocoding 🔴
IMoadianClient backend-phase-11 سامانه مودیان e-invoice — leaves ref pending tbd Real مودیان submission → 22-digit ref 🔴
IReviewModerationService backend-phase-14 AI moderation — keyword/pass-through tbd Real classifier/LLM endpoint 🔴
IFieldEncryptor backend-phase-0 PII encryption — AES-256-CBC + HMAC hash from a local symmetric key (SymmetricFieldEncryptor, Baya.Infrastructure.CrossCutting/Seams/) Seams:FieldEncryption:Key, Seams:FieldEncryption:HashKey KMS / column encryption / Key Vault / HSM 🟡
INotificationDispatcher backend-phase-0/1 Notification channels — in-app write is now real (InAppNotificationDispatcher, Persistence/Services/Notifications/, writes an ops.Notifications row); b0 log stub removed. SMS/push channels still deferred (no-op) behind the same seam none Add SMS (ISmsSender) / push (FCM) channels; polling → Redis pub/sub or SignalR later 🟡
ILicenseVerificationService backend-phase-15 eNamad / MoH establishment-permit — manual approve tbd Real registry/API 🔴

Exact config keys and file paths get filled in by the phase that builds each seam. Keep the "Make it real →" column actionable enough that a developer can pick up any single row and ship it.

Frontend client-side mocks (not backend DI seams)

These are in-browser mocks behind a services/{domain} interface, selected by a config flag. They exist so the frontend can build before the backend phase merges, and swap to the real HTTP client in one line.

Seam (interface) File What it fakes Config flag Make it real → Status
PatientsApi client/src/services/patients/apis/mockApi.ts In-memory patient list/create USE_PATIENTS_MOCK (services/patients/constants.ts) Publish /patients endpoints, set flag false 🟡
AuthApi client/src/services/auth/apis/mockApi.ts (authMockApi) Phone-OTP login offline: requestOtp{otpSent,resendAvailableInSeconds:120}; verifyOtp accepts dev code 123456 and locks after 3 wrong tries (otp_locked); getMe/selectRole/refresh from a MOCK_SCENARIO toggle (customer/nurse_unverified/no_role) to exercise all router branches USE_AUTH_MOCK (services/auth/constants.ts, default false — b2 is live) + MOCK_SCENARIO in mockApi.ts The real authClientApi is already wired to the live b2 routes; set USE_AUTH_MOCK = false (already the default) — no hook/screen change 🟢 real by default, 🟡 mock available