Bind add-ons to the app they sell, and stop Business granting mail free

FixInitializerService
Shipped
August 23, 2026 at 5:35 AM UTC
Author
Kamo
Commit
b60d7af

**************** is the column **************** matches on. KamoCRMPricingLoader never wrote it, so every KamoCRM add-on row has it NULL and that comparison can never match — the second, independent grant path the resolver is built around has been inert since the catalog was seeded. Mail is the case that hurts. PlatformTierMatrixMigration is the authority on tiers and deliberately puts e-mail on no tier ("priced per seat on any plan"), so every plan carries an explicit is_included = false row for it. An explicit false is a denial, not a gap, so entitlement fail-open does not rescue it. With the add-on unbound as well there was no path to the app at all: an organization could buy KamoMail Hosting, be charged monthly, and still have no mail. The same silence cost Starter the four modules it buys as add-ons — bought, billed, never delivered. The loader now passes each add-on's ServiceType, and a migration backfills the rows already seeded (create-only createAddOn means a re-run would not). Only NULL rows are touched, so an operator's hand binding survives and a second run is a no-op. Also drops ServiceType.EMAIL from the loader's businessApps and holds it out of the Enterprise sweep, via ADDON_ONLY_APPS. The loader was granting the mail app to Business while its own feature matrix labelled KamoMail Hosting "Add-on" and the catalog went on charging for it — billable and pointless at once. That brings the loader into line with PlatformTierMatrixMigration, which already declares mail to be on no 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