Auto Assignment offers the ticket, it does not allocate it
Auto Assignment pages every available support agent and goes to the first one who accepts. It was implemented as "silently pick the least-busy agent who is onli...
Run the topic's strategy for widget chats too
A chat opened in the web widget is the same unit of work as one filed inside the app, but this path skipped the topic's assignment strategy entirely — the only ...
Decide the sign-in auto-open on the server, not in this tab
The per-tab sessionStorage flag was not a record of anything. Signing in on a second device replayed every conversation the first had already popped, and cleari...
Don't let one failed request silence the sign-in auto-open
Unread chats are auto-opened once per tab-session, guarded by a sessionStorage flag. That flag was written up-front, before the fetch that tells a chat session ...
Stop typing an unseen support session as a plain chat
A live activity frame for a session not already in the list synthesized a row hard-coded to 'CHAT'. For a support ticket that put it in the wrong sub-tab, showe...
Put the session type on the activity frame too
The unread/ACTIVITY broadcast is published for every session type and carried no indication of which. The chats list, having nothing to go on, typed an unseen s...
Stop a support ticket opening a plain chat window full of JSON
Two faults, one symptom. Assignment makes the agent a member of the ticket's media session, so the incoming-message notification reached them and ChatNotificati...
Tell the client which kind of conversation a message arrived in
Every member of a media session receives the incoming-message notification, and assigning a support ticket makes the agent a member of that ticket's session. Th...
Declare the calendar tokens at :root, and rebuild the event dialog
The tokens were declared on the calendar wrapper element, which reads as the tidy thing to do and is wrong. MUI dialogs and menus render through a portal into d...
Actually override the operator label ink
The previous attempt raised specificity, which was the wrong diagnosis: tailwind.config.js sets `important: true`, so every declaration in .operator-label ships...
Widen the support topic assignment_strategy range CHECK to 0..3
SupportAssignmentStrategyType is @Enumerated(ORDINAL), so Hibernate emitted CHECK (assignment_strategy >= 0 AND assignment_strategy <= 2) on CREATE TABLE rather...
Make every line of the hero readable
The kicker and the three readout labels were painted by .operator-label's own dark ink, not by the colour set beside it: a class and an sx rule carry the same s...
Make the pinned-app eyebrow actually white
The previous attempt overrode .operator-label's ink with a class-qualified sx rule, which could never have worked: tailwind.config.js sets `important: true`, so...
Return the account's creation date to the account list
buildAccountSummary never emitted dateCreated, so the field the list's Date Created column reads was simply absent from the response. Now that Account records t...
A live chat is claimed through the popup, never allocated
Routing chat requests through round-robin was the wrong model and it broke the thing it was meant to fix. An assigned ticket leaves the claimable queue (Support...
Take the caller from the session, not from the query string
GET /api/calendar/calendars took userId as a request parameter, so changing a number in the URL read anyone's calendars — and because calendars carried no organ...
Stop assignment failures destroying the ticket that triggered them
Routing a new ticket ran inside the creation transaction, so anything it hit rolled the ticket back with it and the member asking for help got "Failed to create...
Give each account tab the default order it should open in
The three tabs opened in whatever order the API happened to return, which for members meant the newest sign-ups were buried and for team members meant no order ...
Stop BUSY surviving every future login
Logout writes AWAY and login clears it, so AWAY is a state the system puts you in and takes you out of. Nothing ever cleared BUSY. A member who set it once stay...
Route a chat request through the topic's assignment strategy
A support chat request is filed as a PRE_TICKET, and createTicket skipped assignment for those outright. The guard was written for the web-chat widget, where a ...
SecurityService pool exhaustion caused liveness kills
Hikari had no explicit maximum-pool-size, so it ran on the default of 10 while fronting org/rights lookups for every service and the internal site. Observed tot...
Scope the default-lead-source readiness banner to Residential Mortgage markets
The vendors/products tab showed the "Finish the mortgage vertical to designate a default lead source" warning on every market tab, including Product/Service and...
Centre the selection bar on the contact list, not the page
The bar that appears when rows are selected is absolutely positioned at left 50% with a translateX(-50%), but its nearest positioned ancestor was the whole page...
Make MKCOL create a book that can actually be stored
mkCol built a ContactBook carrying neither an organisation nor an owner and returned 201 regardless, so creating an address book from a CardDAV client failed at...
PublicChatApiKey.scopes jsonb binding
A field with an initializer was skipped by the earlier jsonb sweep, so this one still bound as varchar: 'column scopes is of type jsonb but expression is of typ...
Stop defaulting new contacts into the shared org book
The create dialog targeted the book flagged isOrgDefault, so every member's contacts landed in the one book the whole organisation could read — half of why the ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
Scope address books to the member who owns them
Contacts were scoped by organisation alone. listBooks(orgId) was findByOrganizationId(orgId), and the contact list query opened WHERE c.contactBook.organization...
@Lob String must pin LONGVARCHAR or PostgreSQL reads it as an OID
Hibernate's PostgreSQL dialect maps @Lob String to an OID (large-object reference) and reads it with getLong(). CockroachDialect mapped the same annotation to p...
Allow YugabyteDB port 5433 in kamowssecurity Cilium egress
A CiliumNetworkPolicy selecting app=kamowssecurity allowed host/remote-node egress on 26257, 4222 and 9000 only. After the cutover the database moved to 5433 an...
Allow YugabyteDB port 5433 in kamowssecurity Cilium egress
A CiliumNetworkPolicy selecting app=kamowssecurity allowed host/remote-node egress on 26257, 4222 and 9000 only. After the cutover the database moved to 5433 an...
Correct the rationale on pre-created schemas
KamoInitializerService does set **************** true, so it creates these schemas itself. The previous comment claimed it did not. The file stays as explicit b...
Correct the rationale on pre-created schemas
KamoInitializerService does set **************** true, so it creates these schemas itself. The previous comment claimed it did not. The file stays as explicit b...
Administrator bar panels rendered their key paths, not their copy
TipPanel took the panel's DOM id in a prop called `id` and then built its message keys from that same `id`, so every panel asked for **************** and next-i...
Let the access log fill its pane and page from the server
The tab bar already says "System Access Logs", so the h4 above the stats was the page's name twice. Dropping it also lets the pane use the shell every other Sec...
Stop the list scrolling when it already fits
Three things added height that was not content, so a list short enough to fit still got a scrollbar: - the infinite-scroll sentinel was rendered unconditionall...
Restore the administrator bar changes reverted by 3926d1d8
3926d1d8 carried AdminQuickLinks.tsx back to its ae45fc9c^ blob, undoing the org plural label, the short Blocks/Logs names and the gap removal. Same content as ...
String row ids, org-coloured controls, page icon, centred error bar
Creating a book and selecting it answered "Not found". CockroachDB unique_rowid() ids are 64-bit — a real one is 1200081912680906758 — and JSON.parse rounds any...
Publish row ids as strings — a new book 404'd the moment you selected it
CockroachDB unique_rowid() produces 64-bit ids. A real one from contact_books is 1200081912680906758; JavaScript's JSON.parse rounds anything past Number.MAX_SA...
Stop renewing the shared *** TTL for idle users
Fifth service holding its own copy of KSessionService, and the fifth sliding the shared *** TTL on every read. Each one alone was enough to keep a session alive...
Stop renewing the shared *** TTL for idle users
Caught with redis MONITOR: this pod was issuing GET + PEXPIRE against a *** key whose owner had been idle for over an hour, seconds after SecurityService had co...
Stop /api/user-info renewing the TTL for idle users
This route writes the *** TTL straight to Redis, so it bypassed the gating in SecurityService, MediaService and ChatService entirely — and useUserInfo polls it ...
Stop renewing the shared *** TTL for idle users
This service keeps its own copy of KSessionService, and it slid the TTL on every read. Gating SecurityService alone therefore fixed nothing: kamo-internal point...
Recover a received attachment whose first request was rejected
A video arriving in a conversation could not be played until the page was reloaded, while a video the member had just sent always played. Both copies were byte-...
Give each organization a real transaction boundary
StorageSnapshotSweep.catchUp carried @Transactional(REQUIRES_NEW) and was called from sweep() on the same bean. Spring applies @Transactional through a proxy, s...
Record message sizes instead of writing zero
SearchIndexService wrote sizeBytes = 0 for every message it ever indexed, under the comment "Not available from envelope". It was available — the fetch profile ...
Popover X closes the window, not just the popover
Dismissing the popover already had two affordances (click outside, Escape), so an X that only dismissed it was a duplicate and left no way to get rid of the hea...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.