Make orgs.alias unique platform-wide
The column was never constrained. Survivable while an alias was only resolved as (security_provider_id, alias) behind a host, since two orgs under different pro...
Put tenant_id back at the front of the clinical resource keys
ddl-auto built PRIMARY KEY (logical_id, resource_type, tenant_id) on fhir_resource_current and fhir_resource_version, because Hibernate emits @EmbeddedId column...
Create the System Bugs tables
No CHECK constraint on the ordinal columns: support_ticket_status_check is what happens when Hibernate freezes one at an enum's size and the enum then grows, an...
Price the commerce children and the EHR, with a totality guard
Neither pricing map had a totality check, and the two failure modes are different and both silent. Missing from CATALOG, an app lands nowhere on the pricing mat...
Extend market grandfathering into the app-tree backfill
grandfatherExistingGatedMarkets already walked each org's active markets, resolved getRequiredService() and enabled the missing app — it was just restricted to ...
Rich-text description columns on webinar_type
Mirrors the shared-lib entity change. Two things the table needs before MediaService maps them. The description column has to be unbounded: it holds a Lexical ...
Remember the last workspace a member signed in to
users.last_org_id backs the workspace picker. An organization is no longer named by the hostname, so a member who belongs to several chooses one after signing i...
Settle Additional Storage at $2.50 per 10 GB block
Confirms the block size and rate as $2.50 per 10 GB rather than the $4 per 25 GB the production row had drifted to. The seeder, the catalog row, the Stripe pric...
Price Additional Storage as $4 per 25 GB unit, FLAT not metered
Additional Storage is bought by the unit, belongs to no plan on any tier, and is not seat-based. The seeder still described it as $2.50 per 10 GB block, which i...
Correct what the add-on binding gap actually was in production
The previous commit's reasoning was inferred from the loader, not measured. It claimed every KamoCRM add-on row had service_type NULL and that hosted mail was t...
Bind add-ons to the app they sell, and stop Business granting mail free
**************** is the column **************** matches on. KamoCRMPricingLoader never wrote it, so every KamoCRM add-on row has it NULL and that comparison can...
Drop the frozen ordinal CHECKs that were failing every new enum value
imgs_assoc_id_check allowed assoc_id 0..13. ImageAssocType.PICTURE_FRAME is ordinal 14, so EVERY Picture Frame upload violated it. Hibernate writes CHECK (col ...
Merge the two modified records into one with two layers
Where a document has both kinds, the CLASSIC row survives — it is the one that may hold edited bytes — the design is repointed onto it, and the FORM_FILLABLE ro...
Create the picture_frames table
One row per Picture Frame widget a member has arranged on their launchpad. A table rather than a preference blob because the photos and videos in a frame are i...
Add the master-scope columns to notes
MASTER_SCOPE ('MEMBER' / 'ORG' / NULL) and ORGANIZATION_ID, plus the two indexes the entity declares and a partial unique index per scope so one live master not...
Move existing designs onto FORM_FILLABLE rows
Before versions existed, putting form fields on a document attached an esign_templates row straight to the original, and the Modified tab was "originals that ha...
Add imgs.modified_kind and imgs.original_img_id
Both stay nullable — null kind means the row is an original, so there is nothing to backfill and no NOT NULL step, unlike the usual column-add shape. The parti...
Create the chat policy schema
Six tables: the versioned ruleset, its rules and their clauses, the reply grants behind "reply only while their window is open", and the trail of what the polic...
Add binders.is_scratch
Four statements rather than one ALTER: binders is populated, and Yugabyte rejects the whole ADD COLUMN … NOT NULL statement rather than the clause, so the colum...
Add ****************
Records who filed a reservation when that is not the agent it names, so somebody managing opportunities can raise one on a sales agent's behalf without the reco...
Composite indexes for geolite_locations
Country alone was the only index on an 80,429-row table. Measured on production: city resolution (country + subdivision) index-scanned all 18,870 US rows to kee...
Index member_rights_applied on (member_id, the_right)
The table had no indexes at all, while every finder on it filters by MEMBER_ID. At 10,524 rows a single member's rights lookup was a full sequential scan — meas...
Composite lead indexes, and unblock the run that creates them
The /leads grid now filters and pages in the database instead of shipping the whole organisation to the browser. With only IX_LEADS_ORG_ID that would relocate t...
Retire ****************
Tracking codes are shared as ?discount=<uuid> now. The old <memberId>.<n> token published a real member id in every shared link and made the space walkable — on...
Add users.is_fake, in the only statement order a populated table allows
Mirrors the new `User.isFake` field. Four statements, and the order is the whole migration: YugabyteDB rejects `ADD COLUMN … NOT NULL` on a populated table — re...
Add the kamomeet_logo_overlay column
Third overlay surface: the KamoMeet pre-meeting screen. Same shape as the other two — nullable, no backfill, no DEFAULT. The drift guard needed only its field ...
Purge the reports and dashboard rows, and stop seeding VIEW_DASHBOARD
VIEW_DASHBOARD (0), VIEW_REPORTS (1) and EXPORT_REPORTS (2) were deleted from RoleRightType today, along with the two pages they named. This removes what they l...
Add the loading_logo_overlay column
Second surface for the logo overlay feature: the loading screen shown between page navigations, alongside the home page masthead. Both ALTERs live in the one r...
Add the home_logo_overlay column
Backs the Home Page Logo Overlay setting: the solid colour an org can paint over the masthead logo on the kamo-internal home page. Holds a token rather than a ...
Purge VIEW_EMAIL_LOGS rows, and stop a test rotting when ordinals shift
VIEW_EMAIL_LOGS (64) was deleted from RoleRightType today for naming a feature that was never built. This removes what it left behind — measured at 42 role rows...
Purge the stored rows for the two retired notes rights
SHARE_NOTES (72) and MANAGE_NOTES_SETTINGS (73) were deleted from RoleRightType today for having no feature to gate. This removes what they left behind, counted...
Add orgs.background_order
Nullable VARCHAR(20), no backfill and no DEFAULT — every client resolves an absent value to sequential, which is the behaviour every org had before the column e...
The meet seed recomputes applied rights instead of waiting for a boot
Granting the two rights on org_role_rights changes nothing anybody can observe. member_rights_applied is the flattened snapshot the session and the server-side ...
Stand up the platform administrator list
Backfills it from the retired system_user_access grants so nobody who could operate the System User before this deploy loses it: direct member grants map one-to...
Seed the meet rights before the gate can lock anyone out
MediaService now requires START_MEETING to create a meeting and VIEW_MEETINGS to resolve one. Measured on production before writing this: 42 security roles acro...
Purge stored rows for the deleted chat-channel rights
Ids 74/75/76 no longer resolve. RoleRightsSyncService would sweep them on some future SecurityService boot anyway — silently, at an unpredictable moment, with n...
Move notes from account ownership onto membership
Adds notes.member_id and attaches each note to its owner's earliest membership — the organisation the account has belonged to longest, which in practice is wher...
Backfill ancestors so closure cannot remove access
MemberRightsAppliedService now denies any right whose parent chain is not granted. Every row written before the hierarchy existed knows nothing about ancestors,...
Add the is_rich_text column, defaulted and backfilled to rich
Whether a note is edited as rich text or plain text cannot be read back out of its content: a rich note nobody has formatted yet is byte-for-byte a plain one. W...
Seed every organization a default legal text
One hr_legal_settings row per org, unique on org_id, carrying **************** INSERT-ONLY, never an UPDATE. An org that has edited its own wording owns it; a ...
Match the enum-whitelist CHECK sweep to the YugabyteDB rendering
dropStaleEnumWhitelistChecks() looked for '% IN (%', which is how CockroachDB stored a @Enumerated(EnumType.STRING) whitelist. PostgreSQL and YugabyteDB normali...
Member notification tables, and an event's origin columns
Two halves of one feature. A callback scheduled on a lead is mirrored onto the scheduling member's calendar, and the point of the mirror is to get back to the l...
Correct what the index-backed read path actually guarantees
The previous comment claimed the read path "refuses to serve any folder it cannot prove it agrees with the server about — so a row that is wrong here is a row t...
Add is_answered to the mail search index
Adds **************** so the index records all three IMAP flags rather than two. The message list draws a reply marker from this one, and the index-backed listi...
Index and REVOKE the payroll-provider tables
What Hibernate cannot express for the new hr_timecard_payroll_* tables. Two REVOKEs. PayrollDispatch and PayrollSyncIssue refuse updates and deletes in Java th...
The void columns on hr_timecard_punch
Mirrors four new nullable columns on the TimecardPunch entity. A void is neither a delete nor a correction: it says the punch should never have existed — a doub...
Point at YugabyteDB, and stop `mvn test` migrating production
The datasource still named port 26257. That is the retired CockroachDB, which is still running and still answering, so a run against it succeeds completely and ...
Start again, and stop the billing migration deleting its own index
KamoInitializer could not start at all. Hibernate detects CockroachDialect, whose supportsInsertReturning() and **************** are both false, so an @Id carry...
Create ACCOUNT_HISTORY
Mirrors the AccountHistory entity in kamo-shared-library. Written explicitly rather than left to ddl-auto because the defaults matter: ID and DATE_CREATED carry...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.