Design a newly-unread sender count

Model the difference between total unread messages and newly unread senders with Redis sorted sets and per-user read state.

Newly-Unread Indicator

A newly-unread badge is not the same as total unread messages.

Example product behavior:

You receive messages from three unique people while away. The badge shows 3 . You open the messages screen. The badge clears, even if you did not open every conversation.

This is an acknowledgement indicator, not the canonical per-message read state.

The app needs a cheap call:

Near-real-time badge reads should not scan messages or replay Kafka events. Precompute the state.

Redis Sorted Set Model

Use one sorted set per recipient:

members are unique sender IDs, score keeps latest sender order, cardinality gives the badge count, a sender can update their timestamp without duplicating the count.

mermaid sequenceDiagram participant A as Sender A participant API participant DB as Message DB participant R as Redis participant WS as WebSocket Gateway participant B as Recipient B

A- API: send message to B API- DB: persist message API- R: ZADD newly unread:B timestamp A alt B online API- WS: push badge update WS- B: newly unread count changed end

Persist the message first, then update the badge projection. If the projection update fails, it can be retried or rebuilt from recent messages.

Acknowledgement Flow

mermaid sequenceDiagram participant B as User B participant API participant R as Redis

B- API: open messages screen API- R: DEL newly unread:B API-- B: messages screen payload