Skip to content

feat(store): billing account delete hides the account's token transactions with the row - #1999

Open
rohilsurana wants to merge 4 commits into
feat/billing-rows-soft-deletefrom
feat/billing-account-delete-hides-transactions
Open

rohilsurana wants to merge 4 commits into
feat/billing-rows-soft-deletefrom
feat/billing-account-delete-hides-transactions

Conversation

@rohilsurana

@rohilsurana rohilsurana commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Deleting a billing account now hides the account's token transactions. The delete also tells the caller how many tokens were forfeited.

An account that owes tokens cannot be deleted. The API answers with failed precondition.

When tokens are forfeited, an app.billing.tokens.forfeited audit record is written.

This PR is stacked on #1983.

Changes

  • The account delete in the repository hides the account's live token transactions and returns the forfeited amount and the purchased share.
  • The delete is rolled back if the hidden transactions add up to a debt.
  • The service refuses the delete when the balance is below zero. This check runs before the Stripe call.
  • The service also checks for live subscriptions, invoices and checkouts before the Stripe call, with a new HasLiveRecords repository method. A refused delete no longer leaves a deleted customer at Stripe.
  • The API maps the new ErrHasTokenDebt error to failed precondition.
  • The service writes the forfeited tokens audit record when the amount is above zero.
  • billing/credit and core/deleter are not changed.

Technical Details

  • One SQL statement hides the transactions and returns the totals. It only touches rows where account_id is the customer id, never the system account.
  • The purchased share is the net of rows with source system.buy, kept between zero and the forfeited amount.
  • The debt check happens twice. The service checks the balance before the Stripe call, so nothing is deleted at Stripe for an account that owes tokens. The repository checks again inside the transaction, so a race cannot hide a debt.
  • The audit record is written after the delete. It uses a context that is not cancelled, so a client disconnect cannot lose it.
  • The live records check also runs twice, for the same reason: once before the Stripe call and once inside the transaction, where the row is locked.
  • A gap remains. A credit that passed the account check just before the delete can still land on the hidden account. There is no lock on that insert.
  • A crash between the delete and the audit write loses the event. The hidden rows still carry the amounts.

Test Plan

  • go build ./...
  • go vet on the touched packages
  • go test ./internal/store/postgres/ ./billing/... ./core/deleter/... ./internal/api/v1beta1connect/
  • golangci-lint run on the touched packages, 0 issues
  • gofmt on the changed files
  • Each commit was written test first and the new tests were seen failing before the code

SQL Safety

  • Values go in through goqu.Record and goqu.Ex or bind parameters
  • Callers of ToSQL forward the params
  • No ? placeholders inside quoted literals in goqu.L
  • No new nolint annotations

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
frontier Ready Ready Preview Oct 16, 2026 10:22am UTC

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: raystack/frontier/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 28fc4a02-3341-4ba3-bbd9-e215a402f27c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@coveralls

coveralls commented Oct 14, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 38886680511

Coverage increased (+0.06%) to 55.526%

Details

  • Coverage increased (+0.06%) from the base build.
  • Patch coverage: 18 uncovered changes across 2 files (57 of 75 lines covered, 76.0%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
internal/store/postgres/billing_customer_repository.go 41 31 75.61%
billing/customer/service.go 32 24 75.0%
Total (3 files) 75 57 76.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 41822
Covered Lines: 23222
Line Coverage: 55.53%
Coverage Strength: 19.26 hits per line

💛 - Coveralls

@rohilsurana
rohilsurana force-pushed the feat/billing-account-delete-hides-transactions branch from 4f3a2c0 to 88f48ee Compare October 14, 2026 06:27
@rohilsurana
rohilsurana force-pushed the feat/billing-rows-soft-delete branch from be61aad to 49f5fe5 Compare October 14, 2026 09:03
@rohilsurana
rohilsurana force-pushed the feat/billing-account-delete-hides-transactions branch from 88f48ee to 55510df Compare October 14, 2026 09:04
@rohilsurana
rohilsurana marked this pull request as ready for review October 14, 2026 10:45
@rohilsurana
rohilsurana force-pushed the feat/billing-rows-soft-delete branch from 49f5fe5 to 170adbe Compare October 16, 2026 08:44
@rohilsurana
rohilsurana force-pushed the feat/billing-account-delete-hides-transactions branch from 55510df to 5a6a5bc Compare October 16, 2026 10:04
@rohilsurana
rohilsurana force-pushed the feat/billing-rows-soft-delete branch from 170adbe to c2b82b8 Compare October 16, 2026 10:04
@rohilsurana
rohilsurana force-pushed the feat/billing-rows-soft-delete branch from c2b82b8 to e625872 Compare October 16, 2026 10:20
@rohilsurana
rohilsurana force-pushed the feat/billing-account-delete-hides-transactions branch from 5a6a5bc to 0286c5f Compare October 16, 2026 10:21
}

func (s *Service) logTokensForfeited(ctx context.Context, customer Customer, forfeit ForfeitedTokens) {
if err := audit.NewLogger(ctx, customer.OrgID).LogWithAttrs(audit.BillingTokensForfeitedEvent, audit.Target{

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.

this is not audit records, can we add audit records or is this event audit log intended?

This branch was successfully deployed

1 active deployment
Preview — 0286c5f5 Deployed Oct 16, 2026 by vercel[bot]
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