🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

fix(deleter): clean up all billing and kyc records during org delete - #1838

Merged
whoAbhishekSah merged 2 commits into
fix/subscription-teardown-retryfrom
fix/org-delete-cleanup
Aug 5, 2026
Merged

fix(deleter): clean up all billing and kyc records during org delete#1838
whoAbhishekSah merged 2 commits into
fix/subscription-teardown-retryfrom
fix/org-delete-cleanup

Conversation

@whoAbhishekSah

@whoAbhishekSah whoAbhishekSah commented Aug 4, 2026

Copy link
Copy Markdown
Member

Fixes #1835. Top layer of the cleanup stack — uses the delete methods added in #1841, #1842, #1843 and relies on the retryable teardown from #1844.

Problem

Organization delete could fail halfway and leave the org in a broken state: no owners, and a billing account pointing to a Stripe customer that was already deleted. Checkout and kyc rows were never removed, so their foreign keys made the hard delete of billing_customers and organizations fail after the Stripe customer was gone. Retrying hit the same error forever.

Changes

  • The deleter now removes checkout rows and credit transactions before the billing customer row, and the org_kyc row before the org row.
  • Reordered the teardown: billing first, org policies near the end. A failure at any step now leaves the org owned and the delete retryable.
  • Always remove local subscription and invoice rows, including for offline billing accounts.

Testing

  • Rewrote core/deleter/service_test.go to cover the new deletion order and the checkout, credit, and kyc steps.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview Aug 5, 2026 2:52am

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2dae08f8-6b2e-41cc-a6a2-d041005ff927

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
📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Organization deletion now removes associated billing accounts, invitations, KYC records, policies, and roles in the appropriate order.
    • Customer deletion now removes subscriptions, invoices, checkout records, and credit transactions.
  • Bug Fixes
    • Improved subscription cancellation handling when providers have already canceled or removed a subscription.
    • Offline customers no longer trigger unnecessary provider cancellation requests.
    • Deletion workflows now handle missing provider records more gracefully.

Walkthrough

The PR adds deletion methods for checkout records, credit transactions, and KYC records. It integrates these deletions into the cascade deleter, reorders organization and customer cleanup to remove billing data first, and improves subscription cancellation to handle offline customers and provider-side state synchronization.

Changes

Billing and KYC deletion

Layer / File(s) Summary
Deletion contracts and persistence
billing/checkout/service.go, billing/credit/service.go, core/kyc/service.go, internal/store/postgres/billing_checkout_repository.go, internal/store/postgres/billing_transactions_repository.go, internal/store/postgres/kyc_repository.go
Services add DeleteByCustomer, DeleteByAccountID, and DeleteKyc methods. PostgreSQL repositories implement corresponding delete queries with error mapping.
Subscription cancellation and customer teardown
billing/subscription/service.go
Cancel synchronizes local state when the provider subscription is already canceled and returns without issuing another cancellation request. DeleteByCustomer skips provider cancellation for offline customers and tolerates ErrSubscriptionOnProviderNotFound during active subscription cancellation.
Cascade deletion orchestration
core/deleter/service.go, cmd/serve.go
The cascade deleter receives checkout, credit, and KYC service dependencies. Organization deletion invokes billing-account cleanup before deleting projects and roles. Customer deletion removes subscription, invoice, checkout, and credit records before deleting the customer row.
Mock wiring and cascade coverage
core/deleter/mocks/checkout_service.go, core/deleter/mocks/credit_service.go, core/deleter/mocks/kyc_service.go, billing/credit/mocks/transaction_repository.go, core/kyc/mocks/repository.go, core/deleter/service_test.go
Generated mocks support deletion method expectations and invocation tracking. Tests cover billing teardown, KYC cleanup, offline customer handling, checkout deletion failures, and existing cascade paths.

Estimated code review effort: 4 (Complex) | ~50 minutes

Possibly related PRs

  • raystack/frontier#1615: Both PRs modify cascade-deletion orchestration and expand NewCascadeDeleter dependencies.

Suggested reviewers: amangit07

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the linked issue requirements for billing, checkout, KYC, subscription, invoice, transaction, ordering, retry safety, and hard deletion.
Out of Scope Changes check ✅ Passed All changes support the organization deletion fix, including service wiring, repository methods, generated mocks, and focused test updates.

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
billing/subscription/service.go (1)

1100-1107: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Cancel non-active provider-backed subscriptions before local delete.

IsActive() allows only active and trialing, but StatePastDue is a known local/Stripe status. A past_due subscription can therefore skip Cancel() in DeleteByCustomer() and leave the Stripe subscription billable after the local row is deleted. Treat non-terminal non-active states the same way, or add a non-terminal check before deletion.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bc4f87c9-2cfb-4014-b174-8902b6d224d3

📥 Commits

Reviewing files that changed from the base of the PR and between ad5e9a5 and 6b61473.

📒 Files selected for processing (15)
  • billing/checkout/service.go
  • billing/credit/mocks/transaction_repository.go
  • billing/credit/service.go
  • billing/subscription/service.go
  • cmd/serve.go
  • core/deleter/mocks/checkout_service.go
  • core/deleter/mocks/credit_service.go
  • core/deleter/mocks/kyc_service.go
  • core/deleter/service.go
  • core/deleter/service_test.go
  • core/kyc/mocks/repository.go
  • core/kyc/service.go
  • internal/store/postgres/billing_checkout_repository.go
  • internal/store/postgres/billing_transactions_repository.go
  • internal/store/postgres/kyc_repository.go

Comment thread core/deleter/service_test.go
Comment thread core/deleter/service.go Outdated
Comment thread core/deleter/service.go Outdated

@rohilsurana rohilsurana left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Verified the new order against the schema FKs: subscriptions, invoices, checkouts, and transactions all go before the customer hard delete, and org_kyc goes before the owner policies. Every earlier step is idempotent on retry, so a failure at any point leaves the org owned and the delete can just run again. The test rewrite with strict mocks pins exactly that ordering, nice work. Two notes inline.

Comment thread core/deleter/service.go
Comment thread core/deleter/service.go
whoAbhishekSah and others added 2 commits August 5, 2026 08:21
…1835)

Organization delete could fail halfway and leave the org without owners
and with a billing account pointing to a deleted Stripe customer.
Checkout and kyc rows were never removed, so their foreign keys made
the hard delete of billing_customers and organizations fail after the
Stripe customer was already gone. Retrying hit the same error forever.

- delete checkout rows before the billing customer row
- delete the org_kyc row before the org row
- delete credit transactions instead of orphaning them
- always remove local subscription and invoice rows, also for offline
  billing accounts
- tear down billing first and org policies near the end, so a failure
  at any step leaves the org owned and the delete retryable

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A kyc delete failure after the policy loop left the org without owners.
Moving it earlier keeps the org owned when the kyc delete fails.
Also drop a redundant comment in DeleteCustomers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 30970587297

Coverage increased (+0.02%) to 47.5%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 9 uncovered changes across 2 files (31 of 40 lines covered, 77.5%).
  • 3 coverage regressions across 1 file.

Uncovered Changes

File Changed Covered %
core/deleter/service.go 38 31 81.58%
cmd/serve.go 2 0 0.0%

Coverage Regressions

3 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
core/deleter/service.go 3 75.14%

Coverage Stats

Coverage Status
Relevant Lines: 39335
Covered Lines: 18684
Line Coverage: 47.5%
Coverage Strength: 15.4 hits per line

💛 - Coveralls

@whoAbhishekSah
whoAbhishekSah merged commit 2930c71 into main Aug 5, 2026
8 checks passed
@whoAbhishekSah
whoAbhishekSah deleted the fix/org-delete-cleanup branch August 5, 2026 03:37
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.

Organization delete can fail halfway and leave the org in a broken state

3 participants