Conversation
…or non stackable offer
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a pre-purchase ownership check to the create-purchase-url route using a new getCustomerPurchaseContext helper. Refactors payments validation to centralize ownership and catalog checks, updates known error semantics for ProductDoesNotExist to use a context field, and adjusts e2e tests to the new structured error responses and a non-stackable duplicate purchase case. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant API as CreatePurchaseURL Route
participant Pay as payments.getCustomerPurchaseContext
participant DB as Prisma (tenancy)
participant Stripe as Stripe API
Client->>API: POST /payments/purchases/create-purchase-url (product_id, customer)
API->>Pay: getCustomerPurchaseContext(tenancy, customer, product_id)
Pay->>DB: Query one-time purchases + subscriptions
DB-->>Pay: Purchase/subscription data
Pay-->>API: { existingOneTimePurchases, subscriptions, alreadyOwnsProduct }
alt product non-stackable AND alreadyOwnsProduct
API-->>Client: 400 StatusError ("product not stackable for customer")
else product passes ownership check
API->>Stripe: Ensure/create customer & checkout session
Stripe-->>API: session URL
API-->>Client: 200 { url }
end
note right of API: Product existence/server-only errors use\nKnownErrors.ProductDoesNotExist with details.context
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🧰 Additional context used📓 Path-based instructions (2)**/*.test.{ts,tsx,js}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
🔇 Additional comments (4)
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. Comment |
There was a problem hiding this comment.
Review by RecurseML
🔍 Review performed on 017b43f..5fa068e
✨ No bugs found, your code is sparkling clean
✅ Files analyzed, no issues (5)
• apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts
• apps/backend/src/lib/payments.tsx
• apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.ts
• apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts
• packages/stack-shared/src/known-errors.tsx
There was a problem hiding this comment.
Greptile Overview
Summary
This PR improves error message handling in the payments system by standardizing error responses and adding better validation for non-stackable products. The changes span across multiple files to enhance the user experience when working with the payments API.The key improvements include:
-
Enhanced error messaging for product lookups: The
ProductDoesNotExisterror now provides contextual information to distinguish between different scenarios - when a product doesn't exist, when an item ID is used instead of a product ID, or when a server-only product is accessed from client-side code. -
Structured error responses: Error messages have been migrated from simple strings to structured JSON objects with error codes, details, and context fields. This follows the established
KnownErrorspattern used throughout the codebase for consistent, machine-readable error responses. -
Non-stackable product validation: A new validation layer prevents customers from creating purchase URLs for non-stackable products they already own. This is implemented by checking the customer's purchase history using a newly extracted utility function
getCustomerPurchaseContext. -
Code consolidation: Common customer purchase validation logic has been extracted into the reusable
getCustomerPurchaseContextfunction, reducing code duplication and improving maintainability.
These changes integrate well with the existing codebase architecture, following established patterns for error handling and API consistency. The improvements will make the payments API more developer-friendly by providing clearer, more actionable error messages.
Important Files Changed
Changed Files
| Filename | Score | Overview |
|---|---|---|
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts |
3/5 | Added validation for non-stackable product ownership but uses generic StatusError instead of KnownError |
apps/backend/src/lib/payments.tsx |
4/5 | Enhanced ProductDoesNotExist error with context and extracted customer purchase validation logic |
packages/stack-shared/src/known-errors.tsx |
5/5 | Improved ProductDoesNotExist error to use context parameter instead of generic accessType |
apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts |
4/5 | Updated test snapshots and added comprehensive non-stackable product ownership validation test |
apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.ts |
5/5 | Updated error message snapshots to reflect new structured error format |
Confidence score: 4/5
- This PR is generally safe to merge with good improvements to error messaging and user experience
- Score reflects solid functionality improvements but inconsistent error handling in one file
- Pay close attention to
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.tswhich uses StatusError instead of KnownError
Additional Comments (1)
-
apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.ts, line 19 (link)style: Error message inconsistency: this endpoint still returns a plain string error while other payment errors now return structured JSON objects
5 files reviewed, 4 comments
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts (1)
47-59: Do the non‑stackable ownership check before creating Stripe client; consider consistent error shape
- Move getStripeForAccount below this block to short‑circuit earlier and avoid unnecessary Stripe work.
- For consistency with other validation errors (e.g., RedirectUrlNotWhitelisted), consider a KnownError for “already owns non‑stackable” rather than a plain StatusError. At minimum, dedupe the exact message with validatePurchaseSession to avoid drift.
As per coding guidelines (consistent API responses)
apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts (1)
323-388: New non‑stackable duplicate purchase test is solid; minor assertion style tweakTest flow is good and deterministic. Optional: switch the final body assertion to an inline snapshot for consistency with test style.
- expect(secondResponse.body).toBe("Customer already has purchased this product; this product is not stackable"); + expect(secondResponse.body).toMatchInlineSnapshot( + "\"Customer already has purchased this product; this product is not stackable\"" + );As per coding guidelines (prefer .toMatchInlineSnapshot)
apps/backend/src/lib/payments.tsx (1)
460-466: Avoid message drift; centralize or standardize errorSame “already owns non‑stackable” text appears here and in the route. Consider:
- Extracting a shared constant for the message, or
- Introducing a KnownError (e.g., NON_STACKABLE_ALREADY_OWNED) to standardize the response shape and headers across endpoints.
As per coding guidelines (consistent API responses)
Also applies to: 468-470
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts(2 hunks)apps/backend/src/lib/payments.tsx(4 hunks)apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.ts(2 hunks)apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts(3 hunks)packages/stack-shared/src/known-errors.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
apps/backend/src/app/api/latest/**
📄 CodeRabbit inference engine (AGENTS.md)
apps/backend/src/app/api/latest/**: Organize backend API routes by resource under /api/latest (e.g., auth at /api/latest/auth/, users at /api/latest/users/, teams at /api/latest/teams/, oauth providers at /api/latest/oauth-providers/)
Use the custom route handler system in the backend to ensure consistent API responses
Files:
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer ES6 Map over Record when representing key–value collections
Files:
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.tsapps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.tspackages/stack-shared/src/known-errors.tsxapps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.tsapps/backend/src/lib/payments.tsx
**/*.test.{ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
In tests, prefer .toMatchInlineSnapshot where possible; refer to snapshot-serializer.ts for snapshot formatting and handling of non-deterministic values
Files:
apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.tsapps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts
🧬 Code graph analysis (3)
apps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.ts (3)
apps/backend/src/prisma-client.tsx (1)
getPrismaClientForTenancy(64-66)apps/backend/src/lib/payments.tsx (1)
getCustomerPurchaseContext(351-378)packages/stack-shared/src/utils/errors.tsx (1)
StatusError(152-261)
apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts (2)
apps/e2e/tests/helpers.ts (1)
it(11-11)apps/e2e/tests/backend/backend-helpers.ts (1)
niceBackendFetch(107-171)
apps/backend/src/lib/payments.tsx (5)
packages/stack-shared/src/utils/objects.tsx (1)
has(550-553)packages/stack-shared/src/known-errors.tsx (2)
KnownErrors(1575-1577)KnownErrors(1579-1701)apps/backend/src/prisma-client.tsx (1)
PrismaClientTransaction(18-18)apps/backend/src/lib/tenancies.tsx (1)
Tenancy(47-47)packages/stack-shared/src/utils/strings.tsx (1)
typedToUppercase(30-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Vercel Agent Review
- GitHub Check: docker
- GitHub Check: all-good
- GitHub Check: build (22.x)
- GitHub Check: docker
- GitHub Check: lint_and_build (latest)
- GitHub Check: build (22.x)
- GitHub Check: setup-tests
- GitHub Check: Security Check
🔇 Additional comments (7)
packages/stack-shared/src/known-errors.tsx (1)
1498-1512: Context-driven ProductDoesNotExist looks correctConstructor, details payload, and message branching align with tests and new semantics. No issues.
apps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.ts (2)
58-73: Snapshot updates to structured error payload LGTMMatches new ProductDoesNotExist shape with details.context = null.
236-249: Server-only case snapshot LGTMUses ProductDoesNotExist with details.context = "server_only" as intended.
apps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.ts (2)
58-73: Structured error snapshot for non-existent product LGTMCorrect code, message, and details.context = null.
236-249: Server-only structured error snapshot LGTMCorrectly asserts code, headers, and details.context = "server_only".
apps/backend/src/lib/payments.tsx (2)
35-40: Improved diagnostics for wrong product_id LGTMUsing has(...) to detect item_id collisions and returning ProductDoesNotExist with context "item_exists"/"server_only" matches the new semantics and tests.
351-378: getCustomerPurchaseContext helper LGTMConcise aggregation of purchases/subscriptions and a simple alreadyOwnsProduct flag. Fits reuse in route and validation.
…or non stackable offer
High-level PR Summary
This PR improves error messaging in the payments system by addressing two main issues: (1) providing clearer error messages when an item ID is mistakenly used as a product ID, including distinguishing between non-existent products, server-only products, and cases where an item exists with that ID, and (2) preventing checkout creation for non-stackable products that a customer already owns by adding an early validation check. The changes update the
ProductDoesNotExistknown error to include contextual information, introduce a newgetCustomerPurchaseContexthelper function to check existing purchases, and update related test snapshots to reflect the improved error messages.⏱️ Estimated Review Time: 15-30 minutes
💡 Review Order Suggestion
packages/stack-shared/src/known-errors.tsxapps/backend/src/lib/payments.tsxapps/backend/src/app/api/latest/payments/purchases/create-purchase-url/route.tsapps/e2e/tests/backend/endpoints/api/v1/payments/create-purchase-url.test.tsapps/e2e/tests/backend/endpoints/api/v1/payments/before-offer-to-product-rename/outdated--create-purchase-url.test.tsImportant
Enhances payment error handling by adding context to error messages and preventing duplicate purchases of non-stackable products.
create-purchase-url/route.tsto prevent checkout for non-stackable products already owned by the customer.ensureProductIdOrInlineProductinpayments.tsxto include context inProductDoesNotExisterror.getCustomerPurchaseContextinpayments.tsxto check existing purchases.ProductDoesNotExistinknown-errors.tsxto includecontext(null, server_only, item_exists).create-purchase-url.test.ts,purchase-session.test.ts, andvalidate-code.test.tsto reflect new error messages and behavior.This description was created by
for 5495b9c. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Bug Fixes
Tests