Skip to content

Faster payments page#1124

Open
Fabcien wants to merge 5 commits intoPayButton:masterfrom
Fabcien:faster_payments_page
Open

Faster payments page#1124
Fabcien wants to merge 5 commits intoPayButton:masterfrom
Fabcien:faster_payments_page

Conversation

@Fabcien
Copy link
Collaborator

@Fabcien Fabcien commented Mar 4, 2026

Improve the payments page loading speed by removing the bottlenecks:

  • Don't filter amount > 0 when it's not necessary
  • Use a new isPayment flag (indexed) when necessary
  • Some more minor improvements

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional includeInputs parameter to transaction and payment APIs for retrieving detailed transaction input data.
  • Performance

    • Optimized payments page data loading through parallel request execution, reducing overall load time.

Fabcien added 5 commits March 4, 2026 17:19
This avoids loading the tx inputs where they are unlikely needed. Can still be requested by passing`includeInputs=true` to the query.

The following api endpoints are affected:
 - /api/payments
 - /api/paybutton/transactions/[id]

None of these needs the inputs by default.
This just add overhead, especially when called in loops.
This is called from the very niche endpoint /api/transaction/years.

The amount > 0 was intended to only check for payments, but in practice this doesn't matter. We can just return the years of acticity for this userId and show no payments for the years it was not used on paybutton. This dramatically speeds up the query (from ~9s to ~100ms on my machine).
This makes the payment requests much faster.
This speeds up loading of the payments page for some filters.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

This PR extends the transaction and payment handling pipeline by introducing an isPayment boolean field to distinguish payments, adding optional transaction input inclusion control, refactoring payment generation to synchronous operations, and parallelizing frontend data fetching for improved performance.

Changes

Cohort / File(s) Summary
API Endpoint Updates
pages/api/paybutton/transactions/[id].ts, pages/api/payments/index.ts
Added includeInputs query parameter support to conditionally include transaction inputs in API responses; updated service function call signatures accordingly.
Database Schema & Migration
prisma-local/schema.prisma, prisma-local/migrations/20260228000000_add_is_payment_flag/migration.sql
Added isPayment boolean field (default false) to Transaction model and created composite index on (addressId, isPayment) for query optimization.
Service Layer Updates
services/transactionService.ts, services/chronikService.ts
Extended transaction fetch functions with includeInputs parameter, computed isPayment field (amount > 0), replaced amount-based filtering with isPayment flag throughout payment queries, and updated function signatures for fetchTransactionsByAddressListWithPagination, fetchTransactionsByPaybuttonIdWithPagination, and fetchAllPaymentsByUserIdWithPagination.
Payment Cache Refactoring
redis/paymentCache.ts
Converted generatePaymentFromTx and generatePaymentFromTxWithInvoices from asynchronous to synchronous functions; removed await calls at invocation sites.
Frontend Data Fetching
pages/payments/index.tsx
Parallelized payments API requests and JSON parsing using Promise.all to reduce latency while preserving error handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement (behind the scenes)

Suggested reviewers

  • chedieck
  • Klakurka
  • lissavxo

Poem

🐰 A payment flag was born with care,
Inputs toggled here and there,
Parallel fetches swift and true,
Async to sync—refactored through!
The database dances, indexed bright,
Our transactions now get it right! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a clear summary of improvements made (avoiding unnecessary filters, using indexed isPayment flag, minor optimizations) but lacks required template sections like related issue number, test plan, and detailed technical context. Add the related issue number (#), a test plan describing how the performance improvements were validated, and any relevant remarks about the changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main objective of the PR, which is to improve payments page loading speed through performance optimizations.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pages/payments/index.tsx (1)

238-244: ⚠️ Potential issue | 🟡 Minor

Debug logging may fail due to stream consumption order.

When paymentsResponse.ok is false, calling both paymentsResponse.body (line 241) and paymentsResponse.json() (line 242) can cause issues since body is a ReadableStream that can only be consumed once. The .json() call may fail or return incomplete data.

Consider simplifying the error logging:

🔧 Suggested fix
       if (!paymentsResponse.ok || !paymentsCountResponse.ok) {
-        console.log('paymentsResponse status', paymentsResponse.status)
-        console.log('paymentsResponse status text', paymentsResponse.statusText)
-        console.log('paymentsResponse body', paymentsResponse.body)
-        console.log('paymentsResponse json', await paymentsResponse.json())
+        console.log('paymentsResponse failed:', paymentsResponse.status, paymentsResponse.statusText)
+        console.log('paymentsCountResponse failed:', paymentsCountResponse.status, paymentsCountResponse.statusText)
         throw new Error('Failed to fetch payments or count')
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/payments/index.tsx` around lines 238 - 244, The debug logging reads
paymentsResponse.body and then paymentsResponse.json(), which can consume the
response stream twice and fail; update the error logging in the failure branch
(where paymentsResponse and paymentsCountResponse are checked) to avoid
double-consuming the stream—either remove the paymentsResponse.body access and
only await paymentsResponse.json(), or call paymentsResponse.clone().json() for
logging (or use text() once) so the original response stream isn't consumed
twice; apply the same approach if you need to inspect paymentsCountResponse.
services/transactionService.ts (1)

576-585: ⚠️ Potential issue | 🟡 Minor

Use Number(tx.amount) > 0 for consistency with amount comparisons elsewhere.

Line 582 compares tx.amount > 0 directly, but line 1098 in the same file explicitly converts the amount to a number before comparing: Number(tx.amount) > 0. Since tx.amount is a Prisma.Decimal, follow the established pattern in this codebase and use the explicit conversion for clarity and consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/transactionService.ts` around lines 576 - 585, The isPayment
calculation in the flatTxData mapping uses tx.amount > 0; update it to use
Number(tx.amount) > 0 to match the established pattern and handle Prisma.Decimal
consistently—locate the flatTxData const and change the isPayment expression
from tx.amount > 0 to Number(tx.amount) > 0 (transactionsData and tx.amount are
the referenced symbols).
🧹 Nitpick comments (1)
prisma-local/migrations/20260228000000_add_is_payment_flag/migration.sql (1)

1-8: Migration is correct; consider operational impact for large tables.

The backfill logic (amount > 0) correctly matches the application code in createManyTransactions (line 582 of transactionService.ts) and chronikService.ts (line 301).

For production deployment on large Transaction tables, be aware that the UPDATE and CREATE INDEX statements may lock the table or cause significant I/O. Consider running during low-traffic periods or using online DDL strategies if supported by your MySQL version.

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@prisma-local/migrations/20260228000000_add_is_payment_flag/migration.sql`
around lines 1 - 8, The migration's UPDATE and CREATE INDEX can cause locks/IO
on large Transaction tables; modify migration.sql to perform the backfill in
safe steps (batch the UPDATE to set isPayment where amount>0 in bounded chunks
until complete) and create the index using an online DDL option if supported
(e.g., ALTER/CREATE INDEX with ALGORITHM=INPLACE, LOCK=NONE) or document that it
must be run during a low-traffic maintenance window; note that this change
corresponds to the new isPayment column and backfill in migration.sql and is
logically tied to the application logic in transactionService.ts
(createManyTransactions) and chronikService.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pages/payments/index.tsx`:
- Around line 238-244: The debug logging reads paymentsResponse.body and then
paymentsResponse.json(), which can consume the response stream twice and fail;
update the error logging in the failure branch (where paymentsResponse and
paymentsCountResponse are checked) to avoid double-consuming the stream—either
remove the paymentsResponse.body access and only await paymentsResponse.json(),
or call paymentsResponse.clone().json() for logging (or use text() once) so the
original response stream isn't consumed twice; apply the same approach if you
need to inspect paymentsCountResponse.

In `@services/transactionService.ts`:
- Around line 576-585: The isPayment calculation in the flatTxData mapping uses
tx.amount > 0; update it to use Number(tx.amount) > 0 to match the established
pattern and handle Prisma.Decimal consistently—locate the flatTxData const and
change the isPayment expression from tx.amount > 0 to Number(tx.amount) > 0
(transactionsData and tx.amount are the referenced symbols).

---

Nitpick comments:
In `@prisma-local/migrations/20260228000000_add_is_payment_flag/migration.sql`:
- Around line 1-8: The migration's UPDATE and CREATE INDEX can cause locks/IO on
large Transaction tables; modify migration.sql to perform the backfill in safe
steps (batch the UPDATE to set isPayment where amount>0 in bounded chunks until
complete) and create the index using an online DDL option if supported (e.g.,
ALTER/CREATE INDEX with ALGORITHM=INPLACE, LOCK=NONE) or document that it must
be run during a low-traffic maintenance window; note that this change
corresponds to the new isPayment column and backfill in migration.sql and is
logically tied to the application logic in transactionService.ts
(createManyTransactions) and chronikService.ts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3019f77f-9fec-447f-8e8b-4a22d8acd0e0

📥 Commits

Reviewing files that changed from the base of the PR and between f44fa99 and 5ea55f4.

📒 Files selected for processing (8)
  • pages/api/paybutton/transactions/[id].ts
  • pages/api/payments/index.ts
  • pages/payments/index.tsx
  • prisma-local/migrations/20260228000000_add_is_payment_flag/migration.sql
  • prisma-local/schema.prisma
  • redis/paymentCache.ts
  • services/chronikService.ts
  • services/transactionService.ts

@Klakurka Klakurka added the enhancement (behind the scenes) Stuff that users won't see label Mar 4, 2026
@Klakurka Klakurka added this to the Phase 3 milestone Mar 4, 2026
@Klakurka Klakurka self-requested a review March 4, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement (behind the scenes) Stuff that users won't see

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants