Skip to main content

๐Ÿ’ฌ Conversations Module (v2)

๐Ÿ“– Overviewโ€‹

The Conversations v2 module is DashClicks' unified communication platform, enabling real-time team collaboration through direct messages, channels, and a dedicated support inbox system. It integrates multiple communication channels (in-app chat, SMS, email) into a single threaded interface, with features including message search, favorites, reminders, read receipts, and file attachments.

File Path: internal/api/v1/conversation-v2/

Key Capabilitiesโ€‹

  • Direct Messaging: 1-on-1 private conversations between team members
  • Channels: Group discussions for teams, departments, or projects
  • Support Inbox: Dedicated customer support message routing with assignment
  • Multi-Channel: Send/receive SMS and Email within conversation threads
  • Real-time Sync: Socket.IO integration for instant message delivery
  • Rich Features: File attachments, message favorites, reminders, read tracking
  • Search: Full-text search across messages and rooms
  • Status Management: Online/offline status, snooze notifications, unread counts

๐Ÿ—๏ธ Architectureโ€‹

Service-Oriented Structureโ€‹

conversation-v2/
โ”œโ”€โ”€ services/ # Business logic layer
โ”‚ โ”œโ”€โ”€ conversation.service.js # User conversation management
โ”‚ โ”œโ”€โ”€ room.service.js # Room CRUD and queries
โ”‚ โ”œโ”€โ”€ message.service.js # Message operations
โ”‚ โ”œโ”€โ”€ support.conversation.service.js
โ”‚ โ”œโ”€โ”€ support.inbox.service.js # Support inbox assignment
โ”‚ โ”œโ”€โ”€ support.message.service.js # Support message handling
โ”‚ โ””โ”€โ”€ support.room.service.js # Support room management
โ”œโ”€โ”€ controllers/ # Express request handlers
โ”œโ”€โ”€ routes/ # API endpoints
โ”œโ”€โ”€ validations/ # Request schema validation
โ”œโ”€โ”€ middlewares/ # Auth, permissions
โ”œโ”€โ”€ utils/ # Helper functions
โ””โ”€โ”€ config/ # Configuration

Data Modelโ€‹

erDiagram
CONVERSATION ||--o{ ROOM : participates
ROOM ||--o{ MESSAGE : contains
USER ||--|| CONVERSATION : has
ROOM ||--o{ SUPPORT_INBOX : "assigned_to"

CONVERSATION {
ObjectId _id
ObjectId user_id
ObjectId account_id
Array status
Boolean default_sms_inbound
Boolean default_email_inbound
}

ROOM {
ObjectId _id
String room_type
String name
Array members
ObjectId last_message_id
Array unread_count
Boolean deleted
Array favorite
Array snooze_time
}

MESSAGE {
ObjectId _id
ObjectId room_id
ObjectId conversation_id
String content
String source
Array receivers
Array attachments
Array favorite
Array reminders
Boolean deleted
}

SUPPORT_INBOX {
ObjectId _id
String name
Array members
ObjectId account_id
}

๐Ÿ—„๏ธ Collections Usedโ€‹

conversationsโ€‹

  • Purpose: User conversation container (1 per user)
  • Model: shared/models/conversation.js
  • Key Fields:
    • user_id (ObjectId) - Owner user
    • account_id (ObjectId) - Agency account
    • status (Array) - Online/offline history
    • default_sms_inbound_conversation (Boolean) - Default SMS recipient
    • default_email_inbound_conversation (Boolean) - Default email recipient

conversations.roomsโ€‹

  • Purpose: Chat rooms (direct messages, channels)
  • Model: shared/models/conversation.room.js
  • Key Fields:
    • room_type (String) - 'direct' | 'channel'
    • name (String) - Channel name (null for direct)
    • members (Array) - [{ conversation_id, last_message_read }]
    • last_message_id (ObjectId) - Latest message reference
    • unread_count (Array) - [{ conversation_id, count }]
    • favorite (Array) - Favorited by users
    • snooze_time (Array) - Notification snooze settings
    • deleted (Boolean) - Soft delete flag

conversations.messagesโ€‹

  • Purpose: Message storage with threading
  • Model: shared/models/conversation.message.js
  • Key Fields:
    • room_id (ObjectId) - Parent room
    • conversation_id (ObjectId) - Message author
    • content (String) - Message text
    • source (String) - 'chat' | 'sms' | 'email'
    • receivers (Array[ObjectId]) - Recipient conversation IDs
    • attachments (Array) - File metadata
    • favorite (Array) - Favorited by users
    • reminders (Array) - Reminder settings
    • deleted (Boolean) - Soft delete flag
    • deleted_by (Array[ObjectId]) - User-specific deletion

support.inboxesโ€‹

  • Purpose: Support team inbox configuration
  • Model: shared/models/support-inbox.js
  • Key Fields:
    • name (String) - Inbox label
    • members (Array[ObjectId]) - Assigned conversation IDs
    • account_id (ObjectId) - Owner account

_usersโ€‹

  • Operations: Read (lookup for user details)
  • Usage: Populate conversation owner information

crm.contactsโ€‹

  • Operations: Read (contact lookup for SMS/email)
  • Usage: Retrieve contact details for multi-channel messaging

๐Ÿ”„ Data Flowโ€‹

Message Creation Flowโ€‹

sequenceDiagram
participant Client
participant API as Conversation API
participant DB as MongoDB
participant Socket as Socket.IO
participant External as SMS/Email Service

Client->>API: POST /messages
API->>DB: Create message document
API->>DB: Update room.last_message_id
API->>DB: Increment unread_count
DB-->>API: Confirm
API->>Socket: Emit 'new_message' event
Socket-->>Client: Push to receivers

alt Message source is SMS/Email
API->>External: Send SMS/Email
External-->>API: Delivery confirmation
end

API-->>Client: 201 Created

Room Unread Count Managementโ€‹

flowchart TD
A[New Message Created] --> B[Get Room Document]
B --> C{Member in unread_count array?}
C -->|Yes| D[Increment count]
C -->|No| E[Add member with count=1]
D --> F[Update room.unread_count]
E --> F
F --> G[Emit Socket Event]
G --> H[Client Updates Badge]

I[User Reads Message] --> J[Update member.last_message_read]
J --> K[Set unread_count to 0]
K --> G

Support Inbox Assignmentโ€‹

flowchart TD
A[New Support Message] --> B{Room has inbox assigned?}
B -->|No| C[Find available support inbox]
B -->|Yes| D[Route to existing inbox]

C --> E{Inbox members online?}
E -->|Yes| F[Assign to least busy member]
E -->|No| G[Round-robin assignment]

F --> H[Update room.inbox_id]
G --> H
D --> H
H --> I[Notify assigned member]
I --> J[Create support.room entry]

๐Ÿ”ง Core Servicesโ€‹

Conversation Serviceโ€‹

File: services/conversation.service.js

Functions:

  • queryConversation(accountId, userId) - Get or create user conversation
  • getConversation(id) - Retrieve conversation by ID
  • queryTeamConversations(options) - List all team member conversations with filtering

Key Business Logic:

// Auto-create conversation if not exists
const convObj = await Conversation.findOne({ user_id: userId });
if (!convObj) {
const newConv = await new Conversation({
user_id: userId,
account_id: accountId,
}).save();
return newConv;
}

Room Serviceโ€‹

File: services/room.service.js (807 lines)

Functions:

  • getRoomStatus(options) - Query rooms with filtering, search, pagination
  • createRoom(options) - Create direct message or channel
  • updateRoom(roomId, updates) - Update room metadata
  • deleteRoom(roomId) - Soft delete room
  • markAsRead(roomId, conversationId, lastMessageId) - Update read status
  • favoriteRoom(roomId, conversationId) - Toggle favorite status
  • snoozeRoom(roomId, conversationId, duration) - Snooze notifications

Key Business Logic:

  • Unread Filtering: Filters rooms with unread_count.count > 0 for specific conversation
  • Search: Searches channel names and user names in direct messages
  • Pagination: Cursor-based pagination with next/previous references
  • Read Tracking: Updates members[].last_message_read and resets unread count

Message Serviceโ€‹

File: services/message.service.js (624 lines)

Functions:

  • getMessageStatus(options) - Query messages with pagination, search, filtering
  • createMessage(roomId, conversationId, content, options) - Create new message
  • updateMessage(messageId, content) - Edit message content
  • deleteMessage(messageId, conversationId) - Soft delete for user
  • favoriteMessage(messageId, conversationId) - Toggle favorite status
  • processMessage(conversationIds, message) - Send SMS/Email messages

Key Business Logic:

  • Multi-Channel Sending: Detects source: 'sms' | 'email' and sends via external services
  • Soft Delete Per User: Uses deleted_by array to allow per-user deletion
  • Cursor Pagination: Uses upperRef and lowerRef for bidirectional scrolling
  • Attachment Processing: Generates file buffers from Wasabi/S3 for email attachments

Support Servicesโ€‹

Files: support.*.service.js

Support Inbox Features:

  • Inbox Management: Create/update support inboxes with team member assignment
  • Automatic Routing: Route support messages to available team members
  • Load Balancing: Distribute incoming requests across inbox members
  • Status Tracking: Track resolution status and response times

๐Ÿ”€ Integration Pointsโ€‹

Socket.IO Eventsโ€‹

Emitted Events:

  • new_message - New message created
  • message_updated - Message edited
  • message_deleted - Message removed
  • room_created - New room/channel
  • room_updated - Room metadata changed
  • read_receipt - User read messages
  • typing_indicator - User is typing
  • status_changed - Online/offline status

Event Payload Example:

{
event: 'new_message',
room_id: ObjectId,
message: {
id: ObjectId,
content: String,
conversation_id: ObjectId,
created: Date,
attachments: Array
}
}

External Servicesโ€‹

  • SMS Service (utilities/sms.js) - Twilio integration for SMS messaging
  • Email Service (utilities/mail.js) - SendGrid integration for email
  • File Storage - Wasabi/S3 for attachment storage
  • CRM Contacts - Contact lookup for SMS/email recipients

๐Ÿ” Authentication & Authorizationโ€‹

Permission Scopesโ€‹

const REQUIRED_SCOPES = {
conversation: 'Basic conversation access',
'conversation.support': 'Support inbox access',
'conversation.admin': 'Manage channels and settings',
};

Access Controlโ€‹

  • Team Conversations: User must belong to same account_id
  • Direct Messages: User must be member of room
  • Channels: User must be in members array
  • Support Inbox: User must be assigned to inbox or have conversation.support scope

โš™๏ธ Configurationโ€‹

Environment Variablesโ€‹

# Socket.IO
SOCKET_IO_URL=http://localhost:4000

# External Services
TWILIO_ACCOUNT_SID=xxx
TWILIO_AUTH_TOKEN=xxx
SENDGRID_API_KEY=xxx

# File Storage
WASABI_PUBLIC_IMAGE_DOWNLOAD=https://cdn.example.com
WASABI_ACCESS_KEY=xxx
WASABI_SECRET_KEY=xxx

Constantsโ€‹

File: constants/index.js

const ROOM_TYPES = {
DIRECT: 'direct',
CHANNEL: 'channel',
};

const MESSAGE_SOURCES = {
CHAT: 'chat',
SMS: 'sms',
EMAIL: 'email',
};

const MAX_MESSAGE_LENGTH = 5000;
const MAX_ATTACHMENTS = 10;

๐Ÿงช Edge Cases & Special Handlingโ€‹

Case: Multi-Channel Message Failuresโ€‹

Condition: SMS or Email sending fails after message is created

Handling:

  • Message remains in database as sent
  • Error logged but not propagated to client
  • External service retries handled by queue system
  • User sees message as sent in UI

Case: Orphaned Messagesโ€‹

Condition: Message exists but room is deleted

Handling:

// Messages preserved for audit trail
// Queries filter by room.deleted = false
// Messages still accessible via direct query

Case: Conversation Without Userโ€‹

Condition: User deleted but conversation references remain

Handling:

  • Soft delete user, conversation remains
  • Queries use $lookup with preserveNullAndEmptyArrays: false
  • Conversations with null users filtered from results

Case: Unread Count Synchronizationโ€‹

Condition: Client goes offline, multiple messages sent

Handling:

  • Server maintains authoritative unread count
  • On reconnect, client fetches current count via API
  • Socket events update count incrementally
  • Read receipts reset count to 0

โš ๏ธ Important Notesโ€‹

  • ๐Ÿ”’ Data Isolation: All queries filter by account_id to prevent cross-account access
  • โšก Real-time Critical: System heavily dependent on Socket.IO availability
  • ๐Ÿ“ฑ Multi-Device: Same user can have multiple socket connections (desktop + mobile)
  • ๐Ÿ’พ Soft Deletes: Never hard-delete messages for audit compliance
  • ๐Ÿ“ง External Costs: SMS/Email messaging incurs external service costs
  • ๐Ÿ”„ Eventual Consistency: Unread counts may briefly desync between devices

๐Ÿ“Š Performance Considerationsโ€‹

Indexing Requirementsโ€‹

// conversations collection
{ user_id: 1, account_id: 1 }

// conversations.rooms collection
{ 'members.conversation_id': 1, deleted: 1, updated: -1 }
{ 'unread_count.conversation_id': 1, 'unread_count.count': 1 }

// conversations.messages collection
{ room_id: 1, receivers: 1, deleted: 1, created: -1 }
{ content: 'text' } // Text index for search

Optimization Patternsโ€‹

  • Pagination: Always use cursor-based pagination for messages
  • Projection: Exclude large fields (attachments) when not needed
  • Aggregation: Use $facet for combined queries (data + count)
  • Caching: Cache room metadata for frequently accessed rooms

Last Updated: 2025-10-08
Module Path: internal/api/v1/conversation-v2/
Services: 8 service files (conversation, room, message, support variants)
Collections: 4 core collections (conversations, rooms, messages, inboxes)

๐Ÿ’ฌ

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM