Actually measure the bulk-export bucket
StorageDomain.BULK_EXPORTS shipped declared, documented as "measured by scanning the object store", and referenced by nothing. It reported zero for every practi...
Create returns the domain its theme is provisioned under
The caller cannot work this out and must stop trying. GET /org/{id} answers with the entity, whose `domains` is LAZY and serializes as null outside a transactio...
A push token may be claimed by one device row, not every past sign-in
Companion to MediaService 8a809b3, which stopped members getting the same chat message three-plus times on their phone. That change made dispatch collapse dupli...
Recover a lost background count from the images themselves
commitBackgroundOrder writes the images to STAGING, and imageBgCount is only a record of how many it wrote — which made that one column a single point of failur...
Gate the nine Service Work endpoints on a right
They shipped checking only that the caller had a session, so any member of an org could read and mutate every work order in it regardless of role. ASSIGN_SERVI...
Drop the nine Service Work endpoints from the unguarded baseline
They are gated as of e6e1d02, so their baseline entries no longer match an unguarded endpoint and **************** fails on the stale lines. Requiring the remov...
Stop the customer **************** rights reading every tenant's rows
Every endpoint that accepted a VIEW_OWN_* right as an OR-alternative loaded its record by primary key alone, never checking who it belonged to: getSubscription,...
Serve a tenant's assets from a host that resolves, and stop deleting its backgrounds
Two faults found while working out why a new org opened with no logo and no colours. THEME DELIVERY. Assets were requested from theme.<the org's own domain>. A...
Show one call once in a rollup, and stop 500ing on unworked leads
Two fixes the account rollup made visible. A phone number can be a contact point on more than one owner at the same time, and two leads on one account sharing ...
Make the KamoDesktop SSO link redeemable exactly once
The link is delivered as a URL, so it lands in browser history and in the reopen-closed-tab list, where it long outlives the session it was minted for. Until no...
The account rollup must not widen what a reader may see
The account timeline I added last commit was a way around the per-lead read gate. A member refused a lead's messages on the page that names the lead could open ...
/org/current stops depending on a live Hibernate session
This endpoint is what the workspace shell loads before it renders, and the client refuses a record it cannot read — Organization.fromJSON throws without a domai...
A failed workspace selection no longer destroys the sign-in
Reported as being thrown back to the email field with "Your sign-in timed out. Please sign in again." after clicking Continue. The timeout had not happened — th...
Stop the logo pass starving backgrounds, and read <picture>
Diagnosed against a real site that returned six logos, brand colours and zero background images. Three separate causes, all ours. The logo pass could eat the e...
An unfinished domain picks a different host, not a refusal
Entering an org was refused outright unless its own custom domain had finished DNS and SSL. That was right while entering meant navigating to https://internal.<...
Stop the SSO token expiry from emptying a live desktop session
"The requested connection does not exist. Please check the connection name and try again." on a KamoDesktop reconnect was not a missing connection. It was the S...
Send the member to the workspace host, not a relative path
SignInCompletionService returned a relative /validate?otk=. That resolves against the host that served the SIGN-IN — login.<apex> — and kamo-login has a /valida...
Delete the "first organization in the database" fallbacks
Seven blocks across five controllers ended their org-resolution with, in effect: if the server name is localhost or a bare IP, return whichever organization the...
Keep an alias unique platform-wide, on both write paths
Creation checked the alias only within one security provider, and PUT /org/{id} checked nothing at all — it applied whatever it was given. Both were reasonable ...
Refuse an alias that names more than one organization
byAlias took LIMIT 1 over orgs.alias, which has no uniqueness constraint: the create path checks it per security provider and PUT /org/{id} does not check it at...
Resolve the domain on /org/current server-side
internal.kamocrm.com failed to render with "Invalid organization data: missing 'id' or 'domain'". Organization has no `domain` field -- it has a `domains` colle...
Give the workspace path the same post-login work as the host path
Two gaps found by re-reading the original login tail against the new one, before enabling the picker. The form-encoded /login endpoint built its LoginRequest w...
Stop requiring DNS verification to sign in
OrgHostResolver.resolveByDomain filtered on od.is_dns_verified = TRUE, so a domain row that existed but had not finished verifying resolved to nothing and login...
Verify-dns answers for the present, not for a stored flag
The endpoint skipped probing entirely when ssl_confirmed was already true, on the reasoning that under the all-hosts rule it could only have been set when every...
Re-verify domains already marked SSL-confirmed, and heal them
findAwaitingVerification filters confirmed domains out by design, so once ssl_confirmed was set nothing ever looked at that domain again. That was fine while th...
Make post-commit org setup actually write, and heal the orgs it missed
A @Transactional method called from **************** does not open a transaction of its own. Spring fires those callbacks from processCommit BEFORE cleanupAfter...
Confirm SSL only when every org host has its own certificate
Certificates are minted one per FQDN -- a single dnsName each, so the leaf CN matches the hostname the browser connected to -- and auto-cert works through an or...
Serve frame media ourselves, with Range
Every photo rendered as a broken image. The URL pointed at MediaService's **************** which I took for a general imaging proxy because it spoke HTTP Range....
Stamp last_login so "Last Login" stops reading Never
Nothing in SecurityService has ever written users.last_login. The write lived in the retired AuthenticationService and was not carried over when authentication ...
Restore the status endpoint the frontend has been polling
kamo-internal polls GET /api/security/session/god-mode once on mount and every 60s thereafter. That endpoint was removed in 9c70cb7 along with the rest of the t...
Drop the universal seed; the timecard widget follows MANAGE_TIMECARDS
UNIVERSALLY_SEEDED_RIGHTS is removed entirely. It existed only because the timecard widget had no parent right to inherit from, and now it has one — so the widg...
Stop cutting note bodies off at 500 characters in the timeline
The All tab of a lead's communications rendered a note through LeadCommunicationMapper, which capped the body at 500 characters — with no ellipsis and no flag, ...
Report leads available for products with no allotment
/manage built its whole response by looping over allotments, calling countAssignablePool once per row. But the Manage-Credits grid lists products from the vendo...
Settle each backlog payload as it is processed
processBacklog mirrored the scheduled job's two defects: it mutated payload statuses in memory and saved them in one batch at the end, and it saved the whole en...
Never fail a submission because its counter update lost a race
storePayload no longer bumps the endpoint's received counter; the receive controller now calls recordReceipt separately, in its own transaction, and swallows th...
Make the verification sweep's DNS upgrade reachable
DomainVerificationWatcher gated on **************** but **************** only ever answers ok/pending/error/na — it has never returned "verified". allVerified w...
Restore media as a required DNS alias so its card can verify
media.<domain> backs MediaService realtime websockets and is live in Traefik, auto-cert and the /setup/dns studio catalog, but it was dropped from KnownAliases ...
Stop reporting a missing column as a missing table
Four controllers each rewrote ANY message containing "does not exist" into "Database table X does not exist. Please run KamoInitializerApp to create the schema....
Close two unauthenticated endpoints reachable from the internet
SecurityService is anyRequest().permitAll() with @EnableMethodSecurity absent, so every @PreAuthorize is inert and public is the default; APIService relays /api...
Delete the dead Long-as-string config and pin why it must stay dead
JacksonConfig registered a **************** serializing Long as String -- the standard guard for CockroachDB ids, which run past JavaScript's MAX_SAFE_INTEGER. ...
Stop rejecting request fields the DTO does not have
Declaring an ObjectMapper bean takes binding away from Spring Boot's auto-configured one, and a hand-built mapper carries Jackson's defaults rather than Boot's....
Stop failing a branding save over compliance flags it never sent
PUT /org/{id} derived the age ranges and the three ATF flags from the stored row whenever a request omitted them, then asserted all five against the applied sec...
Creating and deleting a lead take the rights that name them
LeadController is one of the better-gated controllers in the platform — VIEW_LEADS, EDIT_LEADS, ASSIGN_LEADS, REASSIGN_LEADS_MANUALLY, VIEW_UNASSIGNED_LEADS and...
Renaming a member is an admin act, and now has a gate
The member profile's legal-name card was self-only, so an admin who typed a name wrong on the create form could never correct it — MemberCreateForm asks for pre...
Close the add-path route around the platform-admin lockout guard
POST replaces an existing administrator's rights, so it can take them away as well as give them — but only the PUT and DELETE paths checked whether the edit wou...
Enforce the doc-share search rights server-side
/members-subscribers and /team-members-contractors enumerate the organisation's people — names and ids — to fill the document-share autocomplete, and required o...
Stop copying lead details onto the calendar event
The event carried the lead's name, number, email and best time to call, copied into its description when the call was booked. A copy of a record that is still b...
Stop writing the lead path into the callback's description
It read "Open the lead: /leads/view/123" and was not a link. It could not be: a description is edited in a textarea, where text is text — and outside the applic...
An unreadable close-readiness body is unknown, and the approval count moves into its window
The wrong-path bug is fixed and the response shape is verified, but the CLASS of failure it belonged to was still open: if TimecardService renames `blocking`, d...
A failed close-readiness relay leaves awaitingApproval unknown, not a confident zero
With FINALIZE_PAY_PERIODS held, a 5xx/404/unparseable close-readiness response left awaitingApproval sitting at its initial 0 — the WARN log fired but the HR Ov...
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.
