System_bug.published needs a column DEFAULT, or it is never created
The field was declared `@Column(nullable = false)` with no columnDefinition, so ddl-auto emitted `ADD COLUMN published boolean not null` — which Postgres REFUSE...
Three public transactional templates, and the org patch keys behind them
The careers site now writes to people who have no account, which is new for this platform: every other transactional template goes to a member. Three canonical ...
The Publish flag on a system bug, and the query rule behind it
A system bug already crossed the tenancy line in one direction. This adds the second visibility rule on top of it: a report a god-mode operator filed privately ...
The schema behind apply-first, the network, alerts and retention
member_id on hr_job_application becomes NULLABLE, which is the whole of apply-first: five steps stood between pressing Apply and answering the first question, a...
An empty platform registration is not "connect with Kamo's app"
isPlatformEnabled now also requires a client id, matching what OrgOAuthClientController reports as platformEnabled. Without that the meetings screen and the bri...
An organization can bring its own OAuth2 client
Until now the client id and secret for every OAuth provider came from one platform-wide registration, so an org could only connect what Kamo had registered — an...
The two columns a public job board needs
publish_externally decides whether an advert reaches careers.<apex> at all. It is a separate axis from status: an internal-only posting is fully AVAILABLE and m...
Careers is a platform alias, not an org's own
OrgResolutionService.byHost reads a leading label that is not a known platform alias as an ORGANIZATION's alias within the domain behind it, so without this ent...
The schema behind a row of footer badges
The email signature footer held one image, named by footer_image_source and sized by a percentage. It now holds a ROW of them: the three built-in sources plus a...
A dispatch names the terminal it is running in
Send to AI is hosted in a Remote Terminal now, so the answer has to say which one — the console opens that window, and opening it is what starts the session. B...
Job postings and applications — the schema behind /hr/careers
Two entities, six enums and two repositories under com.kamo.z.shared.hr.careers, plus the three shared types the feature had to widen. JobPosting is three grou...
Wire the accept-gate mock into the FFA spend test
acceptNextLead consults LeadAcceptEligibilityService before it reaches any of the credit logic these cases are about, and the test builds the service by reflect...
Widen the accept gate, obfuscate masked contact info, let free-for-all leads be claimed
Three related changes to the lead-assignment core. **The accept gate now asks two questions, over every assigned lead.** LeadAcceptEligibilityService replaces ...
Record a dev-machine terminal in the access log
A member opening a shell on desktop-1 now has an event type of its own. That machine holds a cluster-admin kubeconfig and its accounts have passwordless package...
Send an account's company alongside its contact for customer pickers
Six customer pickers read AccountSummaryDTO — the order editor, the service-job form, the subscription detail and wizard, and the pipeline signups tab — and eve...
Add JUST_CALL as a phone provider type
Appended at ordinal 5. **************** is EnumType.ORDINAL and carries no CHECK constraint, so appending is safe and inserting anywhere else would silently re-...
Comping an account now drops its cached entitlements
SecurityService answers /api/security/entitlements/me out of Redis with a 15-minute TTL, invalidated by messages on kamo.entitlements.invalidate. Every self-ser...
Editing a draft order's seats or cycle now reprices it
updateDraftOrder set seatCount and billingCycle and saved. Both are price drivers, and neither the order's money fields nor its line items were touched, so the ...
A paper colour per block
**************** holding a palette ID — "lemon", "glass" — and never a hex value. Stored the way notes and launchpad panes store theirs, for the reason that ma...
A comped order now grants the add-ons it sold
Comping an account granted the plan and nothing else. provisionCompSubscription copied plan, seats, cycle, source and status onto the AccountSubscription and ne...
Bind content_json as JSON, or every insert fails
REPORTED: "Failed to create sales script". The server said exactly why: column "content_json" is of type jsonb but expression is of type character varying ...
IMPERSONATE, so an operator can enter a tenant as one of its members
Appended to PlatformRightType rather than inserted: getSortOrder() returns ordinal(), so a right added in the middle renumbers every right below it in the conso...
An archived market's scripts leave the Interaction Center
findMarketIdsWithActiveScripts asked only whether the SCRIPT was active, so a market the organization had retired still appeared as a sub-tab for as long as any...
The script a member reads on a call, as ordered blocks
Two tables and two rights. SALES_SCRIPTS hangs off a lead market the way a LeadVendor does; SALES_SCRIPT_BLOCKS holds the parts, each one a Lexical document plu...
PdfRedactor, so a covered word is actually gone
A filled rectangle drawn over an account number hides it from the eye and from nothing else: the glyphs stay in the page's content stream, and a copy-paste or a...
Flush the link, so a refused write reaches the catch that reports it
link() is @Transactional(REQUIRES_NEW), so its transaction commits in the proxy after the method body returns. A plain save() of an entity whose id is generated...
Return the contact's country, state and time zone
LeadDTO carried neither Lead.country, Lead.subdivision nor Lead.timezone, so the three fields were write-only: UpdateLeadRequest accepted them and LeadService w...
An address is several lines, so send it as several lines
Splitting the suite out of addressLine was not enough — it left the street and the city sharing a line with the unit printed beneath them, which is worse than t...
A setup fee on a single-price quote, and the suite on its own line
Two things a quote could not state. A one-off setup fee lived only on QuoteOption, where each alternative carries its own. A flat sheet has no option to hang o...
Expose repricing as a static so a backfill can reuse it
Quote money columns are written, not computed on read, so an engine correction leaves existing rows carrying the old arithmetic until something saves them. A mi...
Pin the quote letter's dotted templateKey, as the HR family already is
The constant is not the templateKey. CanonicalTemplateLoader.load derives only the FILENAME from the constant (QUOTE_SENT -> quote-sent.json) and reads template...
Restore the timestamp that every lead association depends on
A method was inserted between @CreationTimestamp and the dateCreated field it annotates, so the annotation bound to subject() instead. These entities are read b...
A unit price is a MONTHLY rate, so the term multiplies it
The engine treated an option's line-item sum as the price for the whole billing period and divided down to reach a monthly figure. It is the other way round. P...
Let an event invite its guests, and put it on their calendar
Saving an event told nobody. The guest list was materialized and the audience stored, and the people on it heard nothing until a reminder fired — which reaches ...
A three-year deal totals three years, not one month of it
Two faults, both showing a monthly figure where the term's value belonged. 1. The headline took periodTotal + setup. On a MONTHLY option committed to 36 mon...
The check constraint a fourth visibility would break
Hibernate wrote `check (visibility in **************** 'PLATFORM_ADMIN_ONLY'))` when it created report_catalog. ddl-auto adds columns and never rewrites a const...
Let the platform decide who may see each report
MANAGE_REPORTS, appended to PlatformRightType, and a REPORT_CATALOG override row per report holding one of ALL_ORGS, PLATFORM_ORG_ONLY or PLATFORM_ADMIN_ONLY. ...
Bill the whole term up front, and say so on the quote
An org that charges up front saw the monthly rate on a three-year deal. The setting deciding that already existed — **************** — but it reached only Quote...
The one-time setup fee belongs in the quote's total
A setup fee typed on an option reached exactly one figure — QuoteOptionTotals put it in contractTotal — and applyOptionHeadlineTotals then built the quote's hea...
The email a scheduled report arrives in
REPORT_SCHEDULED, registered in CANONICAL_KEYS — absent from that list a template is a permanent 404, whatever files exist beside it. The body states the data ...
A service-work report, and a share target that fits every id
ServiceWorkReport is the tenth seed report and the one that makes row-level scope real rather than merely present. Commerce carries the platform's own/all pair ...
ReportDefinition never shipped the narrower rights its resolver reads
ReportScopeResolver, its test and this class's own javadoc all name alsoGrantedBy, and ReportSecurityScope has had SELF/TEAM/ORGANIZATION since the framework la...
The Report Studio framework, and nine reports built on it
A report is now a Java class here and nothing anywhere else. ReportDefinition describes what a report is, what it may be asked, which columns it has and how eac...
Let an org put a custom status label back to blank
A status label had no way to be removed. The settings screen saved through an upsert-only bulk write, so the only thing a request could say was "this status is ...
Persist a market's quote-contact rule, and refuse a half-stated one
The DTOs carried quoteContactMode and quoteContactMemberId but no writer read them, so the setting round-tripped through the form and was silently dropped. Both...
A market decides who a quote names as the customer's contact
QuoteContactMode gives a LeadMarket three answers: the lead's assigned agent (resolved per read, which is what every quote does today and what a null column mea...
Article-to-article relations
KB_ARTICLE_RELATIONS holds the curated "see also" links between articles in one knowledge base. Rows are per direction and the pair is kept symmetric by KbArtic...
A three-year term, and the promotion rules that were never read
Adds BillingCycle.TRIENNIAL so a subscriber can commit for three years. The column is varchar with no CHECK constraint anywhere, so this needs no migration — bu...
Carry the report title through a Send To AI dispatch
The dispatch sent the operator's instruction and the bug description and nothing else, so the one line saying what the report is ABOUT never reached the session...
A join/leave row has to carry the name of who it is about
The id alone cannot be resolved in the one case these rows exist for. A "removed" or "left" line names somebody who is, by then, no longer in the session, so th...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
