---
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
