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 ...
Paint the branding of the org in the tab, not the host
getThemePath() derived the theme base from window.location.hostname. That answered the right question while every organization had a hostname of its own — and f...
Clear the cloned session in the enter-as tab
Entering an org opens a tab with window.open('', '_blank') and points it at /validate. That was cross-origin until now, so nothing was shared. It is same-origin...
The five pre-existing verticals must ship available
Shipping all six children PLANNING was wrong for five of them. RETAIL, RENTAL, SERVICE, SUBSCRIPTION and PROCUREMENT are not new functionality — they are what C...
Read the session from the tab, not the shared cookie jar
46 client modules read the *** id out of document.cookie and sent it as X-***-Token. sessionStorage is per-TAB; a cookie is per-ORIGIN. While every organization...
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...
The scheduled-support presenter picker offered nobody
The Presenters tab dropdown was empty for every organization, and always had been. GET **************** answers with { teamMembers, total }; the tab read data.m...
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 /api/org/current the domain the client requires
internal.kamocrm.com failed to render with "Invalid organization data: missing 'id' or 'domain'". Organization.fromJSON refuses a record without a domain, and t...
Move jump-to-newest in with the toolbar's other actions
Search now owns the whole left track of the toolbar, because the empty part of that track is exactly the room the field opens into. The scroll-to-bottom control...
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...
A sent message animates in once, not twice
The message list keyed each row on the message id, and a sent message's id changes exactly once — the optimistic row is appended under a local id, and the STOMP...
Name rooms after the org id, not the hostname
getOrgToken() took the first label of the current host, and its own comment said why: "so identically-named rooms cannot collide across orgs". On the shared hos...
Scope rooms to their organization on the shared meet host
Room isolation was the HOST. A member of org B could not present a *** cookie on meet.<org-A-domain>, so knowing org A's room name got them nowhere. Serving org...
Make the auto-login cross-tenant guard actually run
The guard read the host org's id with /"id"\s*:\s*(\d+)/ -- a bare digit straight after the colon. SecurityService's JsSafeLongSerializer writes any Long above ...
Stop handing an alias row over as the org's domain
**************** walked org.getDomains() filtering only on isActive. That collection holds the org's root domain AND its alias rows -- api, login, theme and the...
Take the chat-core that stops a sent message showing twice
@kamo/chat-core 0.1.6. The conversation reducer now adopts the pending optimistic row when the member's own message comes back over STOMP, instead of appending ...
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...
Stop RingCentral OAuth signing white-label tenants out
Two faults, both on the same hop, and each one hides the other. RingCentral rejects every scope value this app can ask for — "invalid_request / Parameter [scop...
Show cents on an add-on rate that has them
Additional Storage is $2.50 per 10 GB block, and the catalog stores that as a number — so 2.50 arrives as 2.5 and rendered straight into the card it read "+$2.5...
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...
Stop offering Business the add-ons it already includes
Choosing Business still presented video conferencing, the AI assistant, the HR system and e-signatures as things to buy, even though the plan bundles all four. ...
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...
Stop selling add-ons the chosen plan already includes
The catalog has always recorded which add-ons a plan bundles, in **************** — Business and Enterprise carry video conferencing, the AI assistant, the HR s...
Let the SSL check lower the flag, not only raise it
checkDns only ever latched sslConfirmed to true. A domain whose stored flag was set under the old any-one-host rule therefore kept a green SSL card and an unloc...
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...
Open the swatch's own colour window, not the first on the page
The swatch reached its hidden <input type="color"> through document.getElementById on an id built from the picker's translated label. A label is only unique ins...
Stop the colour group fighting the colour you are choosing
ModernColorGroup was controlled and uncontrolled at the same time. It kept local state for every slot, mirrored the `value` prop into that state in one effect, ...
Read the new org's id when it arrives quoted
The last step of the wizard appeared to do nothing, and clicking Create a second time answered that the organization already exists — because the first click ha...
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...
Show per-host certificate progress, not a single spinner
Certificates are issued one per subdomain, and they do not all land at once, so the SSL step now reports how many of the org's hosts are live and names the ones...
Point frame media at an endpoint that actually serves it
Every photo and video in a picture frame rendered as a broken image. The URL pointed at **************** I took that for a general imaging proxy — it speaks HT...
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....
Make the Spirit Animal visible, and stop the palette vanishing
Two reports, two different mistakes of mine. THE PATTERN WAS INVISIBLE. It painted behind the pane, and every pane surface — FeatureCard, LauncherParentCard, W...
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 ...
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 ...
Stop /validate and /logout from mounting the signed-in shell
A load of / showed a burst of 401/403 before the session settled — user-info, ui-preferences, by-department, chat/unread, timezone/effective and tickets/pending...
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...
Stop the drag preview from driving itself into a render loop
Dragging a pane sometimes threw React #185 and left the page scrolling to the bottom forever, undoing every attempt to scroll back up. One cause, two symptoms....
Bucket the history by the member's day, not the browser's
groupByDay built its day key from getFullYear/getMonth/getDate, which read the machine's calendar rather than the member's. With createdAt now parsed as the UTC...
Restore the timezone fix, and take chat-core 0.1.5 / net 0.1.1
5d1cc23e was committed through a stale private index and reverted ec881208 wholesale — serverTime.ts, the member-timezone provider, the guard and all 216 call-s...
Render every timestamp in the member's zone, read every one as UTC
A direct message sent at 3:33 AM Pacific displayed "10:33 AM" — the raw UTC clock, printed as though it were local. Two independent defects, present together on...
Stop the master-note ring sweeping a gradient across the launchpad
LIVE ON PRODUCTION since b9b1fe08. The org master note's ring was a conic gradient in a pseudo-element sized 150% by 150%, centred and rotating once every six s...
Make the pane logo visible, and stop the two seeding passes racing
Two bugs, either of which alone would have shown no logos. IT WAS PAINTED BEHIND FROSTED GLASS. The mark went in at z-index 0, under the pane's content — where...
Do not offer form fields on files that cannot carry them
Replacing the two buttons dropped the isConverted gate the old "Edit PDF" had, so Modify offered form-fillable editing on audio and video — where there is no re...
A form fillable row can still be opened in the editor
I had disabled "Edit In Form Fillable Mode" on a form-fillable row, which contradicts the rule: its fields stay editable in every tool the editor has — what a f...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.