Say when a selected document could not be added
The Selected Docs binder skips a document it cannot legally hold rather than failing the whole sync, which is right — but it did so silently, so a binder holdin...
Fold the Modify tab into Binders
The strip is now Originals | Binders | Modified | Common | Uploads. Modify is gone: everything it did — arrange the checked documents, preview them, merge them ...
Assemble the lead record instead of holding it behind a spinner
The Details tab's loading state was one card of fourteen grey MUI pulse rows — a shape the pane never takes, on a per-element clock, replaced wholesale by a lay...
A minimized chat is neither read nor silent
Two bugs that shared a cause: the only flag saying "this window is minimized" was pinned false, so everything that asked it silently did nothing. An arriving m...
A member chat's own reads clear its badge, and a reply counts as one
Two gaps left over from giving the support window this treatment. Sending a message cleared nothing. The chat core marks a conversation read when it starts, wh...
Offer to associate past e-mail when a lead's address is set
Mail is matched to a lead strictly point-in-time: an address only claims traffic from the moment it is recorded, so that editing a lead today cannot rewrite who...
One agent picker for assignment, reservations and the filter
The Assigned Agent control on a lead's assignment pane was a local component in LeadViewClient. Two other places wanted exactly it, so it moves to *************...
Stop flexbox crushing the When card down to its header
The start and end fields were not clipped by their own width. The card holding them was being shrunk to nothing. A flex item's automatic minimum size — `min-he...
Hide the balance controls that free-for-all cannot use
Credit Balance, Daily Allotment and Max Balance all act on a granted balance, and an FFA product has none — acceptance there mints and spends its own credit. Le...
Name the requestor, move the org line, shorten the Open Org button
Three adjustments to the support surfaces. "Open org as System User" is now "Open Org", sitting immediately after assign/reassign rather than at the end of the...
Say which clock the event dialog is on, and show the start time
Four things the composer got wrong, on /calendar and on the lead page alike. The zone was the browser's. That is a fact about the laptop, not about the member:...
Show the requestor's photo on each support chat row
Every row in Chats → Support wore the same blue support glyph, which is no help at all when the list is what you scan to decide what to pick up. The face is now...
Pool count on the product header, accepted-today per member
Leads Available was rendered in every member row of a product group, but it is a property of the (product, market) pool — the same number repeated down the colu...
Take leads-available from the server's per-product counts
leadsByProduct was derived from the allotment rows, which only cover products someone already holds a credit rule for. The grid lists products from the vendor c...
Give the composer its caret back after each send
Every chat box in a tool window locks itself while a message goes out — the input carries `disabled` so nothing typed mid-flight is discarded when the draft res...
Show the requestor's org, and offer the System User door to their agent
The support chat header now names the organization the request came from, to everyone working the conversation and to nobody else — the person who raised it wou...
Fetch one server-filtered page instead of the whole organisation
The grid fetched every lead in the org and narrowed it in a ~300-line useMemo. Measured on production 2026-08-20: 1,427 leads fetched so seven could be shown, 2...
Every country flag in the app was a blocked image
Eight more screens had the defect found in the marketing visitor drawer. The app is served under img-src 'self' data: blob: https://theme.kamocrm.com https:/...
Flags are emoji, because the CSP blocks every flag CDN
The visitor drawer painted a broken-image glyph where each country flag should be. react-country-flag's `svg` mode reads like a self-contained component and is ...
Offer Company Name as a mappable import field
leadFields.ts is the list the mapping canvas draws from, and it must mirror the backend switch in LeadImportController — a path missing from either side is acce...
Retitle Modified to Converted and fix two tab icons
Both tabs wore an icon that already means something else in this grid: the Modify tab used GetApp, the row-level download button, and Converted used EditNote, t...
Clear the unread badge for a conversation the member is reading
The badge was fed by two unordered sources — the REST unread read and MediaService's unread topic — and applied whichever landed last, with nothing ever re-read...
Choose which page a tracking link lands on
A code is not tied to a page — the marketing site captures it site-wide — so the only real question when sharing one is where the visitor should land. The produ...
Show the code as a handle, not 36 characters of hex
Moving the token to a UUID left the grid rendering the whole thing, which is correct in a URL and useless in a table: it cannot be scanned, compared against the...
Build the shared link as ?discount=<uuid>
buildTrackingLink emits the new parameter, and the link strip highlights the ?discount= segment it used to highlight as ?mrt=. The token itself is now an opaque...
Show when a visitor's credit moved to another link
The timeline gains ATTRIBUTION_MOVED, in the warn tone — not a conversion and not a failure, but the moment this visitor stopped being this member's to earn fro...
Move Windows Desktop and Master Machine into Platform Admins
Both are Guacamole targets that share one credential between everybody, which makes them operator tooling rather than a member's own workspace. They were top-ba...
A popup with nowhere to dock now overlaps instead of not opening
A tool window — the email composer, a support conversation, a chat, the softphone — would sometimes simply not appear, and be fine after a reload. Three silent ...
Say which link the strip is offering
"Your tracking link" showed exactly one link while a member can hold any number of them, so the strip silently rendered whichever code the sort put first and ga...
Finish the details the first pass left rough
Nine small corrections, each with a visible symptom. The drawer opened on ~0.4s of blank panel: `loading` started false, so the first committed render fell thr...
Build out Tracking Codes in place of the referral placeholder
/marketing/discounts was a ComingSoon stub; it is now /marketing/tracking, a working workspace, with the old path kept as a client redirect so existing bookmark...
Shorten the empty-description hint
The Description column shows {No Description} in place of "No description provided..". The string was hardcoded English, so it now comes from the dictionary — w...
Reorder and retitle the document tabs
The strip now reads Originals | Modify (n) | Modified | Binders | Common | Uploads, and Common trades the gear icon for a library one now that it no longer says...
Stop opening a note from overwriting it with a blank body
The editor seeded its buffer with `note.content || ''`, then compared that '' against the incoming null and concluded the member had unsaved edits. Two seconds ...
Paint the knowledge console in the org's colour, not a fixed purple
The rebuild took its chrome from --accent-knowledge, which globals.css declares as #8b5cf6. That variable does not move with an organization's brand, so every c...
Rebuild the knowledge base as a console
The four knowledge-base screens were the last in the app still wearing the old look, and three of them stated things that were not true. /kb showed "Pinned Art...
Nobody with a login is the anonymous web-chat visitor
A widget ticket names the org's SYSTEM member as its requestor because the visitor has no member record — and that member is the org owner, usually the person a...
Stop the inbox claiming email is unset while it works it out
Opening /messages showed the "email isn't available / you have no mailbox" panel for a moment on nearly every visit, then replaced it with the member's real inb...
Drop the masthead stat rail, move the filter to the bar
The five counted tiles are gone from the header. It now states what the page is and gives the rest of its width to the primary action. They were also the only ...
Rebuild /hr/attendance as a payroll console
Eight flat tabs over eight panels that each drew their own heading, table, skeleton, error line and Snackbar — and had drifted. The overhaul is three things at ...
Rebuild the network page as an operations console
The page was the last screen still wearing the old look — a flat gradient bar, white cards, a centred spinner, alert() for every failure — while the rest of the...
Rebuild /hr/legal-compliance as the legal registry
The surface was a MUI tab strip over two AG Grids. Packages rendered as seven columns of counts and an actions cell of six unlabelled icon buttons, three of whi...
Rebuild /hr/training as a training console
The tab was two AG Grids under a tab bar: accurate and mute. It now opens on the org's whole training obligation and lets an admin act on the gaps. - A masthea...
Let a note pinned from its sticky reach the launchpad band
The home band fetched the pinned list once on mount, so a note pinned from its floating sticky afterwards was in no list it held. Closing the sticky then left t...
Rebuild to pick up the Start Group Chat/Meeting labels
The image bakes messages/ from kamo-translation-dictionary at build time, so the dictionary push alone left the deployed bundle on the old copy.
Hold the token's int64 ids as digits, not as numbers
KToken could not verify a real token. The four ids it carries are int64s, and the Java signer (kamo-shared-library KToken#canonicalForMac) appends each as a raw...
Market filters were comparing a UUID against a number
Both market filters were dead, in different ways, and neither said so. Leads: a market tab matches a lead either by marketId or by the market's vendor products...
Stop rounding int64 ids on the way back to the server
Sweep of the client half of the int64 id work. Each of these took an id the server had sent intact and put it through Number()/parseInt(), which rounds anything...
Record the SecurityService unauthenticated-endpoint triage
Three fixed, the rest explained. The headline number needed narrowing three times and the first two attempts were wrong the same way — enumerating helper names ...
Let the colour palette take clicks again
The sticky's palette was a child of the title bar. Header and writing surface are siblings on the same layer, so the body — later in the DOM — paints over the h...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.