Let a group's plan be cancelled, and stop double-paying for one person

FeatureBillingService
Shipped
August 11, 2026 at 6:29 PM UTC
Author
Kamo
Commit
d79656c

Three gaps in what shipped last: A group with a plan could never be removed. delete() refuses while a live subscription exists — correct, since the group row is the only thing pointing at the Stripe subscription — but there was no way to cancel, so the safeguard was a dead end. cancelPlan() releases the seats first, so the roster cannot go on claiming people hold seats that no longer exist. Adding someone the organization already buys a seat for is now refused unless takeOverFromOrg says otherwise. That is the second way to be charged twice for one person and nothing caught it: SubscriptionMember's uniques are per-subscription and AccountLicense declares none at all. Moving somebody from the organization's bill onto a group's is a real thing a manager does, so it is allowed — deliberately rather than by accident. BillingGroupScopeInterceptor binds every /api/billing/groups/{uuid}/** request to the caller's organization. The handlers already check, and this does not replace them; it exists because those checks are per-handler and a group now has sub-resources that spend money. The next route added inherits nothing unless something above it applies the rule. Deliberately narrower than the handlers: this settles which organization, not who within it may act, so the two cannot drift into disagreeing answers. An unknown group id passes through so the handler answers "not found" rather than confirming the id exists somewhere.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing