Files
nick-doc/Issues/ISSUE-018-select-offer-updatemany-has-no-status-filter-overwrites-with.md
Siavash Sameni dceaf82934 audit: 2026-05-30 full-codebase audit — report, issues, docs, runbooks
Full-codebase-audit 2026-05-30 outputs:
- Audit report: 09 - Audits/Full Codebase Audit - 2026-05-30.md
- 81 issue files ISSUE-055..135 (decisions + 1 skipped no-brainer).
- Scanner docs from scratch (was zero): architecture, data model, API ref, payment
  flow, operations runbook + repo README.
- Doc-sync updates across API reference, data models, flows, design system.
- Secret Rotation Runbook (08 - Operations) for the exposed credentials.
- Reusable workflow guide (07 - Development) + .claude/workflows/full-codebase-audit.js.

Issues remain status:open intentionally — the code fixes are uncommitted-then-committed
working-tree changes per repo and aren't "resolved" until merged/deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:48:04 +04:00

1.8 KiB

issue, title, severity, domain, labels, status, resolved, fix, status, created, source
issue title severity domain labels status resolved fix status created source
018 select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history major Seller Offer
bug
backend
major
data-integrity
resolved 2026-05-29 Added status: { $nin: ['withdrawn', 'rejected'] } to the updateMany filter in select-offer handler — preserves existing terminal statuses. open 2026-05-29 Doc vs Code Audit 2026-05-29

🟠 select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history

Severity: major Domain: Seller Offer Labels: bug, backend, major, data-integrity

Description

The POST /purchase-requests/:id/select-offer route handler (routes.ts lines 1386-1395) uses updateMany with only {purchaseRequestId, _id: {$ne: offerId}} — no status filter. This can overwrite already-withdrawn or previously-rejected offers' status back to 'rejected', corrupting their status history. SellerOfferService.acceptOffer() correctly filters by status: {$in: ['pending', 'active']}.

Current Behavior

Selecting an offer via the select-offer endpoint corrupts previously-withdrawn offer records by setting their status back to 'rejected'.

Expected Behavior

The select-offer updateMany call should include a status filter: {$in: ['pending']} to only reject pending offers, matching the service-layer behavior.

Reproduction Steps

Create a request with one withdrawn offer and one pending offer. Select the pending offer via POST /purchase-requests/:id/select-offer. Verify the withdrawn offer's status is now 'rejected'.

Affected Files

  • backend/src/routes/routes.ts

References