The new workspace opens once, ready, and as itself
Three faults with one cause, reported after creating Carl's Jr: the new tab said ?org=kamocrm.com, showed Kamo's logo and none of the org's colours — while its ...
Correct two errors in the SW2 plan
The rsync recipe used a bare 'rsync -a', which preserves mtimes — a file restored to an earlier version arrives older than the .class already compiled from a la...
Remove the recurrence control, which discarded what it collected
The switch, frequency select and occurrence count rendered on the calendar page and reached no payload: composeDraft never read them and onSave never sent them....
The record's Communications tab shows communications
It rendered the record's media stream alone — the internal notes people write about a job. Useful, and not what anybody means by "the communications about this ...
Settle the loading gate on the gate, not on a "load started" flag
Two follow-ups to the session store, one of them a real defect. ensureLoaded decided foreground-vs-background from an `everLoaded` flag set when the first fore...
Plan SW2, the three calendar repairs
Research corrected the spec on one point: recurrence is not dead at both ends. The UI renders on the calendar page today and silently discards what the member e...
A tab only names an organization it actually has
Opening TacoBell from /network put ?org=kamocrm.com on the new tab. The tab lands on /validate, which renders inside this shell BEFORE its session exists — so t...
The launchpad shortcuts wear the org's colour, not glass
The four controls in the launchpad masthead — My Widgets, My Wallpapers, the wallpaper switch wallpaper the member chose, and a translucent white pill over a ph...
One session snapshot for the tab, not one per hook instance
useUserInfo held its session in three useState cells. It has 187 call sites and roughly 27 of them are mounted for the whole session — the nav, every shell prov...
The org reference belongs in proxy.ts, not a second middleware file
Next 16 replaced middleware with proxy, and this repo already had proxy.ts — so adding middleware.ts alongside it failed the build outright: "Both middleware fi...
Mirror the Service Work rights into TypeScript
VIEW_SERVICE_WORK, VIEW_OWN_SERVICE_WORK, MANAGE_SERVICE_WORK, ASSIGN_SERVICE_WORK and COMPLETE_SERVICE_WORK land at ids 268-272, not the 265-269 the plan assum...
One tab, one tenant — stop resolving the org from the shared cookie
Open KamoCRM in one tab and another organization in a second, refresh the first, and it rendered as the second. Close that tab, refresh again, and it came back....
Notification-spine follow-ups, triaged
Deferred items from the 33-task plan, all raised by review and all non-blocking. The whole-branch review's four must-fix findings were fixed and are not listed....
Stop standing workload from flashing the browser tab forever
TabAttention fed navGrandTotal into a 1100ms title flasher. Four of its eight addends are queue depth that never reaches zero when a member reads something: sup...
Wire markSmsRead/markAiRead/social mark-read to their windows
Final review found markSmsRead and markAiRead had zero callers, and SocialChatWindow never called markAsRead/beginViewing at all — three of five conversation su...
Ship Geist as WOFF2
Both faces are preloaded on every route, so the format is paid on every first visit. 134,132 B of WOFF became 112,252 B of WOFF2 — 21,880 B, a 16% cut. That is...
Take the softphone measurements instead of waiting for them
38 calls in the entire history of PHONE_CALL_LOG, 26 in the last 30 days. The drop-then-redial fingerprint finds 4 pairs, all provisioning test calls from April...
Give the web media path a TURN relay
The browser SIP path built its peer connection with one hardcoded public STUN /api/voip/turn/credentials for as long as that endpoint has existed — TurnControll...
Plan Service Work's first rights and the commerce permission gap
Corrects two spec assumptions against real code: no RoleRightType uses **************** (all 36 commerce rights use POS, and the editors filter on exact equalit...
Pin down bucketOf and unreadForRow against a repeat
This file just shipped four silent defects in one review round — an AI row that fell through to the wrong bucket, a title that was never read off the row, a buc...
A retail market should not download the mortgage tabs
The market settings page imported all 24 tabs statically, so every market shipped every tab — a retail market carried the seven mortgage tabs, the four personal...
Show the first wallpaper without waiting for the slowest
The slideshow preloaded every wallpaper behind a single Promise.all, so nothing painted until the LAST image in the set had settled. On a tenant with a dozen ba...
Stop the app tree's rails putting a scrollbar on the viewport
/settings/account?tab=apps scrolled the whole window, down into empty space below the shell, while the apps column it was supposedly scrolling had its own scrol...
Mark the line window executed
All eight tasks shipped across four repos, with the four deliberate deviations recorded — most importantly that Task 6's call surface was written fresh rather t...
Gate the line window per member, and show which mode you are in
The rollout control. Default off, opt-in per member from Phone Settings, nested under the VOIP switch because it means nothing for a member with no line. One h...
Every context and hook now reads user-info through the coalescer
Seven independent /api/user-info calls fired on a cold authenticated load, each one asking for the member id a sibling was already asking for at the same moment...
One refresh timer for the whole app, not one per useUserInfo()
useUserInfo has 194 call sites, roughly a dozen of them mounted for the entire session — the nav, the shell providers, the launchpad. Each instance armed its ow...
Keep the decision record — 18 rulings and what each costs if wrong
The plan records what shipped; this records why it differs from the plan. Three rulings were themselves corrected by a later review (the Stripe write count went...
Server-render the authenticated app, and fix the fallback org that 500s
MemberListProvider returned null until its mount effect ran, and it sits above NavTop AND {children} — so that one line kept the ENTIRE authenticated applicatio...
An AI sub-tab in the Interaction Center
AI sessions live in AIService and are not MediaSessions, so this bucket gets its own loader in front of the /api/media/sessions/chat fetch the other four share,...
The dedicated line window
The call now lives in a window a refresh of the workspace cannot touch. SoftphoneProvider becomes owner-or-follower. Only the owner REGISTERs and opens the STO...
A communications tab that rolls up the account's leads
The level most people mean when they say "this customer's calls". Several leads commonly hang off one account precisely because they are the same person enquiri...
The KamoDesktop link is single-use now
The comment claimed a reload re-submits ?data= and restores the session. It no longer does: the link is spent the moment the tab opens it, so it is worthless af...
Thump the first real message, not just the second
shouldThump(undefined, n) meant "first render" — but a spawned head's unread starts genuinely undefined, and applyUnreadToHeads's own undefined-vs-0 guard never...
Line ownership, the bridge, and the no-yank handover rule
Three pure modules with no consumers yet, so this ships inert. lineOwnership elects exactly one SIP registrar per browser via Web Locks. That is mandatory here...
Stop the plan instructing the money-path bug it was corrected on
Task 8 Step 4 still told the reader to key update/cancel/detach/del with "the current intent in the key". That is the Critical defect the final review reversed:...
The tab title counts everything waiting, not just chat
The tab strip has room for one number, and 'chat and support only' stopped being what a member is waiting on once SMS, AI, missed calls and unreviewed reports e...
Answer the softphone spec's biggest open question
Verified live on the cluster: every FreePBX AOR is max_contacts=1 with remove_existing=yes. That value was set nowhere in any Kamo repo, which is why it had gon...
Make every client component safe to render on the server
Next server-renders client components, so `window`, `document`, `localStorage`, `sessionStorage` and `navigator` do not exist during the render that produces th...
A total on the phone icon, the breakdown in the menu
This icon carried no badge at all, so a missed call while the softphone was closed reached the member nowhere. Opening the phone clears the missed count.
A total on the icon, the breakdown in the menu
pendingCount was the whole badge, so unreviewed bug reports and webinars booked on somebody's behalf had no way to reach anyone. Opening the webinar row stamps ...
The settings tab opens the calendar's editor
Sharing the day picker was the half-measure. It left two forms that still had to agree with each other about recurrence, times, effective range, note, save sema...
The chat badge counts chats
It was silently chat plus support, so a ticket lit the chat bell and nothing distinguished the two. Support has its own icon now; social joins chat, because a s...
Let a dropdown row carry its own count
The icon shows the sum and the rows show the breakdown — the point of splitting the indicators is seeing WHICH thing wants you without opening anything.
Thump on arrival, with the glow dissipating outward
Its own layer inside .hex-scale: that element already animates transform for the hover grow, and two animations on one element do not compose — the second repla...
One context for the four indicators' counts
Composes what exists and owns the three that had no home: unreviewed bug reports, unreviewed webinars, and the phone's missed calls and voicemails. The 60s for...
Je, unaona nini kuhusu usafiri?
Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.