--- issue: 099 title: "Backend: on-demand RN reconciliation in getPaymentById can race — double-processing risk" severity: medium domain: Payment labels: [bug, backend, concurrency] status: open created: 2026-05-30 source: Full Codebase Audit 2026-05-30 --- # Backend: on-demand RN reconciliation in getPaymentById can race — double-processing risk **Severity:** medium **Domain:** Payment **Labels:** bug, backend, concurrency ## Description `paymentController.ts:407-466` triggers RN reconciliation on every `GET /payment/:id` call. If two browser tabs or requests call this concurrently on a pending payment, both can read `status:'pending'` and both trigger the completion side-effects before either write commits. ## Options 1. Use an atomic `findOneAndUpdate` guarded on `status:'pending'` so only one writer wins. 2. Add a distributed lock (Redis) around reconciliation per payment. 3. Move reconciliation off the read path into a single-writer background job. ## Recommendation Make the status transition atomic (`findOneAndUpdate` filtering on current status) so only the first concurrent caller advances it; ideally move reconciliation off the GET path. ## Affected Files - `backend/src/services/payment/paymentController.ts:407-466` ## References - [Full Codebase Audit 2026-05-30](../09%20-%20Audits/Full%20Codebase%20Audit%20-%202026-05-30.md) — DEC-37