Summary
Driver and investor DVA provisioning performs a read, several Paystack mutations, and only then an upsert. Concurrent requests can both create customers or dedicated accounts before MongoDB's uniqueness constraints arbitrate the final local record, leaking provider-side duplicates and ambiguous account routing.
Repository evidence
lib/services/paystack-dva.service.ts:424-494 checks the local account before creating/updating a Paystack customer and dedicated account.
lib/services/paystack-investor-dva.service.ts:333-394 repeats the same check-then-create sequence.
models/DriverVirtualAccount.ts:97-99 and models/InvestorVirtualAccount.ts:90-92 enforce local uniqueness only after external side effects have happened.
Scope
- Add a per-user/provider provisioning claim with lease or fencing semantics before any Paystack mutation.
- Make retries resume or reconcile an in-flight attempt instead of creating another customer/account.
- Persist attempt state and provider identifiers early enough to recover ambiguous timeouts.
Acceptance criteria
Tests
Non-goals
- Changing Paystack providers or redesigning wallet funding.
Summary
Driver and investor DVA provisioning performs a read, several Paystack mutations, and only then an upsert. Concurrent requests can both create customers or dedicated accounts before MongoDB's uniqueness constraints arbitrate the final local record, leaking provider-side duplicates and ambiguous account routing.
Repository evidence
lib/services/paystack-dva.service.ts:424-494checks the local account before creating/updating a Paystack customer and dedicated account.lib/services/paystack-investor-dva.service.ts:333-394repeats the same check-then-create sequence.models/DriverVirtualAccount.ts:97-99andmodels/InvestorVirtualAccount.ts:90-92enforce local uniqueness only after external side effects have happened.Scope
Acceptance criteria
Tests
Non-goals