I’m using Phoenix channels to build a chat app similar to Discord. I’m new to Elixir and Phoenix and wouldn’t consider myself to be a backend wizard. I’m wondering how you might handle showing unread indicators / counts.
Let’s assume a user belongs to multiple organizations and each of those has multiple rooms. Similar to Discord, I’d like be able to show:
- An unread dot next to each organization with unreads
- Bold the name of the unread room within an organization
I’ve set up my channels like this:
channel "user:*", AppWeb.UserChannel
channel "org:*", AppWeb.OrgChannel
channel "room:*", AppWeb.RoomChannel
I have a somewhat working solution but it feels a bit hacky so I’m wondering what a best practice solution might look like. Currently, I’m doing this:
- I have
organizations
,rooms
,messages
,org_memberships
androom_memberships
tables. - I store a
last_read_message_id
on theroom_memberships
table and use it in my ecto queries. - When the user logs in, I join them to the
UserChannel
which fetches their organizations and each has a virtualized boolean field forunread
. - When the user navigates to an organization, I join them to the
OrgChannel
which fetches the rooms for that organization and each has a virtualized field forunread_count
. I assign therooms
to thesocket
. - When the user navigates to a room, I join them to the
RoomChannel
which fetches the messages for that room. - When a user sends a message, I determine which users should receive that message and use
Phoenix.PubSub
to broadcast that back to their respectiveUserChannel
to update the organization booleanunread
field and to theOrgChannel
to increment theunread_count
for that room if it’s found in the socket’srooms
. These are both pushed to the client so that I can show the unread indicators as described above.
My solution also seems to kind of hit a roadblock when taking into account direct messages because they aren’t tied to a particular organization. Right now a direct message is treated the same as a regular room but with type: “dm”
and organization_id: null
. Open to ideas here too.
I considered sending the unread_count
for all rooms
a user is a member of after they log in but that seemed like a bad idea if they are in say 20+ organizations each with 20+ rooms. Maybe my intuition here is wrong and it’s ok as long as the payload is small with just the room_id
, organization_id
, and the unread_count
?
I’m guessing this is well-trodden territory and would appreciate any tips you might have.