Skip to content

fix(transactions): prevent TTL reaper from deleting confirmed transactions (#94) - #97

Open
ghzhost wants to merge 1 commit into
Deen-Bridge:devfrom
ghzhost:fix/ttl-reaping-non-pending-transactions
Open

fix(transactions): prevent TTL reaper from deleting confirmed transactions (#94)#97
ghzhost wants to merge 1 commit into
Deen-Bridge:devfrom
ghzhost:fix/ttl-reaping-non-pending-transactions

Conversation

@ghzhost

@ghzhost ghzhost commented Aug 16, 2026

Copy link
Copy Markdown

Summary

Fixes #94

This PR resolves a critical bug where confirmed transactions (and other terminal state transactions) were being deleted ~30 minutes after creation by MongoDB's background TTL thread.

Root Cause

  1. Transaction.js schema defined a blanket TTL index { expiresAt: 1 } with { expireAfterSeconds: 0 } matching all documents.
  2. The schema had an unconditional default timestamp Date.now() + 30m for expiresAt.
  3. Terminal status transitions (confirmed, failed, refunded, expired, disputed) did not unset expiresAt, leaving confirmed purchases and donations vulnerable to permanent automatic purging.

Changes Made

  1. Scoped Partial TTL Index: Updated transactionSchema to use partialFilterExpression: { status: "pending" } so MongoDB's TTL reaper only matches pending records.
  2. Conditional Default on Schema: Modified expiresAt default function to return a 30-minute timestamp ONLY when this.status === "pending" (or unset), returning undefined for records created directly in terminal states.
  3. Explicit Invariant Unsetting:
    • src/controllers/stellar/paymentController.js: Clears expiresAt = undefined on purchase confirmation & validation/network failures, and unsets on cancellation.
    • src/controllers/stellar/donationController.js: Clears expiresAt = undefined on donation confirmation & failures.
    • src/services/stellar/reconciliationService.js: Clears expiresAt = undefined in promoteTransaction.
    • src/controllers/stellar/refundController.js: Unsets expiresAt during refund confirmation and dispute escalation.
    • src/jobs/handlers.js: Clears expiresAt = undefined on background on-chain verification confirmation or failure.
  4. Data & Index Migration: Added idempotent migration src/migrations/fixTtlTransactionExpiry.js to $unset expiresAt on existing non-pending records and rebuild the partial index.
  5. Lifecycle Documentation: Added docs/transaction-lifecycle.md documenting the status-to-expiry invariants and architecture safeguards.
  6. Automated Tests: Added test/ttlTransactionExpiry.test.js validating schema defaults, non-pending creations, legacy data backfilling, and partial index construction (100% test suite passing: 30 test suites, 296 passed).

Closes #94

…tions (Deen-Bridge#94)

- Scope TTL index to pending transactions using partialFilterExpression
- Set conditional default for expiresAt so confirmed/terminal records omit expiry
- Explicitly clear expiresAt on all terminal states (confirmed, failed, refunded, expired, disputed)
- Add idempotent fixTtlTransactionExpiry migration to unset legacy expiresAt and update index
- Document status -> expiresAt lifecycle invariants
- Add comprehensive test suite in test/ttlTransactionExpiry.test.js
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 08beaa08-cb09-4955-9c76-1f66ebddd613


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch conflicts with the base branch. Please rebase and resolve conflicts before requesting merge.

2 similar comments
@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch conflicts with the base branch. Please rebase and resolve conflicts before requesting merge.

@zeemscript

Copy link
Copy Markdown
Collaborator

Strict review blocker: this branch conflicts with the base branch. Please rebase and resolve conflicts before requesting merge.

@zeemscript

Copy link
Copy Markdown
Collaborator

@ghzhost this PR has merge conflicts with the main branch. Please resolve the conflicts (merge main in or rebase) and push the fix so it can be merged. Thanks!

@zeemscript

Copy link
Copy Markdown
Collaborator

@samjay8 you are assigned to the issue that PR #97 addresses, which currently has merge conflicts with the main branch. Please resolve the conflicts (merge main in or rebase) and push the fix so it can be merged. Thanks!

@samjay8

samjay8 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Hi @zeemscript , my PR that addresses this issue has been merged, however this PR was also created addressing the issue, and apparently wasn't merged by you. I am not the author of the PR, hence I can't be able to work or resolve the conflicts. I would advise you close it withh the proper label for it since my pr already addressed it and it has been merged.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants