Give every agent a live badge instead of one owner an unread count

FixMediaService
Shipped
August 6, 2026 at 10:55 PM UTC
Author
Kamo
Commit
4dd2888

The nav badge and /support?tab=tickets answered different questions. The page lists every ticket in the org; the badge counted unread chat messages belonging to exactly one member, the resolved org owner, and published to support.agent.{ownerId} while each browser subscribes on its own member id. Anything reaching the list without producing an unread message in a session that one member happened to belong to moved the list and nothing else — an internally filed ticket (whose session the owner is not even a member of), a round-robin assignment, a web-chat session before the visitor typed. Every agent who was not the owner got no live updates at all: their badge was set once by the mount-time fetch, which returned the owner's number regardless of caller, and then froze. SupportPendingCountService now owns the number and the audience. The count is per-member and is the union, deduped by ticket, of tickets awaiting attention in that member's queue and tickets holding messages they have not read. It fans out to everyone with MANAGE_SUPPORT or ACCEPT_SUPPORT_TICKETS plus the owner, each with their own number, on every path that moves a ticket: create, assign, reassign, escalate, status change, pre-ticket conversion, lead re-route, visitor message and markAsRead. Also fixed along the way: - ASSIGNED was published by the backend and silently dropped by the browser, so a round-robin assignment produced neither popup nor badge movement. - Broadcasts fired mid-transaction, racing the agent's fetch against a row not yet visible; they are now deferred to after commit. - A dangling msgIdLastViewed (a plain UUID column with no foreign key) made a session read as permanently caught-up, silently uncountable forever. - support.agent.* is core NATS with no replay, so a notification published while a socket was down was gone until a reload. The client now refetches on tab focus and on a 60s foreground interval. PRE_TICKET is deliberately excluded from the queue half: it is a live web-chat session, not queued work, and counting every abandoned one would have put a permanent 25 on the badge in this cluster. It still announces itself on arrival and still counts once someone says something unread.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing