Skip to main content

Shared Integration

Namespace: /v1/shared

Purpose: General platform events and notifications broadcasting

Authentication: Required (JWT + scope: conversation)


Socket Events

Client → Server Events

EventDescriptionAuthenticationScope Required
joinJoin shared namespaceRequiredconversation
disconnectUser disconnected (automatic)N/AN/A

Database Models

  • Socket - User socket ID tracking

Schema:

{
user: ObjectId, // User ID (ref: User)
socket_ids: [String], // Array of socket connection IDs
createdAt: Date,
updatedAt: Date
}

Event Details

join

Purpose: Register user connection in shared namespace

Request:

socket.emit('join', {}, callback);

Response:

{ success: true, message: 'SUCCESS' }

Side Effects:

  • Creates or updates Socket document for user
  • Adds socketId to socket_ids array
  • Enables receiving broadcast events

Example:

// On join
const existingDoc = await SocketModel.findOne({ user: uid }).exec();
if (existingDoc) {
await existingDoc.updateOne({ $addToSet: { socket_ids: connectionID } });
} else {
await new SocketModel({ user: uid, socket_ids: [connectionID] }).save();
}

disconnect

Purpose: Clean up socket IDs when user disconnects

Trigger: Automatic when socket disconnects

Side Effects:

  • Removes stale socket IDs from Socket document
  • Keeps only active socket IDs
  • Document remains for future connections

Implementation:

async disconnect(connectionID) {
const socket = await SocketModel.findOne({ socket_ids: connectionID }).exec();
if (!socket) return;

// Get all active sockets
const activeClients = [...this.io.sockets].map(c => c[0]);

// Remove inactive socket IDs
const socketIds = socket.socket_ids || [];
const socketToBeDeleted = socketIds.filter(ID => !activeClients.includes(ID));

await socket.updateOne({ $pullAll: { socket_ids: socketToBeDeleted } });
}

REST API Integration

The Shared namespace is primarily controlled via REST API for broadcasting events:

Emit to Specific User

Endpoint: POST /emit/:userId/:emitTo

Purpose: Send event to single user

Request:

POST /emit/64abc123def456789/notification
Content-Type: application/json

{
"title": "New Lead",
"message": "You have a new lead from John Doe",
"type": "lead",
"data": {
"lead_id": "64lead...",
"contact_name": "John Doe"
}
}

Response:

{ success: true, message: 'SUCCESS' }

Controller Logic:

exports.emit = async (req, res, next) => {
const io = req.io; // sharedIo namespace
const userID = req.params.userId;
const payload = req.body;
const emitTo = req.params.emitTo; // Event name

// Find user's socket IDs
let socketIds = await SocketModel.findOne({ user: userID }, { socket_ids: true }).lean().exec();

// Emit to all user's sockets
if (socketIds) {
for (const socketID of socketIds.socket_ids || []) {
io.to(socketID).emit(emitTo, payload);
}
}

return res.status(200).json({ success: true, message: 'SUCCESS' });
};

Emit to Multiple Users

Endpoint: POST /emit/:emitTo

Purpose: Broadcast event to multiple users

Request:

POST /emit/system_announcement
Content-Type: application/json

{
"userIds": ["64abc...", "64def...", "64ghi..."],
"data": {
"title": "System Maintenance",
"message": "Scheduled maintenance on Monday 2AM-4AM",
"priority": "high"
}
}

Response:

{ success: true, message: 'SUCCESS' }

Controller Logic:

exports.emitMultiple = async (req, res, next) => {
const io = req.io;
const payload = req.body.data;
const emitTo = req.params.emitTo;
let userIDs = req.body.userIds;

// Handle JSON string input
if (typeof userIDs === 'string' && userIDs.includes('[')) {
userIDs = JSON.parse(userIDs);
}

// Find all users' socket IDs
let socketIds = await SocketModel.find(
{
user: Array.isArray(userIDs)
? { $in: userIDs.map(id => new mongoose.Types.ObjectId(id)) }
: new mongoose.Types.ObjectId(userIDs),
},
{ socket_ids: true },
)
.lean()
.exec();

// Emit to all sockets
if (socketIds) {
for (const sockets of socketIds || []) {
for (const socketID of sockets.socket_ids || []) {
io.to(socketID).emit(emitTo, payload);
}
}
}

return res.status(200).json({ success: true, message: 'SUCCESS' });
};

Use Cases

1. Real-Time Notifications

Scenario: New lead assigned to user

// Internal API - when lead assigned
await axios.post('http://general-socket:4000/emit/64user.../notification', {
title: 'New Lead Assigned',
message: 'John Doe has been assigned to you',
type: 'lead_assigned',
data: {
lead_id: '64lead...',
lead_name: 'John Doe',
assigned_by: 'Manager Name',
},
timestamp: new Date().toISOString(),
});

2. System Announcements

Scenario: Broadcast maintenance notice

// Internal API - system announcement
const allActiveUsers = await User.find({ status: 'active' }).distinct('_id');

await axios.post('http://general-socket:4000/emit/system_announcement', {
userIds: allActiveUsers,
data: {
title: 'Scheduled Maintenance',
message: 'System will be down Monday 2AM-4AM EST',
priority: 'high',
action_url: '/maintenance-info',
},
});

3. Data Sync Events

Scenario: Notify users of data updates

// External API - after webhook processes data
await axios.post('http://general-socket:4000/emit/data_sync', {
userIds: [workspace.owner_id],
data: {
type: 'google_ads_sync_complete',
account_id: '64acc...',
campaigns_synced: 15,
timestamp: new Date().toISOString(),
},
});

4. Collaboration Events

Scenario: User mentions another user in comment

// Internal API - when user @mentions another
await axios.post(`http://general-socket:4000/emit/${mentionedUserId}/mention`, {
type: 'comment_mention',
source: 'project_task',
task_id: '64task...',
task_title: 'Design Homepage',
mentioned_by: {
id: currentUserId,
name: 'John Smith',
},
comment: 'Hey @Sarah, can you review this design?',
});

Client Example

import io from 'socket.io-client';

const sharedSocket = io('http://localhost:4000/v1/shared', {
transports: ['websocket'],
query: { token: 'your_jwt_token' },
});

// Join shared namespace
sharedSocket.emit('join', {}, response => {
console.log('Joined shared namespace:', response);
});

// Listen for notifications
sharedSocket.on('notification', data => {
console.log('Notification:', data);
// Show toast notification
showToast(data.title, data.message, data.type);
});

// Listen for system announcements
sharedSocket.on('system_announcement', data => {
console.log('System announcement:', data);
// Show banner
showBanner(data.data.title, data.data.message, data.data.priority);
});

// Listen for data sync events
sharedSocket.on('data_sync', data => {
console.log('Data sync:', data);
// Refresh UI component
if (data.type === 'google_ads_sync_complete') {
refreshGoogleAdsData();
}
});

// Listen for mentions
sharedSocket.on('mention', data => {
console.log('You were mentioned:', data);
// Show notification + navigate
showMentionNotification(data);
});

// Listen for custom events
sharedSocket.on('custom_event', data => {
console.log('Custom event:', data);
// Handle custom logic
});

Event Naming Conventions

Recommended event names:

  • notification - General notifications
  • system_announcement - Platform-wide announcements
  • data_sync - Data synchronization events
  • mention - User mentions
  • task_update - Task/project updates
  • deal_update - CRM deal updates
  • lead_update - New/updated leads
  • report_ready - Report generation complete
  • export_complete - Data export finished
  • alert - Urgent alerts
  • reminder - Task/event reminders

Best Practices

  1. Event Naming: Use descriptive, consistent event names
  2. Payload Structure: Keep consistent data structure across events
  3. Timestamp: Always include timestamp in payload
  4. Type Field: Include event type for client-side routing
  5. Batch Emits: For multiple users, use emitMultiple endpoint
  6. Error Handling: Handle user offline scenarios gracefully
  7. Testing: Test with multiple user connections

Performance Considerations

  1. Large User Lists: For more than 100 users, consider batch processing
  2. Payload Size: Keep payloads small (less than 1KB recommended)
  3. Rate Limiting: Implement limits on emit frequency per user
  4. Socket Cleanup: Regularly clean up inactive socket IDs
  5. Monitoring: Track emit success/failure rates

Security Considerations

  1. Authentication Required: All connections must be authenticated
  2. Scope Verification: conversation scope required
  3. Payload Validation: Validate all incoming data
  4. User Isolation: Ensure users only receive their own events
  5. Sensitive Data: Avoid sending sensitive data in broadcasts
💬

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