Engineering

6

mins read

Building Deal Rooms with Real-Time Threads (Without Going Full Chat App)

Jul 7, 2025

Summary

Hexa’s Deal Rooms let reps and managers collaborate in context — comments, mentions, notes, and updates — all tied to a specific opportunity. But we didn’t want to build a full Slack clone. This article breaks down how we built real-time threaded comments using simple primitives: Redis streams, Postgres triggers, and a thin socket layer that just works.

Summary

Hexa’s Deal Rooms let reps and managers collaborate in context — comments, mentions, notes, and updates — all tied to a specific opportunity. But we didn’t want to build a full Slack clone. This article breaks down how we built real-time threaded comments using simple primitives: Redis streams, Postgres triggers, and a thin socket layer that just works.

The challenge

We wanted reps to be able to:

  • Add notes in real-time during or after calls

  • Mention teammates (@carlos) with notification logic

  • View comment history alongside call summaries and pipeline data

  • Never refresh the page

But we didn’t want to:

  • Maintain presence states

  • Deal with long-lived WebSocket pain

  • Bloat the UI with a full “chat UX”

Core constraint: one thread per deal

Every Deal Room is tied to a single deal ID. That gave us a clean scoping mechanism:

// Client-side socket room join
socket.emit('join', { dealId: 'deal_87234' })

On the backend, we mapped this to a Redis pub/sub channel for lightness and speed:

// Server-side listener
redis.subscribe(`dealroom:${dealId}`)

Real-time without state: the trigger trick

Instead of syncing comment history through a big cache layer, we used PostgreSQL triggers to broadcast events:

CREATE OR REPLACE FUNCTION notify_dealroom_comment()
RETURNS trigger AS $$
BEGIN
  PERFORM pg_notify('dealroom_update', row_to_json(NEW)::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

This let us avoid full polling — and meant that the DB was the source of truth, not some middle-layer buffer.

Mentions: just enough parsing

We didn’t need full NLP for @mentions. We used a simple regex + user map:

const mentionedUsers = body.match(/@(\w+)/g)

Then we validate them against the current deal’s team context. If valid, we trigger a notification event with:

  • Author ID

  • Deal ID

  • Mentioned usernames

  • Message text

The result

Deal Rooms feel fast and human — like lightweight sales-focused Slack threads. Reps collaborate without switching tools. Managers see conversation and activity in one place. And we didn’t over-engineer anything.

All of it runs on:

  • 1 Redis instance

  • 1 DB trigger

  • 1 socket server

  • < 500 lines of orchestration logic

Final Thought

Real-time doesn’t have to mean complex. By building for our exact use case — not a generic chat SDK — we created something lighter, clearer, and more durable.

Jump to

Share Article

Share Article

Share Article

Related Reads

More in

Engineering

If it’s not covered here, reach out — or just try Hexa free and see for yourself.

More copy, more conversions

Better content at the speed of write

High-converting, human content assets written by a 10-year copywriting expert. Delivered in 48 hours or less. That’s my promise to you.

More copy, more conversions

Better content at the speed of write

High-converting, human content assets written by a 10-year copywriting expert. Delivered in 48 hours or less. That’s my promise to you.

More copy, more conversions

Better content at the speed of write

High-converting, human content assets written by a 10-year copywriting expert. Delivered in 48 hours or less. That’s my promise to you.