feat(deleter): check all org delete blockers up front and return them together - #1857
feat(deleter): check all org delete blockers up front and return them together#1857whoAbhishekSah wants to merge 2 commits into
Conversation
…tionRequest Generated from raystack/proton@0b8bdb2 (91eaffc + the new field only, so the recent breaking proto changes on proton main stay out of this change). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… together Replace the blanket "any invoice ever" gate with a pre-flight check that runs before any deletion starts and collects every blocker: - active or trialing subscription: cancel it, then retry - open or uncollectible invoice: pay it, then retry; paid invoices stop blocking since the billing provider keeps its own copy - negative token balance: buy tokens to clear the debt, then retry - unused tokens: retry with acknowledge_token_forfeit set; the forfeited amount is written to an audit record during the delete Accounts without a billing provider only get the token checks, since their subscription and invoice rows have nothing the caller could cancel or pay. The handler returns the blockers as a failed_precondition error with one PreconditionFailure violation per blocker, so a caller sees the whole checklist in one response instead of one blocker per retry. Unexpected failures stay internal. Closes #1837 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 4 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (13)
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. Comment |
Closes #1837. Depends on raystack/proton#497 for the new request field.
What changed
Deleting an organization used to be gated by one rule: if the billing account ever had an invoice, the delete was refused — and the caller saw a bare
internal server error. That rule was too strict (a fully paid invoice blocked the org forever) and too loose at the same time (an active subscription didn't block anything; the delete silently cancelled it mid-flight, and token balances were never looked at).This PR replaces that gate with a pre-flight check that runs before any deletion starts, collects all blockers, and returns them together as a
failed_preconditionerror with one standardPreconditionFailureviolation per blocker:ACTIVE_SUBSCRIPTIONUNPAID_INVOICENEGATIVE_TOKEN_BALANCEUNUSED_TOKENSacknowledge_token_forfeitsetPaid, void, draft, and zero-amount invoices no longer block: the billing provider keeps its own permanent copy of every invoice, so deleting our rows loses nothing.
The token forfeit acknowledgment
Unused prepaid tokens have no clean-up action — the user already paid for them. What the server needs is informed consent, and a UI popup alone can't provide that because the API is public (SDKs, scripts, curl). So
DeleteOrganizationRequestgains abool acknowledge_token_forfeitfield (added in raystack/proton#497; this PR bumpsPROTON_COMMIT). Without the flag, a positive balance returns anUNUSED_TOKENSviolation naming the amount at stake. With it, the delete proceeds and the forfeited amount is written to a newapp.billing.tokens.forfeitedaudit record during the credit teardown. The flag cannot bypass a debt.Accounts without a billing provider (offline accounts) only get the token checks: their subscription and invoice rows have nothing behind them the caller could cancel or pay, and the teardown already skips the provider for them.
Error mapping
The handler maps
deleter.BlockedErrortofailed_preconditionand attaches the violations aserrdetails.PreconditionFailure. The error sanitizer interceptor passes non-internal codes through untouched, so both the message and the structured details reach the caller. Everything unexpected staysinternal, same as before.Example response:
{ "code": "failed_precondition", "message": "organization cannot be deleted yet: subscription[...] is active: cancel it, then retry the delete; billing account[...] has 500 unused tokens that deleting the organization forfeits: retry the delete with acknowledge_token_forfeit set to proceed", "details": [{ "type": "google.rpc.PreconditionFailure", "value": { "violations": [ { "type": "ACTIVE_SUBSCRIPTION", "subject": "<subscription-id>", "description": "..." }, { "type": "UNUSED_TOKENS", "subject": "<billing-account-id>", "description": "..." } ]} }] }Notes for review
PROTON_COMMITpin points at proton91eaffc+ only the new field (branchfrontier-pin/org-delete-token-forfeit), because proton main has since picked up breaking changes (plan RPC moves) that frontier hasn't absorbed yet. Regeneratedfrontier.pb.gois the first commit.google.golang.org/genproto/googleapis/rpcmoves from indirect to direct in go.mod for theerrdetailsimport; no version change.🤖 Generated with Claude Code