Per-extension PBX billing schema, backfill and catalog

FeatureInitializerService
Shipped
August 27, 2026 at 3:21 AM UTC
Author
Kamo
Commit
6ca4e79

PbxBillingSchemaMigration is @Order(0) because it adds a column. The shared-library entity maps phone_cost_mode from the moment the build starts, so any runner loading an OrgBillingPolicy through JPA emits it in its SELECT - ordered late this runner never executes at all, because an earlier one dies on "column ... does not exist" and takes the whole run down. org_extension_billing_days is in public, not a schema of its own: every other voip table is. It is unique on (org_id, day, addon_code, subscription_uid), one column wider than the mail equivalent, so an org with two billing groups keeps two audit rows rather than one overwriting the other. subscription_uid is NOT NULL precisely so SQL's nulls-are-distinct rule cannot defeat that index. **************** repairs the assignments InstanceSyncService had been erasing on every sweep - nine members held one and all twenty-three extension rows read null. Only fills a blank: the config side joins on an unconstrained extension string, so it is the weaker record and never overwrites an id that is set. PbxAddonCatalogMigration seeds both add-ons into every catalog that already sells the mail ones, anchored to the EMAIL_HOSTING row for org, market and compatible plans. Scoped that way rather than by a hardcoded id because two tenants own add-ons with the same codes. KamoCRMPricingLoader gets them too, for catalogs seeded from here on - it is create-only, so editing it alone fixes nothing already in the database.

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