Stop selling add-ons the chosen plan already includes

FixBillingService
Shipped
August 23, 2026 at 5:34 AM UTC
Author
Kamo
Commit
1993290

The catalog has always recorded which add-ons a plan bundles, in **************** — Business and Enterprise carry video conferencing, the AI assistant, the HR system and e-signatures. Nothing on the buying path ever read it. resolveAddonCodes filtered on compatiblePlans alone, so an included code passed validation and desiredItems turned it into a recurring Stripe line: a Business owner who accepted the four modules the picker offered paid $31/seat/month a second time for what the $72 seat already carried. Publish the two plan-code lists on AddonDto so a buying surface can see them, and drop an included code in resolveAddonCodes. desiredItems filters again, which is not redundant — both update paths build their items from the stored active_addon_codes, and those are only re-resolved when the request carries addonCodes. Without it, moving Starter -> Business, or merely changing the seat count, would keep billing the modules Business now grants. It also means the duplicate lines already on live subscriptions come off at the next amendment rather than needing a data fix. Matched on the plan's uid rather than on the included set being non-empty, so an add-on bundled only by Enterprise stays purchasable on Business. Both mail add-ons name no plan at all and are untouched: hosting mail here or connecting an existing provider stays a choice on every tier.

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