# User counters API ## GetUserCounters Authenticated lightweight WebSocket request used by the bottom toolbar. Request: ```json {"op":"GetUserCounters","requestId":"...","payload":{}} ``` Success payload: ```json { "login": "alice", "dmUnreadCount": 7, "channelsUnreadCount": 12, "notificationsUnreadCount": 5, "notificationRepliesUnreadCount": 2, "notificationConnectionsUnreadCount": 1, "notificationEventsUnreadCount": 2 } ``` The fields form a stable UI contract. Their server-side calculation is intentionally replaceable by materialized counters/cache later. ## UserCountersChanged Server push event for every active session of the user. It lets the toolbar update without polling. ```json { "op":"UserCountersChanged", "event":true, "payload":{ "login":"alice", "dmUnreadCount":7, "channelsUnreadCount":12, "notificationsUnreadCount":5, "notifications":{"replies":2,"connections":1,"events":2} } } ``` Current implementation emits this event after channel read-state writes, notification seen-state changes and applied incoming DM/read-receipt blocks. Future materialized counter logic can emit the same event immediately on any counter increment/decrement. ## Channel read behaviour - Opening a subscribed channel does **not** mark all messages read. - The UI advances readCount only when message cards cross the viewport read threshold while scrolling. - Writes are debounced; failed writes are shown to the user and retried. - Immediately after a successful subscription from inside an open channel, the client stores `readCount = current messagesCount`, because those existing messages are treated as already viewed at subscription time.