How We Built a Scalable Multi-Agent Team Inbox: Behind the Tech Stack of AR Inbox
A deep-dive case study into the Node.js, WebSockets, and Redis queue architecture powering AppRinger's unified business messaging inbox.

How We Built a Scalable Multi-Agent Team Inbox: Behind the Tech Stack of AR Inbox
To build a high-performance team inbox for conversational commerce, you need more than just standard API connections. When hundreds of users interact with multiple support agents concurrently, the real engineering challenge lies in latency, socket state management, and message queue integrity.
In this technical case study, we review the architecture of AR Inbox, AppRinger's proprietary shared team inbox platform.
1. The Core Architectural Challenge
When a customer sends a message on WhatsApp, Meta triggers a webhook. If 50 customers message your brand simultaneously, your server must:
- Receive and acknowledge the webhook in under 200ms to avoid retries from Meta.
- Ingest the payload and store it in a persistent database.
- Identify the active support agent assigned to the thread.
- Push the new message to the agent's web browser in real-time with sub-100ms socket latency.
Here is how we designed AR Inbox's high-concurrency event-driven architecture to meet these demands:
[ Incoming Meta Webhook ]
│
▼
[ Express.js Ingestion Gateway ] ──► [ Redis Event Queue ]
│
▼ (Broker Dispatch)
[ Socket.io Pool ] ◄────────────── [ Queue Consumer workers ]
│ │
▼ (Websocket Push) ▼
[ Agent Browser Dashboard ] [ PostgreSQL Cluster ]
2. Ingesting Webhooks Safely with Redis Queues
To avoid database locks during bulk broadcasts, we separate webhook ingestion from message writing. Our Express server immediately pushes raw payloads into a Redis-backed bullMQ cluster and returns an instant 200 OK status to Meta.
Background workers consume these jobs, handling database operations, contact association, and agent assignment rules asynchronously.
Queue Consumer Worker (Node.js & Redis):
const { Queue, Worker } = require('bullmq');
const db = require('../lib/database');
const io = require('../lib/socketPool');
const webhookWorker = new Worker('webhook-ingestion', async (job) => {
const { payload } = job.data;
// 1. Write message to PostgreSQL database safely inside a transaction
const message = await db.transaction(async (trx) => {
const [newMessage] = await trx('messages').insert({
whatsapp_id: payload.messageId,
sender_phone: payload.from,
content: payload.text,
direction: 'inbound',
status: 'delivered',
created_at: new Date(payload.timestamp * 1000)
}).returning('*');
// 2. Fetch or update assigned agent
const conversation = await trx('conversations')
.where('phone', payload.from)
.first();
return { newMessage, conversation };
});
// 3. Emit real-time update to active agent sockets
if (message.conversation?.assigned_agent_id) {
io.to(`agent:${message.conversation.assigned_agent_id}`).emit('new_chat_message', {
message: message.newMessage,
conversationId: message.conversation.id
});
}
}, { connection: redisClient });
3. Database Schema for High Concurrency
To support high-concurrency read/write operations without performance bottlenecks, AR Inbox uses a optimized relational schema with composite indexes:
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone VARCHAR(20) NOT NULL UNIQUE,
display_name VARCHAR(100),
status VARCHAR(20) DEFAULT 'open',
assigned_agent_id INTEGER REFERENCES users(id),
last_message_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES conversations(id) ON DELETE CASCADE,
whatsapp_id VARCHAR(100) UNIQUE NOT NULL,
direction VARCHAR(10) CHECK (direction IN ('inbound', 'outbound')),
content TEXT NOT NULL,
status VARCHAR(20) DEFAULT 'sent',
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Indexing for fast lookups on agent dashboards
CREATE INDEX idx_conversations_agent ON conversations(assigned_agent_id) WHERE status = 'open';
CREATE INDEX idx_messages_conversation ON messages(conversation_id, created_at DESC);
4. The Engineering Takeaway
Our work building AR Inbox proves we don't just consume API wrappers—we design, build, and optimize core B2B messaging infrastructure. Whether you need custom webhooks, reliable message queues, or seamless CRM workflows, AppRinger's engineering team delivers scalable, production-ready solutions.