The partial indexes that stop a double payment and a code collision
**************** is the teeth behind the export service's refusal to re-issue. A second committed file for one pay period double-pays an entire company, and the...
KI registration and schema migration
Tables come from ddl-auto; this runner supplies only what Hibernate cannot -- the partial unique indexes on one open primary assignment and one open pay-rate wi...
Recognise an existing CHECK constraint through Spring's wrapper
TrainingSchemaMigration @Order(43) has been aborting EVERY KamoInitializer run, silently withholding all 29 runners ordered after it (orders 45-112). Observed i...
Retry a serialization conflict instead of aborting the whole initializer
Found by running it. YugabyteDB performs online schema change, so a CREATE UNIQUE INDEX issued while Hibernate's ddl-auto pass is still settling can lose the ra...
Schema for groups that can actually pay
Three runners: BillingGroupRosterMigration creates billing_pay_group_members — whom a group means to pay for, before it has bought anything. org_id is denormal...
Create the HR Training schema
Registers com.kamo.z.shared.hr.training in the explicit @EnableJpaRepositories list — @EntityScan is broad so the entities are found either way, but repositorie...
Create billing_pay_groups explicitly, and undo the legacy collision
Creating it in a migration rather than leaving it to ddl-auto, which produced a half-built table when the entity was pointed at the pre-existing billing_groups.
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Add the dunning clock columns
past_due_since and suspension_notified_at, both nullable. Null means paying and not-yet-told respectively.
Drop the constraint that limited a member to one billing account
Finds the constraint by shape rather than by name — Hibernate generated it and the name is not stable across environments, so any unique constraint on account_m...
Add the columns that make a price change detectable
Order(0), nullable, no backfill — a null amount reads as "we do not know what this price was created with" and the reconciler treats it as unknown rather than a...
Reprice Additional Storage as $2.50 per 10 GB, org-wide
The add-on described an organization-wide shared pool and was then priced USAGE_BASED at $4 with "25 GB" stated only in prose. Nothing ever submitted a storage ...
Widen the support topic assignment_strategy range CHECK to 0..3
SupportAssignmentStrategyType is @Enumerated(ORDINAL), so Hibernate emitted CHECK (assignment_strategy >= 0 AND assignment_strategy <= 2) on CREATE TABLE rather...
Add and backfill accounts.date_created
Hibernate cannot add this one itself: ddl-auto emits it NOT NULL, which CockroachDB refuses on a table that already has rows. So it is added nullable here, back...
Move calendars onto memberships and give each org a shared one
Calendars and events were owned by an account and carried no organisation. This attaches each to its owner's earliest membership — the organisation the account ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
Hand shared address-book contacts back to their owners
EmailService now scopes every contact read to contact_books.owner_id, which leaves the contacts already sitting in an ownerless organisation-default book unreac...
Schema for measured thumbnail and track storage
img_dat_derivatives records, per stored file, the real byte size of everything Kamo generated from it. It replaces img_dats.THUMB_FILE_SIZE as the source for th...
Schema for object-store-only storage measurement
object_storage_days records what a sweep reads back from MinIO for the two things that carry no size in the database: branding assets and the docs workspace. Bu...
Schema for per-mailbox storage measurement
**************** holds, per mailbox and per arrival day, the RFC822 bytes that mailbox is holding. Storage accounting had no honest source for mailbox bytes: th...
Schema runner for org_storage_snapshots
Mirrors OrgStorageSnapshot as explicit DDL, per the house style — ddl-auto creates the table first, so the CREATE is a fallback and the SET DEFAULTs are what ac...
Declare the **************** app split
The backfill only ever filled a plan row that was missing — deliberately, so it could not silently move a tier — which left apps that had never been priced wher...
Only real entitlement roots get the platform app rows
Owning subscription plans was treated as proof of being an entitlement root. It is not: a customer org runs its own commerce markets and sells its own plans whi...
Same alias NPE in the initializer seeders
resolveAll() has no entry for a deprecated alias sharing an id with a live app, so looping ServiceType.values() and dereferencing the result would have thrown m...
Bind the rename cutover as a Timestamp, not a String
CockroachDB refuses <timestamp(6)> < <varchar> rather than casting, so the app-config repair threw on its first statement every boot: 'unsupported comparison op...
Repair the second name-persisted site of the LOS rename
**************** is @Enumerated(STRING) and holds RoleRightType names, so a default role granting mortgage stores "LOS_VIEW_PIPELINE". That is the third place t...
Bound the LOS rename repair to rows that predate the rename
The repair matched on the string alone and ran on every boot, so it stopped being idempotent the moment anyone granted the personal-loan app: a row holding 'LOS...
Master model honours a runtime retirement; drop a dead guard
provisionMaxedOutMasterModel force-enables every app for the platform org, and that breadth is deliberate — pre-launch dogfooding is what the model is for. But ...
Repair mortgage grants orphaned by the LOS to MLOS rename
ServiceType is persisted in two places and the 2026-08-08 rename only accounted for one. ORG_FEATURES.FEATURE_TYPE stores the numeric id, so keeping mortgage at...
One properly categorised catalog row per app, on every entitlement root
Nine apps — POS, Marketing Tools, Calculator, Club, Inventory, Legal, Games and the two origination systems — had no catalog representation at all: no pricing r...
Grandfather orgs already running a gated commerce market
Gating MORTGAGE behind MLOS made the gate unsatisfiable for tenants: MLOS is still PLANNING, and FeatureController.enable refuses a non-COMPLETED app for a chil...
Seed app entitlement for every root, and stop inventing plan tiers
Two defects found by checking prod before flipping kamo.entitlement.fail-open. Sign Pink is a second entitlement root (isPlatformProduct, with its own FREE/BUS...
Backfill app entitlement rows into the platform plan catalog
Entitlement now resolves on a typed service_type column, but no catalog row carried one, so every plan still resolved to 'everything included' via the fail-open...
Mailbox pointers for departments and orgs, and backfill the departments
DEPTS.MAILBOX_ID and ORGS.CONTACT_MAILBOX_ID, both plain UUID with no FK to email_provider.mailboxes: mailboxes sync from external providers and can be removed ...
Give a team member a manager
Adds MANAGER_ID to member_team_member, a nullable self-reference for the reporting line. Nothing is backfilled: no manager is a complete answer, both at the top...
Add DEPTS.PARENT_DEPT_ID for nested departments
Nullable with no backfill -- null means top level, which is what every existing department was and most will stay. Declared plain UUID with an explicit DROP DE...
Migration for the commission ledger and Stripe payout tables
Mirrors com.kamo.z.shared.commission. ddl-auto would create these from the annotations anyway; the explicit DDL is the house convention and is what makes the sh...
Fail the run when a required UNIQUE index cannot be created
ensure() caught Exception and logged, so a failed CREATE UNIQUE INDEX reported success and the service booted with no uniqueness guarantee at all — the one outc...
Land the legal package schema
Adds com.kamo.z.shared.hr.legal to the repository scan list and ensures the uniqueness and lookup indexes the entity mapping cannot express safely.
Scope empty binders to (MY_DOCS, '') not the owner's member id
The My Docs DocManager never passes an assocObjectId prop, so it always resolves and queries (3, ''). BACKFILL_EMPTY_SQL was scoping empty binders to (3, member...
Correct javadoc on Hibernate ddl-auto behavior for NOT NULL columns
CockroachDB rejects ADD COLUMN ... NOT NULL without a DEFAULT on a populated table, so Hibernate's ddl-auto attempt fails (logged, non-fatal) rather than no-opp...
Backfill the collection each existing binder belongs to
Derives the scope from the first DOC item's Img; empty binders fall back to the owner's My Docs. Applies NOT NULL only after the backfill.
Create the email search_vector column and its inverted index
**************** never existed. EmailService's own V1__email_metadata_schema.sql declares it, but that migration never ran -- the table came from this service's...
Purge lead e-mail links whose lead-side address is the company's
Clears what the old company-address rule wrote before it read org_domains. Live production was purged by hand at the time (126 rows, 6 leads, one org); this exi...
Schema and contact-point seed for lead communications
Hibernate creates the three new tables from the shared-lib entities; this adds what it cannot express — the partial unique index that keeps at most one open con...
Schema for the multi-provider meeting layer
Creates **************** and org_meeting_oauth_tokens, adds the provider-identity columns to MEETING_RECORDS and MEETING_RECORDINGS and the Zoom/Teams-capable s...
Reassignable primary agent on a reserved opportunity
PRIMARY_AGENT_MEMBER_ID is who holds the opportunity now; REQUESTED_BY_MEMBER_ID is left untouched forever. Nullable with no backfill on purpose — null means "n...
Commission columns for reserved opportunities and market defaults
Six nullable columns: the overall commission agreed on a reserved opportunity, and the market default that pre-fills it at approval. NUMERIC(19,4) to match the ...
Drop the quote recipient columns
The lead holds the client's name, address and phone; snapshotting them on the quote duplicated a record edited elsewhere. The columns existed only briefly and c...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.