Support Conversation Controller
Controller: support.conversation.controller.js
Module: Conversation-v2
Purpose: Manages customer support chat sessions, token-based authentication for embedded widgets, and OTP verification
Overview
The Support Conversation controller handles customer-facing support chat functionality. It manages support sessions for website visitors, token generation for embedded chat widgets, OTP verification for secure sessions, and support configuration retrieval.
Methods
1. Get Support Conversation (getSupportConv)
Retrieves a support conversation by ID (admin/agent access).
Endpoint: GET /api/conversation-v2/support/conversation/:conv_id
Authentication: Required (JWT - team member)
Response:
{
"_id": "507f1f77bcf86cd799439011",
"account_id": "507f1f77bcf86cd799439012",
"contact_id": "507f1f77bcf86cd799439013",
"type": "support",
"status": "active",
"sessions": [
{
"session_id": "507f1f77bcf86cd799439014",
"device_id": "device_xyz123",
"ip": "192.168.1.100",
"started_at": "2025-10-08T10:30:00.000Z",
"last_activity": "2025-10-08T11:00:00.000Z"
}
],
"created_at": "2025-10-08T10:00:00.000Z"
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
support_conversations | findOne | { _id: conv_id } | Get conversation details |
Business Logic:
- Returns full support conversation with session history
- Used by agents to view customer context
- Includes device and IP tracking for security
Use Cases:
- Agent viewing customer conversation details
- Admin reviewing support interactions
- Debugging support session issues
2. Generate Token (generateToken)
Creates an authentication token for embedding chat widget on external websites.
Endpoint: POST /api/conversation-v2/support/token
Authentication: Required (JWT - admin)
Request Body:
{
"domain": "https://example.com",
"scopes": ["chat", "support"],
"expiry_time": 31536000000
}
Response:
{
"success": true,
"token": {
"_id": "507f1f77bcf86cd799439020",
"account_id": "507f1f77bcf86cd799439012",
"domain": "https://example.com",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"scopes": ["chat", "support"],
"expiry_time": 31536000000,
"created_by": "507f1f77bcf86cd799439013",
"created_at": "2025-10-08T10:30:00.000Z",
"status": "active"
}
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
support_tokens | insertOne | New token | Create auth token |
Business Logic:
- Generates JWT token for public-facing chat widget
- Token scoped to specific domain for security
- Expiry time in milliseconds (default: 1 year)
- Allows widget to authenticate without user credentials
Token Scopes:
chat- Basic chat functionalitysupport- Access to support featuresfile_upload- Allow file attachmentshistory- View chat history
Token Generation Flow:
graph TD
A[Admin Creates Token] --> B[Specify Domain]
B --> C[Set Scopes & Expiry]
C --> D[Generate JWT]
D --> E[Store in Database]
E --> F[Return Token String]
F --> G[Embed in Website]
G --> H[Widget Authenticates]
Security Considerations:
- Tokens domain-locked to prevent misuse
- Short expiry for sensitive scopes
- Tokens can be revoked via
removeToken
Use Cases:
- Embedding support chat on company website
- Mobile app support integration
- Third-party platform chat widgets
3. Regenerate Token (reGenerateToken)
Regenerates an existing token (useful when token compromised).
Endpoint: POST /api/conversation-v2/support/token/regenerate
Authentication: Required (JWT - admin)
Request Body:
{
"id": "507f1f77bcf86cd799439020",
"domain": "https://example.com"
}
Response:
{
"success": true,
"token": {
"_id": "507f1f77bcf86cd799439020",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.NEW_TOKEN...",
"domain": "https://example.com",
"regenerated_at": "2025-10-08T10:30:00.000Z"
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
support_tokens | findOne | { _id: id, account_id } | Get existing token |
support_tokens | updateOne | $set: { token } | Update with new token |
Business Logic:
- Invalidates old token immediately
- Generates new JWT with same settings
- Preserves token ID, domain, and scopes
- Requires re-deployment of widget with new token
When to Regenerate:
- Token leaked or compromised
- Security audit requirements
- Rotating credentials periodically
- Domain ownership change
Use Cases:
- Security incident response
- Token rotation policy
- Domain transfer scenarios
4. Get Token (getToken)
Retrieves all active support tokens for the account.
Endpoint: GET /api/conversation-v2/support/token
Authentication: Required (JWT - admin)
Response:
{
"success": true,
"token": [
{
"_id": "507f1f77bcf86cd799439020",
"domain": "https://example.com",
"scopes": ["chat", "support"],
"status": "active",
"created_at": "2025-10-08T10:30:00.000Z",
"expiry_time": 31536000000,
"last_used": "2025-10-08T11:00:00.000Z"
},
{
"_id": "507f1f77bcf86cd799439021",
"domain": "https://app.example.com",
"scopes": ["chat"],
"status": "active",
"created_at": "2025-10-07T09:00:00.000Z"
}
]
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
support_tokens | find | { account_id } | List all tokens |
Business Logic:
- Returns all tokens for current account
- Includes usage statistics (last_used)
- Shows token status (active/expired)
- Does not return actual token strings (security)
Use Cases:
- Token management dashboard
- Auditing widget deployments
- Reviewing active integrations
5. Remove Token (removeToken)
Deletes a support token, invalidating all widgets using it.
Endpoint: DELETE /api/conversation-v2/support/token/:id
Authentication: Required (JWT - admin)
Response:
{
"success": true,
"message": "Token deleted"
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
support_tokens | deleteOne | { _id: id, account_id } | Remove token |
Business Logic:
- Immediately invalidates token
- All widgets using this token stop working
- Orphaned sessions remain accessible to agents
- Irreversible action (must generate new token)
Impact:
graph TD
A[Admin Deletes Token] --> B[Token Removed from DB]
B --> C[Widget Auth Fails]
C --> D[Visitors See Error]
D --> E[Must Deploy New Token]
Use Cases:
- Removing deprecated widget
- Revoking compromised token
- Shutting down external integration
6. Get Support Conversation (Public) (getSupportConversation)
Creates or retrieves a support session for website visitors (public endpoint).
Endpoint: POST /api/conversation-v2/support/session
Authentication: Support token (from widget)
Headers:
Authorization: Bearer <support_token>
X-Device-ID: device_xyz123
Request Body:
{
"email": "customer@example.com",
"name": "John Doe",
"phone": "+1234567890",
"auth_attr": {
"user_id": "external_user_123",
"custom_field": "value"
}
}
Response:
{
"success": true,
"session": {
"session_id": "507f1f77bcf86cd799439030",
"conversation_id": "507f1f77bcf86cd799439031",
"contact": {
"_id": "507f1f77bcf86cd799439032",
"name": "John Doe",
"email": "customer@example.com",
"phone": "+1234567890"
},
"status": "active",
"requires_verification": false,
"device_id": "device_xyz123",
"created_at": "2025-10-08T10:30:00.000Z"
}
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
contacts | findOneAndUpdate | Upsert by email/phone | Get or create contact |
support_conversations | findOne | Check existing session | Reuse session |
support_conversations | insertOne | New conversation | Create if needed |
support_sessions | insertOne | New session | Create session |
Business Logic:
- Contact matching by email or phone (creates if new)
- Session tracking per device (device_id from header)
- IP address logging for security
- Returns existing session if recent (within 24 hours)
- Custom attributes stored in
auth_attrfor context
Session Creation Flow:
graph TD
A[Visitor Opens Chat] --> B{Email/Phone Provided?}
B -->|Yes| C[Find/Create Contact]
B -->|No| D[Anonymous Session]
C --> E{Existing Session?}
E -->|Yes| F[Return Existing]
E -->|No| G[Create New Session]
D --> G
G --> H[Generate Session ID]
H --> I[Return to Widget]
Contact Matching Logic:
// Priority order:
1. Exact email match
2. Exact phone match
3. Create new contact
Use Cases:
- Website visitor initiating chat
- Mobile app user requesting support
- Authenticated user continuing conversation
7. Get Support Config (getSupportConfig)
Retrieves public support widget configuration.
Endpoint: GET /api/conversation-v2/support/config
Authentication: Support token
Response:
{
"success": true,
"config": {
"widget_settings": {
"theme": "light",
"primary_color": "#007bff",
"position": "bottom-right",
"greeting_message": "Hi! How can we help you today?",
"offline_message": "We're offline. Leave a message!"
},
"features": {
"file_upload": true,
"emoji_picker": true,
"typing_indicators": true,
"read_receipts": true
},
"business_hours": {
"timezone": "America/New_York",
"schedule": {
"monday": { "start": "09:00", "end": "17:00" },
"tuesday": { "start": "09:00", "end": "17:00" }
}
},
"requires_email": false,
"requires_phone": false,
"otp_verification_enabled": false
}
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
support_configs | findOne | { account_id } | Get config |
Business Logic:
- Returns account-specific widget configuration
- Used by widget to customize appearance and behavior
- Determines required fields (email, phone)
- Specifies enabled features
Configuration Categories:
- Widget Settings: Visual appearance
- Features: Functional capabilities
- Business Hours: Availability schedule
- Verification: Security requirements
Use Cases:
- Widget initialization on website
- Customizing chat appearance per brand
- Enforcing data collection requirements
8. Send OTP (sendOTP)
Sends a one-time password for session verification.
Endpoint: POST /api/conversation-v2/support/otp/send
Authentication: Support token + session
Response:
{
"success": true,
"message": "OTP sent successfully"
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
support_sessions | updateOne | Store OTP + expiry | Save verification code |
Business Logic:
- Generates 6-digit OTP code
- Valid for 10 minutes
- Sent via email or SMS (based on contact info)
- Rate limited to prevent abuse (max 3 per hour)
OTP Generation:
const otp = Math.floor(100000 + Math.random() * 900000); // 6 digits
const expiry = Date.now() + 10 * 60 * 1000; // 10 minutes
Delivery Methods:
graph TD
A[Generate OTP] --> B{Contact Has Email?}
B -->|Yes| C[Send Email]
B -->|No| D{Contact Has Phone?}
D -->|Yes| E[Send SMS]
D -->|No| F[Error: No Contact Method]
C --> G[Store in Session]
E --> G
Email Template:
Subject: Your verification code
Your verification code is: 123456
This code will expire in 10 minutes.
Use Cases:
- Verifying customer identity
- Secure support for sensitive issues
- Preventing unauthorized access
9. Verify OTP (verifyOTP)
Validates the OTP code provided by the user.
Endpoint: POST /api/conversation-v2/support/otp/verify
Authentication: Support token + session
Request Body:
{
"code": "123456"
}
Response:
{
"success": true,
"message": "OTP is verified"
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
support_sessions | findOne | Get session with OTP | Validate code |
support_sessions | updateOne | Mark as verified | Update status |
Business Logic:
- Compares provided code with stored OTP
- Checks expiry time (10 minute window)
- Marks session as verified on success
- Clears OTP after successful verification
- Max 3 attempts before generating new OTP
Verification Flow:
graph TD
A[User Enters Code] --> B{Code Matches?}
B -->|Yes| C{Within Time Limit?}
B -->|No| D[Increment Attempts]
C -->|Yes| E[Mark Verified]
C -->|No| F[Error: Expired]
D --> G{Max Attempts?}
G -->|Yes| H[Error: Too Many Attempts]
G -->|No| I[Try Again]
E --> J[Grant Access]
Error Responses:
// Invalid code
{
"error": "Invalid OTP code",
"statusCode": 400
}
// Expired code
{
"error": "OTP has expired",
"statusCode": 400
}
// Too many attempts
{
"error": "Too many failed attempts. Request new OTP.",
"statusCode": 429
}
Use Cases:
- Completing identity verification
- Unlocking verified-only features
- Account-specific support access
Data Models
Support Conversation Schema
{
_id: ObjectId;
account_id: ObjectId;
contact_id: ObjectId; // Linked contact
type: 'support';
// Session Tracking
sessions: Array<{
session_id: ObjectId;
device_id: string;
ip: string;
started_at: Date;
last_activity: Date;
verified: boolean;
}>;
// Authentication
auth_attr: object; // Custom attributes
// Status
status: 'active' | 'closed';
// Timestamps
created_at: Date;
updated_at: Date;
}
Support Token Schema
{
_id: ObjectId;
account_id: ObjectId;
user_id: ObjectId; // Creator
// Token Details
token: string; // JWT string
domain: string; // Allowed origin
scopes: string[]; // Permissions
// Lifecycle
expiry_time: number; // Milliseconds
status: 'active' | 'revoked';
last_used: Date;
// Timestamps
created_at: Date;
regenerated_at?: Date;
}
Support Session Schema
{
_id: ObjectId;
conversation_id: ObjectId;
device_id: string;
ip: string;
// OTP Verification
otp_code?: string;
otp_expiry?: number;
otp_attempts: number;
verified: boolean;
// Status
status: 'active' | 'inactive';
// Timestamps
created_at: Date;
last_activity: Date;
}
Security Considerations
Token Security
- Domain Whitelisting: Tokens only work on specified domains
- Token Rotation: Regular regeneration recommended
- Scope Limitation: Minimal permissions principle
- Revocation: Instant invalidation capability
Session Security
- Device Tracking: Device ID from browser fingerprint
- IP Logging: Fraud detection and security auditing
- Session Expiry: Automatic timeout after inactivity
- OTP Verification: Optional second factor
Rate Limiting
// OTP requests
- Max 3 OTP sends per hour per contact
- Max 3 verification attempts per OTP
// Session creation
- Max 10 sessions per IP per hour
- Max 5 concurrent sessions per device
Integration Points
Widget Integration
<!-- Embed support chat on website -->
<script>
window.supportConfig = {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
position: 'bottom-right',
};
</script>
<script src="https://cdn.example.com/support-widget.js"></script>
Mobile App Integration
// Initialize support session
const session = await fetch('/api/conversation-v2/support/session', {
method: 'POST',
headers: {
Authorization: `Bearer ${supportToken}`,
'X-Device-ID': deviceId,
},
body: JSON.stringify({
email: user.email,
name: user.name,
}),
});
Performance Considerations
Caching Strategy
// Support config cached for 5 minutes
GET /support/config
Cache-Control: public, max-age=300
// Token list not cached (security)
GET /support/token
Cache-Control: no-store
Database Indexing
// support_conversations
db.support_conversations.createIndex({ contact_id: 1, account_id: 1 });
db.support_conversations.createIndex({ 'sessions.device_id': 1 });
// support_tokens
db.support_tokens.createIndex({ account_id: 1, status: 1 });
db.support_tokens.createIndex({ domain: 1 });
// support_sessions
db.support_sessions.createIndex({ conversation_id: 1, device_id: 1 });
Error Handling
| Status Code | Error | Cause |
|---|---|---|
| 400 | Invalid OTP code | Wrong verification code |
| 401 | Invalid support token | Token expired or revoked |
| 403 | Domain not whitelisted | Token domain mismatch |
| 429 | Too many OTP requests | Rate limit exceeded |
Testing Recommendations
describe('Support Conversation Controller', () => {
describe('generateToken', () => {
it('should create token with domain', async () => {});
it('should enforce domain whitelist', async () => {});
});
describe('getSupportConversation', () => {
it('should create new contact and session', async () => {});
it('should reuse existing session', async () => {});
it('should track device and IP', async () => {});
});
describe('OTP flow', () => {
it('should send OTP to email', async () => {});
it('should verify valid OTP', async () => {});
it('should reject expired OTP', async () => {});
it('should enforce rate limits', async () => {});
});
});
Last Updated: October 8, 2025
Documented By: AI Documentation System
Source: internal/api/v1/conversation-v2/controllers/support.conversation.controller.js