Messaging & realtime
Team channels - the unread count is the hard part
channel fan-out against DM, threads that do not bump the room, and the badge nobody wants to store
What this board gets wrong on purpose
The tension
Unread counts are computed, not stored - last_read_seq per (user, channel) subtracted from the channel head - which makes a message one write instead of thirty thousand. The board then pays for it on every app launch: 12M people x 6 launches x 35 channels is 2.5 billion range counts a day, 2.2x more work than the counter writes it avoided, and the read_state table still takes six times as many writes as the message table because moving a marker is itself a write. Worse, mentions cannot be computed this way - a mention badge has to be exact - so the expensive per-user row exists anyway, just for the small case. And nothing on this board reconciles two devices reading the same channel at once: last_read_seq is last-writer-wins, so reading on your phone can mark a channel read on your laptop mid-scroll.
Requirements
Ask these before drawing anything
- How big may a channel get? The answer picks the fan-out strategy, and there is no strategy that is right at both 8 members and 30,000.
- Must the unread count be exact, or may it be approximate while you are not looking at the channel? This is the single highest-leverage question on the page.
- Must a mention badge be exact? Almost certainly yes, and that is a different answer from the one above, which is why two mechanisms exist.
- Is history infinite, or does a plan tier cap it at 90 days? Retention changes the message store from a growing cost into a constant.
- One read state per person, or per person per device? Per device is what users expect and doubles the most-written table on the board.
- Do threaded replies mark the parent channel unread? Getting this wrong makes a busy thread feel like spam to 29,000 people.
- Do we need full-text search across all of it? Search is a second copy of the message store and it should be sized here rather than discovered later.
- Guest and shared-channel access: can a member of workspace A read a channel owned by workspace B? Membership stops being a simple join the moment the answer is yes.
Functional
- Post a message to a channel or a DM; deliver it to anyone currently looking.
- Show a per-channel unread state and an exact mention badge in the sidebar.
- Reply in a thread without marking the channel unread for people not in the thread.
- Mute a channel: it receives messages and generates no badge.
- Open the app after nine hours and get an accurate sidebar in under a second.
- Scroll back through history from any point in a channel.
Non-functional
- p50 delivery to a watching socket under 300 ms; p99 under 1 s.
- Sidebar hydration on cold launch: p95 under 800 ms for 35 channels.
- 99.95% availability for posting. Unread counts may be stale under load; mentions may not be wrong.
- Per-channel ordering is guaranteed. Cross-channel ordering is not, and no part of the product depends on it.
- A message, once acknowledged, is never lost. A count, once wrong, self-heals on the next read.
Out of scope
- Search indexing (a second system, sized separately).
- Calls, huddles, file previews.
- Compliance export and legal hold, which want their own read path over the same log.
The rest of this board
Available on Tier Slate
This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 5-table schema — is the board itself, and it opens in Tierslate.
- 5written pages
- 8walkthrough steps
- 5tables33 columns
5 pages behind this one
- Capacity estimation
- Storage estimation
- Availability
- How it works
- Deployment plan
More boards
Delivery, presence, ordering, and who is typing.