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

Skip to content

Conversation

@BilalG1
Copy link
Collaborator

@BilalG1 BilalG1 commented Oct 30, 2025

https://www.loom.com/share/db645a1799454ec6b0234c55ee28cee9

Summary by CodeRabbit

  • New Features

    • Unified, schema-driven transaction model with richer multi-currency amounts and clearer transaction type labels/icons.
    • New transaction builders producing consistent, entry-based transaction objects for purchases, subscriptions, and item-quantity changes.
  • Refactor

    • Backend, SDK and admin UI migrated to the new Transaction/TransactionType surface; table rendering now uses summary-driven columns and avatar cells; client APIs updated to use the new types.
  • Bug Fixes

    • Fixed aggregation, sorting and cursor/pagination across mixed transaction sources.
  • Tests

    • Updated endpoint snapshots and serializers to match the new transaction shape and effective_at_millis handling.

Note

Introduce a new schema-driven Transaction model with builders, update the transactions API/SDK to return entry-based transactions, revamp the admin table UI, and extend tests/pagination/filters.

  • Shared Schema/Types:
    • Replace AdminTransaction with unified Transaction model and TransactionEntry union; add TRANSACTION_TYPES.
    • New fields: effective_at_millis, entries, adjusted_by, multi-currency charged_amount/net_amount.
  • Backend:
    • Transactions endpoint now returns transactionSchema; supports filtering by TRANSACTION_TYPES and customer type.
    • Add transaction-builder to construct entry-based transactions for subscriptions, one-time purchases, and manual item quantity changes (including money transfer/product grant entries and currency math).
    • Merge/sort/paginate across sources; map to unified transactions; update cursor logic.
  • Admin SDK/Template:
    • Update interfaces and caches to use Transaction/TransactionType in listTransactions and related hooks.
  • Dashboard UI:
    • Refactor transaction table to show icons/labels, customer avatars/links, amount and detail from transaction entries; add filters using TRANSACTION_TYPES.
  • Tests:
    • Update snapshots and serializer (strip effective_at_millis).
    • Add tests for type/customer filters, pagination, and server-granted subscriptions.

Written by Cursor Bugbot for commit e77f688. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Oct 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
stack-backend Ready Ready Preview Comment Nov 14, 2025 11:40am
stack-dashboard Ready Ready Preview Comment Nov 14, 2025 11:40am
stack-demo Ready Ready Preview Comment Nov 14, 2025 11:40am
stack-docs Ready Ready Preview Comment Nov 14, 2025 11:40am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

Note

Other AI code review bot(s) detected

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

Walkthrough

Replaces the legacy AdminTransaction shape with a typed Transaction schema and entry-based model; adds transaction-builder functions; updates the backend transactions route, shared SDK/types, dashboard table rendering, and end-to-end tests to consume and return the new Transaction objects.

Changes

Cohort / File(s) Summary
Core Transaction Schema & Types
packages/stack-shared/src/interface/crud/transactions.ts
Remove AdminTransaction; add transactionSchema, Transaction, TransactionEntry union, TRANSACTION_TYPES/TransactionType, multi-currency charged_amount/net_amount, and entry schemas (money_transfer, product_grant, item_quantity_change, revocation, reversal).
Transaction Builders
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts
New module exporting buildSubscriptionTransaction, buildOneTimePurchaseTransaction, buildItemQuantityChangeTransaction, ProductWithPrices, plus helpers for price resolution, money arithmetic, and entry assembly.
Backend API Route
apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx
Replace AdminTransaction-based retrieval with merged TransactionRow[]; use transaction-builder functions to construct typed Transaction objects; validate with transactionSchema; merge/sort rows and compute next_cursor from merged last IDs.
Dashboard Transaction Table
apps/dashboard/src/components/data-table/transaction-table.tsx
Refactor rendering to derive TransactionSummary from entry-level data; add entry type guards, avatar cells, formatted type labels, new filter keys mapped to TRANSACTION_TYPES, and summary-driven columns.
Shared Admin Interface (SDK)
packages/stack-shared/src/interface/admin-interface.ts
listTransactions updated to accept TransactionType and return Transaction[]; query construction and JSON casting updated to the new schema.
Template / Admin App Implementations & Types
packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts, packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
Replace AdminTransaction with Transaction; use TransactionType in public signatures, caches, and listTransactions / useTransactions return types.
Tests & Snapshot Serializer
apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts, apps/e2e/tests/snapshot-serializer.ts
Update tests and snapshots to expect entries array, effective_at_millis, adjusted_by; add effective_at_millis to strip list; add tests covering type/customer filters and merged-source scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Route as GET /internal/payments/transactions
    participant DB as Database
    participant Builder as Transaction Builder
    participant Schema as transactionSchema

    Client->>Route: GET /transactions?type=...&cursor=...
    Route->>DB: fetch subscriptions, one-time purchases, item-qty-changes (parallel)
    DB-->>Route: raw rows (subs / otps / iqcs)
    Route->>Route: merge & sort rows -> TransactionRow[]
    Route->>Builder: buildTransaction(row) for each row
    Builder-->>Route: Transaction
    Route->>Schema: validate Transaction[]
    Schema-->>Route: validated
    Route-->>Client: { transactions: Transaction[], next_cursor }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay special attention to:
    • packages/stack-shared/src/interface/crud/transactions.ts — union validation, multi-currency invariants, TRANSACTION_TYPES.
    • apps/backend/.../transaction-builder.ts — price resolution, money arithmetic, test-mode behavior, and edge cases.
    • apps/backend/.../route.tsx — merging, sorting, pagination, and cursor computation across heterogeneous sources.
    • apps/dashboard/.../transaction-table.tsx — summary derivation and filter translation correctness.

Possibly related PRs

Poem

🐇 I hop through rows and stitch each trace,

entries nested in tidy place.
Builders hum and cursors glide,
transactions sorted, side by side.
A carrot for tests — neat code, we pride!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Payment transactions' is vague and generic, using non-specific terminology that doesn't convey the actual scope or nature of the changes. Revise the title to be more descriptive, such as 'Replace AdminTransaction with entry-based Transaction model' or 'Refactor payment transaction schema to use entries'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed PR description includes a comprehensive summary generated by Cursor Bugbot covering all major changes (schema, backend, SDK, UI, tests), but lacks traditional structure with explicit section headings or the CONTRIBUTING.md guideline acknowledgment beyond a comment.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch payment-transactions

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
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR refactors the payment transaction API to use dedicated builder functions, improving code organization and maintainability.

Key Changes

  • Refactored transaction construction: Extracted transaction building logic from the route handler into dedicated builder functions (buildSubscriptionTransaction, buildOneTimePurchaseTransaction, buildItemQuantityChangeTransaction)
  • Added comprehensive tests: New test file covers edge cases including missing product snapshots, test mode handling, and money amount multiplication
  • Improved type safety: Better separation between internal TransactionSource types and external Transaction types
  • Frontend integration: Added transaction table component with filtering by type and customer type
  • Money arithmetic: Implemented proper decimal handling for multi-currency amounts using BigInt for precision

Architecture Improvements

The refactoring follows good separation of concerns:

  1. Route handler manages pagination and API concerns
  2. Builder functions handle transaction object construction
  3. Money arithmetic is isolated and well-tested
  4. Type definitions are centralized in shared package

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - the refactoring improves code quality and has comprehensive test coverage
  • Score reflects solid refactoring with good test coverage. Minor concern about pagination efficiency when filtering after merge-sort, but unlikely to cause issues in practice
  • Pay attention to apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx - the pagination logic filters transactions after fetching and merging, which may need optimization for large datasets

Important Files Changed

File Analysis

Filename Score Overview
apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx 4/5 Refactored to use builder functions for transaction construction; improved maintainability and separation of concerns
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts 5/5 New file with comprehensive test coverage; implements transaction building logic with proper money arithmetic
apps/dashboard/src/components/data-table/transaction-table.tsx 4/5 Frontend component for displaying transactions with filtering and pagination; uses Map for customer data lookup

Sequence Diagram

sequenceDiagram
    participant Client as Dashboard Client
    participant API as Transaction API Route
    participant Builder as Transaction Builder
    participant DB as Prisma Database
    participant Interface as Admin Interface

    Client->>Interface: listTransactions(params)
    Interface->>API: GET /internal/payments/transactions
    
    Note over API: Parse cursor (sub|iqc|otp)
    Note over API: Validate limit (1-200)
    
    API->>DB: Find subscription cursor
    API->>DB: Find item change cursor
    API->>DB: Find purchase cursor
    
    par Fetch all transaction sources
        API->>DB: findMany(subscriptions)
        API->>DB: findMany(itemQuantityChanges)
        API->>DB: findMany(oneTimePurchases)
    end
    
    DB-->>API: Return records
    
    loop For each source type
        API->>Builder: buildSubscriptionTransaction
        Builder-->>API: Transaction object
        API->>Builder: buildItemQuantityChangeTransaction
        Builder-->>API: Transaction object
        API->>Builder: buildOneTimePurchaseTransaction
        Builder-->>API: Transaction object
    end
    
    Note over API: Sort by createdAt DESC, id DESC
    Note over API: Filter by transaction type
    Note over API: Slice to page limit
    Note over API: Build next cursor
    
    API-->>Interface: {transactions, next_cursor}
    Interface-->>Client: {transactions, nextCursor}
    Client->>Client: Display in TransactionTable
Loading

9 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@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: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aea7ad0 and db16ac2.

📒 Files selected for processing (9)
  • apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx (4 hunks)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts (1 hunks)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1 hunks)
  • apps/backend/src/lib/email-rendering.tsx (2 hunks)
  • apps/dashboard/src/components/data-table/transaction-table.tsx (2 hunks)
  • packages/stack-shared/src/interface/admin-interface.ts (3 hunks)
  • packages/stack-shared/src/interface/crud/transactions.ts (1 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (3 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use ES6 Maps instead of Records wherever possible in TypeScript code

Files:

  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts
  • apps/backend/src/lib/email-rendering.tsx
  • apps/dashboard/src/components/data-table/transaction-table.tsx
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
  • packages/stack-shared/src/interface/admin-interface.ts
  • apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
  • packages/stack-shared/src/interface/crud/transactions.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When writing tests, prefer .toMatchInlineSnapshot over other selectors where possible

Files:

  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts
apps/{dashboard,dev-launchpad}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

For blocking alerts and errors in the UI, never use toast; use alerts instead

Files:

  • apps/dashboard/src/components/data-table/transaction-table.tsx
apps/{dashboard,dev-launchpad}/**/*.{css,tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Animations: keep hover/click transitions snappy; do not delay actions with pre-hover transitions; apply transitions after the action (e.g., fade-out on hover end)

Files:

  • apps/dashboard/src/components/data-table/transaction-table.tsx
packages/template/**

📄 CodeRabbit inference engine (AGENTS.md)

When changes are needed for stack or js packages, make them in packages/template instead

Files:

  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
🧠 Learnings (1)
📚 Learning: 2025-10-20T22:25:40.427Z
Learnt from: CR
PR: stack-auth/stack-auth#0
File: AGENTS.md:0-0
Timestamp: 2025-10-20T22:25:40.427Z
Learning: Applies to apps/backend/src/app/api/latest/**/route.ts : In backend API routes, use the custom route handler system to ensure consistent API responses

Applied to files:

  • apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx
🧬 Code graph analysis (8)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts (2)
apps/backend/src/lib/tenancies.tsx (1)
  • Tenancy (47-47)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (3)
  • buildSubscriptionTransaction (173-216)
  • buildOneTimePurchaseTransaction (218-261)
  • buildItemQuantityChangeTransaction (263-291)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (3)
packages/stack-shared/src/utils/currency-constants.tsx (2)
  • Currency (3-7)
  • SUPPORTED_CURRENCIES (9-45)
packages/stack-shared/src/utils/strings.tsx (1)
  • typedToLowercase (15-18)
apps/backend/src/lib/tenancies.tsx (1)
  • Tenancy (47-47)
apps/dashboard/src/components/data-table/transaction-table.tsx (4)
packages/stack-shared/src/interface/crud/transactions.ts (4)
  • TransactionEntry (176-176)
  • Transaction (206-206)
  • TransactionType (189-189)
  • TRANSACTION_TYPES (178-187)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx (1)
  • useAdminApp (29-44)
packages/stack-ui/src/components/data-table/cells.tsx (2)
  • AvatarCell (45-52)
  • TextCell (7-43)
packages/stack-ui/src/components/data-table/data-table.tsx (1)
  • DataTableManualPagination (174-238)
packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (2)
packages/template/src/lib/stack-app/apps/implementations/common.ts (1)
  • createCache (29-34)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (189-189)
  • Transaction (206-206)
packages/stack-shared/src/interface/admin-interface.ts (1)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (189-189)
  • Transaction (206-206)
apps/backend/src/app/api/latest/internal/payments/transactions/route.tsx (2)
packages/stack-shared/src/interface/crud/transactions.ts (3)
  • TRANSACTION_TYPES (178-187)
  • transactionSchema (191-204)
  • Transaction (206-206)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (3)
  • buildSubscriptionTransaction (173-216)
  • buildItemQuantityChangeTransaction (263-291)
  • buildOneTimePurchaseTransaction (218-261)
packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts (1)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (189-189)
  • Transaction (206-206)
packages/stack-shared/src/interface/crud/transactions.ts (4)
packages/stack-shared/src/utils/currency-constants.tsx (3)
  • SUPPORTED_CURRENCIES (9-45)
  • Currency (3-7)
  • MoneyAmount (1-1)
packages/stack-shared/src/utils/errors.tsx (1)
  • throwErr (10-19)
packages/stack-shared/src/schema-fields.ts (8)
  • yupString (187-190)
  • yupObject (247-251)
  • yupNumber (191-194)
  • customerTypeSchema (547-547)
  • productSchema (569-592)
  • yupUnion (257-281)
  • yupArray (213-216)
  • yupBoolean (195-198)
packages/stack-shared/src/utils/objects.tsx (1)
  • typedFromEntries (281-283)
⏰ 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). (12)
  • GitHub Check: all-good
  • GitHub Check: Vercel Agent Review
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: docker
  • GitHub Check: setup-tests
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: Security Check

Copy link
Contributor

@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

♻️ Duplicate comments (1)
apps/dashboard/src/components/data-table/transaction-table.tsx (1)

131-139: USD-only handling remains unresolved.

This issue was already flagged in a previous review. The function still only displays USD amounts and shows '—' for all other currencies, which blanks the amount column for non-USD tenants. Please refer to the previous review comment for the proposed solution.

🧹 Nitpick comments (2)
apps/dashboard/src/components/data-table/transaction-table.tsx (2)

51-58: Consider simplifying the redundant check.

The condition at line 56 returns 'other' when a productGrant exists without subscription or purchase IDs, but line 57 also returns 'other' as the default. Since both paths lead to the same result, line 56 can be removed.

Apply this diff:

 function deriveSourceType(transaction: Transaction): SourceType {
   if (transaction.entries.some(isItemQuantityChangeEntry)) return 'item_quantity_change';
   const productGrant = transaction.entries.find(isProductGrantEntry);
   if (productGrant?.subscription_id) return 'subscription';
   if (productGrant?.one_time_purchase_id) return 'one_time';
-  if (productGrant) return 'other';
   return 'other';
 }

86-89: Improve type safety in the default fallback.

The as any cast suppresses type checking. Since transactionType is typed as TransactionType | null, the default case should only handle null. Consider using a type-safe fallback.

Apply this diff:

     default: {
-      return { label: (transactionType as any) ?? '—', Icon: CircleHelp };
+      return { label: transactionType ?? 'Unknown', Icon: CircleHelp };
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db16ac2 and 5b1a8c5.

📒 Files selected for processing (1)
  • apps/dashboard/src/components/data-table/transaction-table.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use ES6 Maps instead of Records wherever possible in TypeScript code

Files:

  • apps/dashboard/src/components/data-table/transaction-table.tsx
apps/{dashboard,dev-launchpad}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

For blocking alerts and errors in the UI, never use toast; use alerts instead

Files:

  • apps/dashboard/src/components/data-table/transaction-table.tsx
apps/{dashboard,dev-launchpad}/**/*.{css,tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Animations: keep hover/click transitions snappy; do not delay actions with pre-hover transitions; apply transitions after the action (e.g., fade-out on hover end)

Files:

  • apps/dashboard/src/components/data-table/transaction-table.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/components/data-table/transaction-table.tsx (4)
packages/stack-shared/src/interface/crud/transactions.ts (4)
  • TransactionEntry (176-176)
  • Transaction (206-206)
  • TransactionType (189-189)
  • TRANSACTION_TYPES (178-187)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx (1)
  • useAdminApp (29-44)
packages/stack-ui/src/components/data-table/cells.tsx (2)
  • AvatarCell (45-52)
  • TextCell (7-43)
packages/stack-ui/src/components/data-table/data-table.tsx (1)
  • DataTableManualPagination (174-238)
⏰ 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). (12)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: restart-dev-and-test
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: all-good
  • GitHub Check: Vercel Agent Review
  • GitHub Check: docker
  • GitHub Check: Security Check
🔇 Additional comments (1)
apps/dashboard/src/components/data-table/transaction-table.tsx (1)

172-172: Verify the test mode amount display behavior.

Test mode transactions display 'Test mode' instead of the actual amount. Please confirm whether this is the intended UX or if both the test mode indicator and the amount should be shown (e.g., '$10.00 (Test mode)').

Copy link
Contributor

@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

♻️ Duplicate comments (3)
apps/dashboard/src/components/data-table/transaction-table.tsx (2)

131-139: Fix amount display for non-USD charges.

This issue was flagged in a previous review and remains unresolved. pickChargedAmountDisplay only returns USD amounts; all other currencies render as '—', which blanks the amount column for non-USD tenants.


192-218: Fix critical type mismatch in transaction filtering logic.

This issue was flagged in a previous review and remains unresolved. The column returns SourceType values but the toolbar populates the filter dropdown with TransactionType values from TRANSACTION_TYPES. These value sets don't overlap, so filtering will never match and always return empty results.

apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1)

125-146: Net amount is forced to USD "0" for non‑USD charges.

This issue was flagged in a previous review and remains unresolved. If a purchase is denominated solely in a non-USD currency (e.g., EUR), this code emits net_amount: { USD: "0" }, causing downstream reporting to falsely record zero revenue.

This is compounded by the schema constraint in packages/stack-shared/src/interface/crud/transactions.ts (lines 90-92) that only allows USD in net_amount.

🧹 Nitpick comments (1)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1)

263-291: Unused parameter in buildItemQuantityChangeTransaction.

The tenancy parameter is accepted but never used in the function body. Consider removing it if it's not needed, or add a comment explaining why it's reserved for future use.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b1a8c5 and 47141ce.

📒 Files selected for processing (5)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts (1 hunks)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1 hunks)
  • apps/dashboard/src/components/data-table/transaction-table.tsx (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts (3 hunks)
  • packages/stack-shared/src/interface/crud/transactions.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.test.ts
🧰 Additional context used
🧬 Code graph analysis (3)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (5)
packages/stack-shared/src/schema-fields.ts (1)
  • productSchema (569-592)
apps/backend/src/lib/payments.tsx (1)
  • productToInlineProduct (427-443)
packages/stack-shared/src/utils/currency-constants.tsx (2)
  • Currency (3-7)
  • SUPPORTED_CURRENCIES (9-45)
packages/stack-shared/src/utils/strings.tsx (1)
  • typedToLowercase (15-18)
apps/backend/src/lib/tenancies.tsx (1)
  • Tenancy (47-47)
apps/dashboard/src/components/data-table/transaction-table.tsx (6)
packages/stack-shared/src/interface/crud/transactions.ts (4)
  • TransactionEntry (176-176)
  • Transaction (206-206)
  • TransactionType (189-189)
  • TRANSACTION_TYPES (178-187)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/use-admin-app.tsx (1)
  • useAdminApp (29-44)
packages/stack-ui/src/components/data-table/cells.tsx (2)
  • AvatarCell (45-52)
  • TextCell (7-43)
packages/stack-ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (40-40)
  • TooltipTrigger (40-40)
  • TooltipContent (40-40)
packages/stack-ui/src/components/data-table/data-table.tsx (1)
  • DataTableManualPagination (174-238)
packages/stack-ui/src/components/ui/select.tsx (5)
  • Select (160-160)
  • SelectTrigger (160-160)
  • SelectValue (160-160)
  • SelectContent (160-160)
  • SelectItem (160-160)
packages/stack-shared/src/interface/crud/transactions.ts (4)
packages/stack-shared/src/utils/currency-constants.tsx (3)
  • SUPPORTED_CURRENCIES (9-45)
  • Currency (3-7)
  • MoneyAmount (1-1)
packages/stack-shared/src/utils/errors.tsx (1)
  • throwErr (10-19)
packages/stack-shared/src/schema-fields.ts (8)
  • yupString (187-190)
  • yupObject (247-251)
  • yupNumber (191-194)
  • customerTypeSchema (547-547)
  • inlineProductSchema (606-631)
  • yupUnion (257-281)
  • yupArray (213-216)
  • yupBoolean (195-198)
packages/stack-shared/src/utils/objects.tsx (1)
  • typedFromEntries (281-283)
⏰ 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). (12)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: docker
  • GitHub Check: restart-dev-and-test
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: all-good
  • GitHub Check: setup-tests
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Security Check

Copy link
Contributor

@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: 0

♻️ Duplicate comments (1)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1)

124-145: Net amount is forced to USD "0" for non‑USD charges.

This issue was already identified in a previous review. When a purchase is denominated solely in EUR or another non-USD currency, this code still emits net_amount: { USD: "0" }, falsely recording zero revenue. The net_amount should reflect the actual charged currencies instead of fabricating zero USD values.

🧹 Nitpick comments (2)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (2)

30-52: Consider validating the fallback structure.

The as ProductSnapshot cast on line 41 bypasses type checking. While the structure appears complete, if ProductSnapshot evolves, this could lead to runtime type mismatches.

Consider using a schema validator or ensuring all fields match the expected type explicitly:

   return {
     display_name: options.displayName,
     customer_type: options.customerType,
     prices: {},
     stackable: false,
     server_only: false,
     included_items: {},
+    client_metadata: null,
+    client_read_only_metadata: null,
+    server_metadata: null,
-  } as ProductSnapshot;
+  };

172-260: Consider extracting shared logic from subscription and one-time purchase builders.

buildSubscriptionTransaction and buildOneTimePurchaseTransaction share nearly identical logic (~45 lines of duplication), differing only in which ID field they pass to createProductGrantEntry. Extracting common logic would improve maintainability.

Consider creating a shared helper:

function buildPurchaseTransaction(options: {
  entity: Subscription | OneTimePurchase,
  idField: { subscriptionId?: string } | { oneTimePurchaseId?: string },
}): Transaction {
  const { entity, idField } = options;
  const customerType = typedToLowercase(entity.customerType);
  const product = entity.product as InferType<typeof productSchema> | null;
  const productSnapshot = ensureProductSnapshot(product, customerType);
  const selectedPrice = product ? resolveSelectedPriceFromProduct(product, entity.priceId ?? null) : null;
  const quantity = entity.quantity;
  const chargedAmount = buildChargedAmount(selectedPrice, quantity);
  const testMode = entity.creationSource === "TEST_MODE";

  const entries: TransactionEntry[] = [
    createProductGrantEntry({
      customerType,
      customerId: entity.customerId,
      productId: entity.productId ?? null,
      product: productSnapshot,
      priceId: entity.priceId ?? null,
      quantity,
      ...idField,
    }),
  ];

  const moneyTransfer = createMoneyTransferEntry({
    customerType,
    customerId: entity.customerId,
    chargedAmount,
    skip: testMode,
  });
  if (moneyTransfer) {
    entries.push(moneyTransfer);
  }

  return {
    id: entity.id,
    created_at_millis: entity.createdAt.getTime(),
    effective_at_millis: entity.createdAt.getTime(),
    type: "purchase",
    entries,
    adjusted_by: [],
    test_mode: testMode,
  };
}

export function buildSubscriptionTransaction(options: { subscription: Subscription }): Transaction {
  return buildPurchaseTransaction({
    entity: options.subscription,
    idField: { subscriptionId: options.subscription.id },
  });
}

export function buildOneTimePurchaseTransaction(options: { purchase: OneTimePurchase }): Transaction {
  return buildPurchaseTransaction({
    entity: options.purchase,
    idField: { oneTimePurchaseId: options.purchase.id },
  });
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b30fa8c and 42e3d83.

📒 Files selected for processing (1)
  • apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (6)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionEntry (176-176)
  • Transaction (206-206)
packages/stack-shared/src/schema-fields.ts (1)
  • productSchema (569-592)
apps/backend/src/lib/payments.tsx (1)
  • productToInlineProduct (427-443)
packages/stack-shared/src/utils/currency-constants.tsx (2)
  • Currency (3-7)
  • SUPPORTED_CURRENCIES (9-45)
packages/stack-shared/src/utils/strings.tsx (1)
  • typedToLowercase (15-18)
apps/backend/src/lib/tenancies.tsx (1)
  • Tenancy (47-47)
⏰ 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). (5)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: all-good
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Security Check
🔇 Additional comments (6)
apps/backend/src/app/api/latest/internal/payments/transactions/transaction-builder.ts (6)

1-8: LGTM!

Imports are well-organized and appropriate for the transaction builder functionality.


10-28: LGTM!

Type definitions provide appropriate flexibility for handling various product and price configurations.


54-63: LGTM!

The function correctly handles edge cases and null guards. The as any cast on line 61 is acceptable for field stripping in this context.


65-122: LGTM!

The money multiplication logic correctly handles decimal arithmetic using BigInt for precision, and properly manages signs and currency decimals. The charged amount builder appropriately iterates through supported currencies.


147-170: LGTM!

The product grant entry structure is correct and includes all necessary fields for tracking product grants in transactions.


262-290: LGTM!

The item quantity change transaction builder is straightforward and correctly constructs a transaction with a single item_quantity_change entry.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
packages/stack-shared/src/interface/admin-interface.ts (1)

598-611: Method signature correctly updated to new Transaction model.

The method signature, query construction, and return type are all correctly updated to use Transaction and TransactionType. The implementation properly handles optional parameters and builds the query string as needed.

Consider extracting customerType to a type definition similar to TransactionType for consistency:

In packages/stack-shared/src/interface/crud/transactions.ts, add:

export const CUSTOMER_TYPES = ['user', 'team', 'custom'] as const;
export type CustomerType = (typeof CUSTOMER_TYPES)[number];

Then update this method signature:

-async listTransactions(params?: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' }): Promise<{ transactions: Transaction[], nextCursor: string | null }>
+async listTransactions(params?: { cursor?: string, limit?: number, type?: TransactionType, customerType?: CustomerType }): Promise<{ transactions: Transaction[], nextCursor: string | null }>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd9d850 and 6fce497.

📒 Files selected for processing (3)
  • packages/stack-shared/src/interface/admin-interface.ts (3 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (3 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/stack-shared/src/interface/admin-interface.ts (1)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (111-111)
  • Transaction (128-128)
packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (2)
packages/template/src/lib/stack-app/apps/implementations/common.ts (1)
  • createCache (29-34)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (111-111)
  • Transaction (128-128)
⏰ 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). (11)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: docker
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: all-good
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
🔇 Additional comments (4)
packages/stack-shared/src/interface/admin-interface.ts (1)

11-11: LGTM! Import updated to use new Transaction model.

The import correctly switches from AdminTransaction to Transaction and TransactionType, aligning with the PR's refactor to a typed transaction schema.

packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (3)

7-7: LGTM! Import correctly references new Transaction types.

The import properly brings in Transaction and TransactionType from the shared package, aligning with the refactor to a unified transaction model.


77-79: Cache key correctly updated with new TransactionType.

The cache tuple properly includes TransactionType | undefined and maintains parameter order alignment with the listTransactions method signature, ensuring correct cache behavior for different query combinations.


594-604: LGTM! Transaction methods consistently updated.

Both listTransactions and useTransactions are correctly updated to use the new Transaction and TransactionType types. Cache access patterns properly align with the cache definition, and return types are consistent across both the async method and React hook.

@BilalG1 BilalG1 requested a review from N2D4 November 7, 2025 17:54
@BilalG1 BilalG1 assigned N2D4 and unassigned BilalG1 Nov 7, 2025
Copy link
Contributor

Choose a reason for hiding this comment

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

needs more tests for all the new behavior

Copy link
Contributor

@N2D4 N2D4 left a comment

Choose a reason for hiding this comment

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

code looks good besides the missing tests! can you make a video with all the different types of transactions and edge cases in the UI?

@github-actions github-actions bot assigned BilalG1 and unassigned N2D4 Nov 11, 2025
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
apps/dashboard/src/components/data-table/transaction-table.tsx (2)

192-356: Restore functional type filtering
The source_type column still returns SourceType values while the toolbar hands it TransactionType values and the API filter expects TransactionType. As soon as you pick a type, the table accessor never matches, so the UI shows an empty grid even though the backend returns data. We need this column (and all related wiring) to operate directly on transaction.type so the table, toolbar, and API stay in sync.

@@
-    {
-      id: 'source_type',
-      accessorFn: (transaction) => summaryById.get(transaction.id)?.sourceType ?? 'other',
+    {
+      id: 'type',
+      accessorFn: (transaction) => transaction.type,
       header: ({ column }) => <DataTableColumnHeader column={column} columnTitle="Type" />,
       cell: ({ row }) => {
         const summary = summaryById.get(row.original.id);
@@
-    const newFilters: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' } = {
+    const newFilters: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' } = {
       cursor: options.cursor,
       limit: options.limit,
-      type: options.columnFilters.find(f => f.id === 'source_type')?.value as any,
+      type: options.columnFilters.find(f => f.id === 'type')?.value as any,
       customerType: options.columnFilters.find(f => f.id === 'customer')?.value as any,
     };
@@
       defaultVisibility={{
-        source_type: true,
+        type: true,
         customer: true,
         amount: true,
         detail: true,
         created_at_millis: true,
       }}
       defaultColumnFilters={[
-        { id: 'source_type', value: undefined },
+        { id: 'type', value: undefined },
         { id: 'customer', value: undefined },
       ]}
@@
-      toolbarRender={(table) => {
-        const selectedType = table.getColumn('source_type')?.getFilterValue() as TransactionType | undefined;
+      toolbarRender={(table) => {
+        const typeColumn = table.getColumn('type');
+        const selectedType = typeColumn?.getFilterValue() as TransactionType | undefined;
@@
-            <Select
-              value={selectedType ?? ''}
-              onValueChange={(v) => table.getColumn('source_type')?.setFilterValue(v === '__clear' ? undefined : v)}
+            <Select
+              value={selectedType ?? ''}
+              onValueChange={(v) => typeColumn?.setFilterValue(v === '__clear' ? undefined : v)}
             >

131-139: Show real amounts for every currency
pickChargedAmountDisplay still hardcodes USD, so non-USD tenants see "Non USD amount" and USD entries with undefined amounts render as "$undefined". Please surface whichever currency actually has a value and fall back to '—' only when none do.

 function pickChargedAmountDisplay(entry: MoneyTransferEntry | undefined): string {
   if (!entry) return '—';
   const chargedAmount = entry.charged_amount as Record<string, string | undefined>;
-  if ("USD" in chargedAmount) {
-    return `$${chargedAmount.USD}`;
-  }
-  // TODO: Handle other currencies
-  return 'Non USD amount';
+  const [currency, amount] =
+    Object.entries(chargedAmount).find(([, value]) => typeof value === 'string' && value.length > 0) ?? [];
+  if (!currency || !amount) {
+    return '—';
+  }
+  return currency === 'USD' ? `$${amount}` : `${currency} ${amount}`;
 }
🧹 Nitpick comments (3)
apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts (3)

5-8: Consider stronger typing for payment configuration.

Using Record<string, any> for extraProducts and extraItems loses type safety and could hide configuration errors.

Consider defining explicit types that match the product and item schemas used in the actual payment configuration, or at minimum use Record<string, unknown> to force type narrowing at usage sites.


13-37: Consider extracting base payment configurations to module-level constants.

The baseProducts and baseItems are defined inline, which could lead to duplication if these configurations are needed in other test files or helper functions.

Extract these to module-level constants at the top of the file:

+const BASE_PRODUCTS = {
+  "sub-product": {
+    displayName: "Sub Product",
+    customerType: "user",
+    serverOnly: false,
+    stackable: false,
+    prices: {
+      monthly: { USD: "1000", interval: [1, "month"] },
+    },
+    includedItems: {},
+  },
+  "otp-product": {
+    displayName: "One-Time Product",
+    customerType: "user",
+    serverOnly: false,
+    stackable: false,
+    prices: {
+      single: { USD: "5000" },
+    },
+    includedItems: {},
+  },
+};
+
+const BASE_ITEMS = {
+  credits: { displayName: "Credits", customerType: "user" },
+};
+
 async function setupProjectWithPaymentsConfig(options: PaymentsConfigOptions = {}) {
   await Project.createAndSwitch();
   await PaymentsHelper.setup();
-  const baseProducts = {
-    "sub-product": { ... },
-    "otp-product": { ... },
-  };
-  const baseItems = {
-    credits: { displayName: "Credits", customerType: "user" },
-  };
   await Project.updateConfig({
     payments: {
       testMode: true,
       products: {
-        ...baseProducts,
+        ...BASE_PRODUCTS,
         ...(options.extraProducts ?? {}),
       },
       items: {
-        ...baseItems,
+        ...BASE_ITEMS,
         ...(options.extraItems ?? {}),
       },
     },
   });
 }

332-395: LGTM with optional readability improvement.

Excellent test coverage for customer_type filtering across multiple sources (purchases and item changes).

The nested every() assertions on lines 384-386 and 394 could be more readable:

- expect(teamResponse.body.transactions.every((tx: any) =>
-   tx.entries.every((entry: any) => entry.customer_type === "team")
- )).toBe(true);
+ const allTeamEntries = teamResponse.body.transactions
+   .flatMap((tx: any) => tx.entries)
+   .every((entry: any) => entry.customer_type === "team");
+ expect(allTeamEntries).toBe(true);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 420a508 and 740b941.

📒 Files selected for processing (2)
  • apps/dashboard/src/components/data-table/transaction-table.tsx (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/dashboard/src/components/data-table/transaction-table.tsx (3)
packages/stack-shared/src/interface/crud/transactions.ts (4)
  • TransactionEntry (98-98)
  • Transaction (128-128)
  • TransactionType (111-111)
  • TRANSACTION_TYPES (100-109)
packages/stack-ui/src/components/data-table/cells.tsx (2)
  • AvatarCell (45-52)
  • TextCell (7-43)
packages/stack-ui/src/components/data-table/data-table.tsx (1)
  • DataTableManualPagination (174-238)
apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts (2)
apps/e2e/tests/backend/backend-helpers.ts (1)
  • niceBackendFetch (109-173)
apps/e2e/tests/helpers.ts (1)
  • it (12-12)
⏰ 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). (11)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: restart-dev-and-test
  • GitHub Check: build (22.x)
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: docker
  • GitHub Check: setup-tests
  • GitHub Check: build (22.x)
🔇 Additional comments (7)
apps/e2e/tests/backend/endpoints/api/v1/internal/transactions.test.ts (7)

53-76: LGTM!

The refactoring to support multiple customer types (user/team/custom) is clean and maintains backward compatibility through the wrapper function.


113-156: LGTM!

The snapshot correctly reflects the new transaction model with the entries-based structure, including all expected fields like adjusted_by, effective_at_millis, and nested product metadata.


175-210: LGTM!

The one-time purchase snapshot correctly uses one_time_purchase_id instead of subscription_id while maintaining the same entry-based structure.


229-251: LGTM!

The item quantity change snapshot correctly uses the item_quantity_change entry type with appropriate fields and the manual-item-quantity-change transaction type.


297-330: LGTM!

Good test coverage for the new transaction type filtering feature, verifying that each filter correctly returns only matching transactions.


397-473: LGTM!

Good test coverage for server-granted subscriptions. The snapshot correctly shows price_id: null since these grants bypass the payment flow.


1-1: Test coverage has improved but consider additional scenarios.

The new tests added (filtering by type, filtering by customer_type, and server-granted subscriptions) address some of the previous feedback. However, consider adding tests for:

  • Multiple entries within a single transaction
  • The adjusted_by field being populated (when one transaction adjusts another)
  • Error cases with invalid filter parameters
  • Pagination combined with filtering
  • Edge cases like empty entries or null fields

Based on learnings (previous review comment by N2D4).

@BilalG1 BilalG1 requested a review from N2D4 November 11, 2025 22:26
Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 740b941 and 4693a82.

📒 Files selected for processing (2)
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (3 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (2)
packages/template/src/lib/stack-app/apps/implementations/common.ts (1)
  • createCache (29-34)
packages/stack-shared/src/interface/crud/transactions.ts (2)
  • TransactionType (111-111)
  • Transaction (128-128)
⏰ 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). (11)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: build (22.x)
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: lint_and_build (latest)

Comment on lines +602 to 611
async listTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' }): Promise<{ transactions: Transaction[], nextCursor: string | null }> {
const crud = Result.orThrow(await this._transactionsCache.getOrWait([params.cursor, params.limit, params.type, params.customerType] as const, "write-only"));
return crud;
}

// IF_PLATFORM react-like
useTransactions(params: { cursor?: string, limit?: number, type?: 'subscription' | 'one_time' | 'item_quantity_change', customerType?: 'user' | 'team' | 'custom' }): { transactions: AdminTransaction[], nextCursor: string | null } {
useTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' }): { transactions: Transaction[], nextCursor: string | null } {
const data = useAsyncCache(this._transactionsCache, [params.cursor, params.limit, params.type, params.customerType] as const, "adminApp.useTransactions()");
return data;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Restore safe defaults for transaction params

Both listTransactions and useTransactions now assume params is always provided. Calling either without an argument (the previous API behaviour) will dereference params when it’s undefined, raising a runtime TypeError before any type checks can help. Please keep the signature ergonomic by defaulting to an empty object and destructuring.

-  async listTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' }): Promise<{ transactions: Transaction[], nextCursor: string | null }> {
-    const crud = Result.orThrow(await this._transactionsCache.getOrWait([params.cursor, params.limit, params.type, params.customerType] as const, "write-only"));
+  async listTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' } = {}): Promise<{ transactions: Transaction[], nextCursor: string | null }> {
+    const { cursor, limit, type, customerType } = params;
+    const crud = Result.orThrow(await this._transactionsCache.getOrWait([cursor, limit, type, customerType] as const, "write-only"));
     return crud;
   }

   // IF_PLATFORM react-like
-  useTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' }): { transactions: Transaction[], nextCursor: string | null } {
-    const data = useAsyncCache(this._transactionsCache, [params.cursor, params.limit, params.type, params.customerType] as const, "adminApp.useTransactions()");
+  useTransactions(params: { cursor?: string, limit?: number, type?: TransactionType, customerType?: 'user' | 'team' | 'custom' } = {}): { transactions: Transaction[], nextCursor: string | null } {
+    const { cursor, limit, type, customerType } = params;
+    const data = useAsyncCache(this._transactionsCache, [cursor, limit, type, customerType] as const, "adminApp.useTransactions()");
     return data;
   }
🤖 Prompt for AI Agents
In packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
around lines 602 to 611, both listTransactions and useTransactions assume params
is always passed and will throw if called with undefined; change the signatures
to default params = {} and destructure the four properties (cursor, limit, type,
customerType) from that object (with no-arg defaulting) and then pass those
variables into the cache/get calls instead of indexing params directly so the
methods are safe to call with no arguments.

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