Skip to content

feat(web): add org credit and invoice page procedures - #5462

Merged
iscekic merged 4 commits into
mainfrom
audit-w7b-data-contracts-dffd-s2
Aug 26, 2026
Merged

feat(web): add org credit and invoice page procedures#5462
iscekic merged 4 commits into
mainfrom
audit-w7b-data-contracts-dffd-s2

Conversation

@iscekic

@iscekic iscekic commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

No new behavior. The two new paginated endpoints are not consumed by any page yet, so a user sees the same organization credit transaction and invoice views as before.


Reviewer Notes

The organization credit transaction query gains a cursor-paginated form, the CreditTransactionsPage contract. getCreditTransactionsForOrganizationPage returns 25 entries plus a probe ordered newest first, with a nextCursor, a hasMore flag, and a CreditSummary computed by the new getCreditTransactionsSummaryForOrganization; both helpers exclude kpo:consumption: categories exactly like the old query. The old getCreditTransactionsForOrganization array form stays unchanged and is marked old form, so existing callers keep working until every client migrates to the page form.

Files
  • apps/web/src/lib/creditTransactions.ts — exports the CreditSummary type; adds getCreditTransactionsSummaryForOrganization and getCreditTransactionsForOrganizationPage; marks the old getCreditTransactionsForOrganization with an old form comment.

The Stripe invoice listing gains a cursor-paginated form, the StripeInvoicesPage contract. getStripeInvoicesPage lists 25 invoices with an optional starting_after cursor, reads has_more, and returns a nextCursor equal to the last invoice id. The invoice-to-unified mapping is extracted into mapStripeInvoicesToUnified and reused by both functions; the old getStripeInvoices keeps returning a flat array of up to 100 and is marked old form.

Files
  • apps/web/src/lib/stripe/index.ts — adds the StripeInvoicesPage type, the mapStripeInvoicesToUnified helper, and getStripeInvoicesPage; marks getStripeInvoices with an old form comment.

Two new tRPC procedures expose the paginated queries. organizations.creditTransactionsPage serves the member role with a defaulted non-negative numeric cursor, and organizations.invoicesPage serves the billing role with an optional string cursor, resolving or creating the Stripe customer id first just like the old invoices procedure. The existing creditTransactions and invoices procedures keep their array returns, so no client breaks.

Files
  • apps/web/src/routers/organizations/organization-router.ts — adds the OrganizationTransactionsPageInputSchema and OrganizationInvoicesPageInputSchema schemas plus the creditTransactionsPage and invoicesPage procedures beside their array-returning predecessors.

Tests: 2 test files changed — creditTransactions.page.test.ts (new) and stripe/index.test.ts (extended); both DB-backed tests need the test Postgres and run in CI.
Generated: none.


Verification

  • Manual tests not run on this host: the DB-backed tests require the test Postgres (Docker) and run in CI.
  • E2E report: none attached. E2E runs once on the tip PR, not per stack level.

Human steps: none. No new environment values, secrets, or migrations.

Visual Changes

Visual Changes: N/A


Stacked PRs — merge bottom to top. Each level shows only its own diff.

Full verification (E2E, user advocacy, simplify, bot review) runs on the tip PR over every level.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.

  1. audit-w7b-data-contracts-dffdrefactor(mobile): parse raw HTTP and infer review contracts #5460
  2. audit-w7b-data-contracts-dffd-s2feat(web): add org credit and invoice page procedures #5462 ← this PR
  3. audit-w7b-data-contracts-dffd-s3feat(mobile): owner-keyed credits, ledger paging, list freshness #5468
  4. audit-w7b-data-contracts-dffd-s4refactor: route-scoped registry and live custom mode #5472
  5. audit-w7b-data-contracts-dffd-s5feat(mobile): provider-aware new-session and layout extract #5479 (tip)

@kilo-code-bot

kilo-code-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Full review of the unused org credit-transaction and Stripe invoice page procedures, including the keyset ledger cursor and Stripe has_more fix; no high-confidence correctness, security, or runtime issues.

Files Reviewed (5 files)
  • apps/web/src/lib/creditTransactions.ts
  • apps/web/src/lib/creditTransactions.page.test.ts
  • apps/web/src/lib/stripe/index.ts
  • apps/web/src/lib/stripe/index.test.ts
  • apps/web/src/routers/organizations/organization-router.ts
Previous Review Summaries (3 snapshots, latest commit d27fe8b)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit d27fe8b)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the keyset ledger cursor and Stripe has_more cursor fix; no high-confidence correctness, security, or runtime issues.

Files Reviewed (5 files)
  • apps/web/src/lib/creditTransactions.ts
  • apps/web/src/lib/creditTransactions.page.test.ts
  • apps/web/src/lib/stripe/index.ts
  • apps/web/src/lib/stripe/index.test.ts
  • apps/web/src/routers/organizations/organization-router.ts

Previous review (commit 41a8a81)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the Stripe invoice mapping reuse and test spy isolation; no high-confidence correctness, security, or runtime issues.

Files Reviewed (2 files)
  • apps/web/src/lib/stripe/index.ts
  • apps/web/src/lib/stripe/index.test.ts

Previous review (commit 68211dc)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the unused org credit-transaction and Stripe invoice page procedures, matching helpers, and tests; no high-confidence correctness, security, or runtime issues.

Files Reviewed (5 files)
  • apps/web/src/lib/creditTransactions.ts
  • apps/web/src/lib/creditTransactions.page.test.ts
  • apps/web/src/lib/stripe/index.ts
  • apps/web/src/lib/stripe/index.test.ts
  • apps/web/src/routers/organizations/organization-router.ts

Reviewed by grok-4.6 · Input: 136.7K · Output: 11.5K · Cached: 534.7K

Review guidance: REVIEW.md from base branch main

Comment thread apps/web/src/lib/creditTransactions.ts Outdated
Comment on lines +179 to +181
.orderBy(desc(credit_transactions.created_at), desc(credit_transactions.id))
.limit(CREDIT_TRANSACTIONS_PAGE_SIZE + 1)
.offset(cursor),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

bot: The advertised cursor is an OFFSET, so ledger pages are not stable when credit transactions change between requests.

Suggested fix: Encode the last returned (created_at, id) as the cursor and query for rows strictly after that boundary in the descending order (with the same filters), rather than using .offset(cursor). This keeps later pages disjoint when new transactions arrive or earlier rows are removed. Add a test that fetches page 1, changes the ordered result set, then verifies page 2 does not duplicate or omit the original continuation.

Comment thread apps/web/src/lib/stripe/index.ts Outdated
Comment on lines +742 to +745
return {
entries,
hasMore: invoices.has_more,
nextCursor: lastInvoice ? lastInvoice.id : null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

bot: A non-empty final Stripe page returns a continuation cursor even when Stripe says there are no more invoices.

Suggested fix: Tie the cursor to Stripe's continuation signal, e.g. nextCursor: invoices.has_more ? lastInvoice?.id ?? null : null, and add a test with non-empty data plus has_more: false that expects nextCursor to be null.

@iscekic iscekic closed this Aug 26, 2026
@iscekic iscekic reopened this Aug 26, 2026
@iscekic iscekic closed this Aug 26, 2026
@iscekic iscekic reopened this Aug 26, 2026
@iscekic iscekic closed this Aug 26, 2026
@iscekic iscekic reopened this Aug 26, 2026
Base automatically changed from audit-w7b-data-contracts-dffd to main August 26, 2026 16:49
Page the organization credit ledger by keyset ((created_at, id) of the last
row) instead of by OFFSET. The ledger grows at the head, so a transaction
inserted between two requests shifted every later page and page 2 repeated
a row page 1 already showed.

Return a Stripe invoice cursor only when Stripe reports has_more, so a full
final page no longer advertises a next page that is always empty.
@iscekic
iscekic force-pushed the audit-w7b-data-contracts-dffd-s2 branch from d27fe8b to 69835e4 Compare August 26, 2026 16:49
@iscekic
iscekic merged commit 501d66d into main Aug 26, 2026
19 checks passed
@iscekic
iscekic deleted the audit-w7b-data-contracts-dffd-s2 branch August 26, 2026 17:15
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