Put live widgets on the launchpad, starting with two calendar strips
A widget is a live pane that shares the grid, the drag and the ordering with the app cards rather than sitting beside them. Adding the next one is a single regi...
Add the Policies tab, and stop offering chats the backend refuses
Four views over one draft ruleset, because there are four different questions and no single layout answers them all. Rules is what each rule does, Matrix is wha...
Design the org chat policy engine and its Policies tab
Rules are an ordered list over ordered member pairs; the first match decides, so every verdict names exactly one rule and the UI can always explain itself. Sele...
Reorder the tabs and paint Binders and Uploads
The strip reads Originals | Modified | Common | Binders | Uploads, which puts the three views of the documents together and the two destinations after them. Bin...
Removing from Selected Docs unchecks the row
The mirror ran one way. Removing a document deleted the binder item but left its checkbox ticked in the grid, so the next sync — on the very next visit to the t...
Stop rounding document ids into nothing
A document id is a 19-digit int64 — 1200096283020258886, some 133x past Number.MAX_SAFE_INTEGER. OrganizerTab joined the selection into a key so the effect woul...
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...
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.
