Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: purchases hardening#7

Merged
0-sayed merged 4 commits intomainfrom
fix/purchases-hardening
Mar 3, 2026
Merged

fix: purchases hardening#7
0-sayed merged 4 commits intomainfrom
fix/purchases-hardening

Conversation

@0-sayed
Copy link
Owner

@0-sayed 0-sayed commented Mar 2, 2026

No description provided.

0-sayed added 2 commits March 3, 2026 00:57
Extract the inline UUID regex from user-id.guard and purchases.controller
into src/common/validation/uuid.ts. Update purchase DTO to import from the
shared module and drop the redundant @IsString() decorator alongside @matches().
…ryError wrapping

Replace JS-side .sort() with .orderBy(asc(wallets.id)) in the FOR UPDATE
query so PostgreSQL itself enforces consistent lock acquisition order,
eliminating the circular wait that causes deadlocks.

Unwrap DrizzleQueryError when catching postgres errors — Drizzle wraps
raw PostgresError in a generic Error with cause, so check both the error
and error.cause for the pg error code. Add PG_DEADLOCK (40P01) as a
handled code with a ConflictException response as a safety net.

Add unit test for the DrizzleQueryError wrapping path, concurrency e2e
spec, and set runInBand: true in jest-e2e.json to serialize e2e runs.
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly hardens the purchase system by addressing potential concurrency issues and centralizing UUID validation logic. The changes ensure that concurrent purchase requests are handled reliably, preventing deadlocks and correctly managing idempotency keys. By extracting the UUID regex, the PR also improves code maintainability and consistency for UUID validation across different modules. The addition of new E2E tests provides strong assurance of the system's stability under high load.

Highlights

  • Centralized UUID Validation: The UUID regular expression has been extracted into a dedicated shared file, promoting reusability and consistency across the application for validation.
  • Enhanced Purchase Concurrency Handling: Implemented robust mechanisms to prevent database deadlocks during concurrent purchase transactions by enforcing a consistent lock acquisition order and improved error handling for unique constraint violations and deadlocks.
  • Comprehensive Concurrency E2E Tests: New end-to-end tests have been added to thoroughly validate the system's behavior under concurrent purchase scenarios, including parallel purchases and duplicate idempotency keys.
Changelog
  • src/common/guards/user-id.guard.ts
    • Removed the local UUID regex definition and imported it from the new shared validation module.
  • src/common/validation/uuid.ts
    • Added a new file to define and export the UUID_REGEX constant for centralized UUID validation.
  • src/purchases/dto/purchase.dto.ts
    • Replaced the @IsUUID() decorator with @matches(UUID_REGEX) for buyerWalletId and authorWalletId to use the shared regex and provide custom error messages.
  • src/purchases/purchases.controller.ts
    • Removed the local UUID_REGEX definition and imported it from the shared validation module.
  • src/purchases/purchases.service.spec.ts
    • Imported PostgresError, added orderBy to the mock transaction, and introduced a new test suite to verify correct error handling for DrizzleQueryError wrapping PostgresError unique violations.
  • src/purchases/purchases.service.ts
    • Added a constant for PostgreSQL deadlock error code (PG_DEADLOCK), imported asc for Drizzle ORM, modified wallet locking to use orderBy(asc(...)) to prevent deadlocks, and enhanced the error handling logic to specifically catch and respond to PG_UNIQUE_VIOLATION and PG_DEADLOCK errors, including those wrapped by DrizzleQueryError.
  • test/concurrency.e2e-spec.ts
    • Added a new end-to-end test file to simulate and verify concurrent purchase operations, including scenarios for insufficient funds and duplicate idempotency keys.
  • test/jest-e2e.json
    • Configured Jest to run end-to-end tests serially using runInBand: true to ensure reliable testing of concurrency-sensitive scenarios.
Activity
  • No human activity (comments, reviews) has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly hardens the purchase logic by improving concurrency handling and centralizing validation. The introduction of orderBy in the SELECT FOR UPDATE query is the correct approach to prevent deadlocks, and the enhanced error handling for wrapped Postgres errors makes the service more robust. The new end-to-end concurrency tests are a great addition, providing confidence in these critical paths. I have one minor suggestion to refactor the error handling block to improve its structure.

@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 071aefe and 0738bf3.

📒 Files selected for processing (1)
  • test/concurrency.e2e-spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/concurrency.e2e-spec.ts

Walkthrough

This change refactors UUID validation by extracting a shared UUID_REGEX constant used across multiple files, updates purchase DTO validation from decorator-based to regex-based matching with custom error messages, and enhances database error handling in the purchase service to detect and handle PostgreSQL deadlocks (40P01) and unique constraint violations (23505). Additionally, it adds deterministic wallet row ordering to mitigate deadlocks and introduces an end-to-end concurrency test suite validating parallel purchase requests and idempotency key behavior, with Jest configured to run e2e tests serially.

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether one is related to the changeset. Add a pull request description explaining the hardening changes: UUID validation centralization, deadlock mitigation via deterministic wallet locking, idempotency key conflict handling, and concurrency test coverage.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'fix: purchases hardening' is vague and generic, using broad terminology that doesn't convey the specific nature of the changes made. Use a more specific title that describes the actual hardening measures, such as 'fix: centralize UUID validation and add deadlock/idempotency error handling' or similar.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/purchases-hardening

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/concurrency.e2e-spec.ts`:
- Around line 42-61: The fixture seeding silently no-ops because
.onConflictDoNothing() on schema.wallets can skip inserting required wallet
rows; change the wallets insert to either remove .onConflictDoNothing() or
replace it with an upsert such as .onConflictDoUpdate(...) that sets the desired
fields (e.g., balance and userId) so the fixture always exists with expected
values, and add a quick assertion/guard after the transaction (or inside it) to
throw if the wallets table did not contain the expected rows (e.g., check
affected row count or select the inserted IDs) so the test fails fast instead of
proceeding with missing fixtures; update references in this block
(db.transaction, tx.insert(schema.wallets),
PLATFORM_WALLET_ID/ALICE_WALLET_ID/BOB_WALLET_ID) accordingly.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e12feef and 1b12aec.

📒 Files selected for processing (8)
  • src/common/guards/user-id.guard.ts
  • src/common/validation/uuid.ts
  • src/purchases/dto/purchase.dto.ts
  • src/purchases/purchases.controller.ts
  • src/purchases/purchases.service.spec.ts
  • src/purchases/purchases.service.ts
  • test/concurrency.e2e-spec.ts
  • test/jest-e2e.json

@idris-builds
Copy link
Collaborator

@coderabbitai review
@greptileai review
@gemini review

@gemini-code-assist
Copy link

It looks like you're trying to request a full code review. To initiate a new code review, please use the command /gemini review in a new comment. The @gemini tag is typically used for direct replies within a conversation.

@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

@idris-builds: I'll review the changes in this PR.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@0-sayed 0-sayed force-pushed the fix/purchases-hardening branch from 071aefe to 7596353 Compare March 2, 2026 23:56
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/concurrency.e2e-spec.ts`:
- Around line 43-55: The platform fixture inserts in the db.transaction using
tx.insert into schema.users and schema.wallets are not idempotent and cause
duplicate key errors; modify the seeding so it is safe to run multiple times by
using an upsert/ignore-on-conflict strategy (e.g., insert with ON CONFLICT DO
NOTHING or equivalent upsert method provided by your DB library) when calling
tx.insert for schema.users and schema.wallets, or check existence before
inserting, ensuring PLATFORM_ID/PLATFORM_WALLET_ID rows are skipped or merged
rather than re-inserted.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b12aec and 071aefe.

📒 Files selected for processing (2)
  • pr.md
  • test/concurrency.e2e-spec.ts

@0-sayed 0-sayed force-pushed the fix/purchases-hardening branch from e6d0a8b to 0738bf3 Compare March 3, 2026 00:08
@idris-builds
Copy link
Collaborator

@coderabbitai review
@greptileai review
@gemini review

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

@idris-builds: I'll review the changes in this PR.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly hardens the purchasing functionality by improving deadlock prevention, making error handling more robust, and adding comprehensive end-to-end concurrency tests. The refactoring of UUID validation into a shared constant is also a good improvement for maintainability. My review includes one suggestion to further align with NestJS conventions by using a validation pipe in the controller.

@0-sayed 0-sayed merged commit ae23763 into main Mar 3, 2026
7 checks passed
@0-sayed 0-sayed deleted the fix/purchases-hardening branch March 3, 2026 00:24
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.

2 participants