๐ฌ 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 useraccount_id(ObjectId) - Agency accountstatus(Array) - Online/offline historydefault_sms_inbound_conversation(Boolean) - Default SMS recipientdefault_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 referenceunread_count(Array) -[{ conversation_id, count }]favorite(Array) - Favorited by userssnooze_time(Array) - Notification snooze settingsdeleted(Boolean) - Soft delete flag
conversations.messagesโ
- Purpose: Message storage with threading
- Model:
shared/models/conversation.message.js - Key Fields:
room_id(ObjectId) - Parent roomconversation_id(ObjectId) - Message authorcontent(String) - Message textsource(String) - 'chat' | 'sms' | 'email'receivers(Array[ObjectId]) - Recipient conversation IDsattachments(Array) - File metadatafavorite(Array) - Favorited by usersreminders(Array) - Reminder settingsdeleted(Boolean) - Soft delete flagdeleted_by(Array[ObjectId]) - User-specific deletion
support.inboxesโ
- Purpose: Support team inbox configuration
- Model:
shared/models/support-inbox.js - Key Fields:
name(String) - Inbox labelmembers(Array[ObjectId]) - Assigned conversation IDsaccount_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 conversationgetConversation(id)- Retrieve conversation by IDqueryTeamConversations(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, paginationcreateRoom(options)- Create direct message or channelupdateRoom(roomId, updates)- Update room metadatadeleteRoom(roomId)- Soft delete roommarkAsRead(roomId, conversationId, lastMessageId)- Update read statusfavoriteRoom(roomId, conversationId)- Toggle favorite statussnoozeRoom(roomId, conversationId, duration)- Snooze notifications
Key Business Logic:
- Unread Filtering: Filters rooms with
unread_count.count > 0for 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_readand resets unread count
Message Serviceโ
File: services/message.service.js (624 lines)
Functions:
getMessageStatus(options)- Query messages with pagination, search, filteringcreateMessage(roomId, conversationId, content, options)- Create new messageupdateMessage(messageId, content)- Edit message contentdeleteMessage(messageId, conversationId)- Soft delete for userfavoriteMessage(messageId, conversationId)- Toggle favorite statusprocessMessage(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_byarray to allow per-user deletion - Cursor Pagination: Uses
upperRefandlowerReffor 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 createdmessage_updated- Message editedmessage_deleted- Message removedroom_created- New room/channelroom_updated- Room metadata changedread_receipt- User read messagestyping_indicator- User is typingstatus_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
membersarray - Support Inbox: User must be assigned to inbox or have
conversation.supportscope
โ๏ธ 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
$lookupwithpreserveNullAndEmptyArrays: 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_idto 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
$facetfor combined queries (data + count) - Caching: Cache room metadata for frequently accessed rooms
๐ Related Documentationโ
- Socket.IO Integration - Real-time events
- SMS Service - Twilio integration
- Email Service - SendGrid integration
- File Storage - Wasabi/S3
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)