Room Controller
Controller: room.controller.js
Module: Conversation-v2
Purpose: Manages chat rooms including direct messages, group chats, room membership, roles, and permissions
Overview
The Room controller handles all room-related operations in the chat system. It supports direct messaging, group chats with role-based permissions (owner/admin/member), favorite rooms, snoozing, chat export, and comprehensive member management.
Methods
1. Get Rooms (getRooms)
Retrieves all rooms accessible to the current user with filtering and pagination.
Endpoint: GET /api/conversation-v2/room
Authentication: Required (JWT + conversation context)
Query Parameters:
{
page?: number; // Page number for pagination
search?: string; // Search room names or participants
status?: string; // Filter by room status
type?: string; // Filter by room type ('direct' | 'group')
}
Request:
GET /api/conversation-v2/room?page=1&type=group&search=project
Authorization: Bearer <token>
Response:
{
"rooms": [
{
"_id": "507f1f77bcf86cd799439011",
"type": "group",
"name": "Project Alpha Team",
"members": [
{
"conversation_id": "507f1f77bcf86cd799439012",
"user": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "https://cdn.example.com/avatars/john.jpg"
},
"role": "owner"
}
],
"last_message": {
"content": "Meeting at 3pm",
"created_at": "2025-10-08T10:30:00.000Z"
},
"unread_count": 3,
"is_favorite": true,
"created_at": "2025-10-01T09:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"pages": 3
}
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
rooms | find | Multiple filters | Get user's rooms |
Business Logic:
- Returns rooms where user is a member or all_member
- Supports search across room names and participant names
- Includes unread message counts per room
- Shows favorite status for current user
Room Types:
direct- 1-on-1 conversationgroup- Multi-participant chat
Use Cases:
- Displaying chat sidebar with all conversations
- Searching for specific chats
- Filtering by room type
2. Create Room (createRoom)
Creates a new chat room (direct message or group chat).
Endpoint: POST /api/conversation-v2/room
Authentication: Required (JWT + conversation context)
Request Body:
{
"type": "group",
"conversation_ids": [
"507f1f77bcf86cd799439012",
"507f1f77bcf86cd799439013",
"507f1f77bcf86cd799439014"
],
"room_name": "Project Alpha Team"
}
Response:
{
"_id": "507f1f77bcf86cd799439011",
"type": "group",
"name": "Project Alpha Team",
"owner": "507f1f77bcf86cd799439012",
"members": [
{
"conversation_id": "507f1f77bcf86cd799439012",
"joined_at": "2025-10-08T10:30:00.000Z"
},
{
"conversation_id": "507f1f77bcf86cd799439013",
"joined_at": "2025-10-08T10:30:00.000Z"
},
{
"conversation_id": "507f1f77bcf86cd799439014",
"joined_at": "2025-10-08T10:30:00.000Z"
}
],
"roles": [
{
"conversation_id": "507f1f77bcf86cd799439012",
"type": "owner"
},
{
"conversation_id": "507f1f77bcf86cd799439013",
"type": "member"
},
{
"conversation_id": "507f1f77bcf86cd799439014",
"type": "member"
}
],
"created_at": "2025-10-08T10:30:00.000Z"
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
rooms | findOne | Check for existing direct room | Prevent duplicates |
rooms | insertOne | New room document | Create room |
Business Logic:
- Creator automatically becomes room owner
- Uses
Setto deduplicate conversation_ids - For direct messages, checks if room already exists between two users
- Group chats always create new room
- Broadcasts room creation via Socket.IO to all members
Room Creation Flow:
graph TD
A[Create Room Request] --> B{Room Type?}
B -->|Direct| C{Room Exists?}
C -->|Yes| D[Return Existing Room]
C -->|No| E[Create New Room]
B -->|Group| E
E --> F[Set Creator as Owner]
F --> G[Add All Members]
G --> H[Broadcast to Members]
H --> I[Return Room Object]
Use Cases:
- Starting new direct message
- Creating team chat rooms
- Project-based group conversations
3. Get Favorites (getFavorites)
Retrieves all rooms marked as favorite by the current user.
Endpoint: GET /api/conversation-v2/room/favorites
Authentication: Required (JWT + conversation context)
Response:
{
"favorites": [
{
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha Team",
"type": "group",
"last_message": {
"content": "Meeting at 3pm",
"created_at": "2025-10-08T10:30:00.000Z"
},
"unread_count": 3
}
]
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
rooms | find | { "favorites": conversation_id } | Get favorited rooms |
Business Logic:
- Returns rooms where current user added to favorites list
- Sorted by last activity (most recent first)
- Includes unread count for each favorite
Use Cases:
- Quick access to important conversations
- Pinned chats at top of list
- Priority inbox view
4. Toggle Favorite (toggleFavorite)
Adds or removes a room from the current user's favorites.
Endpoint: POST /api/conversation-v2/room/:roomId/favorite
Authentication: Required (JWT + conversation context)
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha Team",
"is_favorite": true
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | Toggle favorite | Add/remove from favorites |
Business Logic:
- If already favorited → Remove from favorites array
- If not favorited → Add to favorites array
- Each user can independently favorite/unfavorite rooms
Favorite Data Structure:
// In room document
favorites: [
conversation_id1,
conversation_id2,
// ... more conversation IDs
];
Use Cases:
- Pinning important conversations
- Organizing chat priorities
- Quick access toggles
5. Delete Room (deleteRoom)
Deletes a group chat room (only by owner).
Endpoint: DELETE /api/conversation-v2/room
Authentication: Required (JWT + conversation context)
Query Parameters:
{
roomId: string; // Room to delete
}
Response:
{
"success": true,
"message": "Room deleted successfully"
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
rooms | deleteOne | { _id: roomId } | Delete room |
messages | updateMany | Mark messages deleted | Cleanup |
Business Logic:
- Only room owner can delete
- Deletes room document and all associated messages
- Broadcasts deletion event to all members via Socket.IO
- Cannot delete direct message rooms
Authorization:
graph TD
A[Delete Request] --> B{Verify Ownership}
B -->|Owner| C[Delete Room]
B -->|Not Owner| D[Error: Forbidden]
C --> E[Delete Messages]
E --> F[Broadcast Event]
F --> G[Success Response]
Use Cases:
- Removing obsolete project chats
- Cleaning up old group conversations
- Admin management
6. Leave Room (leaveRoom)
Removes the current user from a group chat.
Endpoint: POST /api/conversation-v2/room/:roomId/leave
Authentication: Required (JWT + conversation context)
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha Team",
"members": [
// Remaining members
]
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | $pull member from arrays | Remove user |
Business Logic:
- Removes user from
membersarray - Removes user from
rolesarray - If owner leaves, ownership transfers to another admin or oldest member
- System message posted: "User left the room"
- Cannot leave direct message rooms
Ownership Transfer Logic:
graph TD
A[Owner Leaves] --> B{Other Admins Exist?}
B -->|Yes| C[Transfer to First Admin]
B -->|No| D{Other Members Exist?}
D -->|Yes| E[Transfer to Oldest Member]
D -->|No| F[Delete Room]
C --> G[Update Owner Field]
E --> G
Use Cases:
- Leaving group conversations
- Removing self from project chats
- Exiting team discussions
7. Add Members (addMembers)
Adds new members to a group chat (owner/admin only).
Endpoint: POST /api/conversation-v2/room/members
Authentication: Required (JWT + conversation context)
Request Body:
{
"roomId": "507f1f77bcf86cd799439011",
"conversation_ids": ["507f1f77bcf86cd799439015", "507f1f77bcf86cd799439016"]
}
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha Team",
"members": [
// All members including new ones
]
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | findOne | Get room | Verify permissions |
rooms | updateOne | $addToSet members | Add new members |
Business Logic:
- Only owner or admin can add members
- Uses
$addToSetto prevent duplicates - New members added with "member" role
- System message posted: "User A added User B, User C"
- Broadcasts update to all room members
Authorization Check:
const userRole = room.roles.find(r => r.conversation_id === currentUserId);
if (userRole.type === 'owner' || userRole.type === 'admin') {
// Authorized to add members
} else {
throw forbidden('Only admins can add members');
}
Use Cases:
- Adding team members to project chats
- Including new employees in discussions
- Expanding group conversation
8. Update Owner (updateOwner)
Transfers room ownership to another member (owner only).
Endpoint: PATCH /api/conversation-v2/room/owner
Authentication: Required (JWT + conversation context)
Request Body:
{
"roomId": "507f1f77bcf86cd799439011",
"conversationId": "507f1f77bcf86cd799439013"
}
Response:
{
"success": true,
"message": "Owner changed"
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | Update owner + roles | Transfer ownership |
Business Logic:
- Only current owner can transfer ownership
- New owner must be existing room member
- Previous owner demoted to "member" role
- New owner gets "owner" role
- System message: "User A transferred ownership to User B"
Ownership Transfer:
graph TD
A[Transfer Request] --> B{Current Owner?}
B -->|Yes| C{Target is Member?}
B -->|No| D[Error: Forbidden]
C -->|Yes| E[Update Owner Field]
C -->|No| F[Error: Not Member]
E --> G[Update Previous Owner Role]
G --> H[Update New Owner Role]
H --> I[System Message]
I --> J[Success Response]
Use Cases:
- Handing off project leadership
- Succession planning
- Organizational changes
9. Update Role (updateRole)
Changes a member's role in the room (owner/admin only).
Endpoint: PATCH /api/conversation-v2/room/role
Authentication: Required (JWT + conversation context)
Request Body:
{
"roomId": "507f1f77bcf86cd799439011",
"conversationId": "507f1f77bcf86cd799439013",
"role": "admin"
}
Response:
{
"success": true,
"message": "Role changed"
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | Update role in roles array | Change member role |
Business Logic:
- Only owner or admin can change roles
- Cannot change owner's role (must use updateOwner)
- Valid roles: "admin", "member"
- System message: "User A promoted User B to admin"
Role Hierarchy:
Owner (1 per room)
└─ Can do everything
└─ Transfer ownership
└─ Delete room
Admin (multiple)
└─ Add/remove members
└─ Change member roles
└─ Update room settings
Member (default)
└─ Send messages
└─ Leave room
└─ View content
Use Cases:
- Promoting members to moderators
- Delegating administrative tasks
- Team structure management
10. Remove Member (removeMember)
Removes a member from the room (owner/admin only).
Endpoint: DELETE /api/conversation-v2/room/:roomId/member
Authentication: Required (JWT + conversation context)
Query Parameters:
{
conversation_id: string; // Member to remove
}
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"members": [
// Remaining members
]
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | findOne | Get room | Verify permissions |
rooms | updateOne | $pull member | Remove user |
Business Logic:
- Only owner or admin can remove members
- Cannot remove the owner
- Removed user loses access to room and messages
- System message: "User A removed User B"
- Internally uses
leaveRoomservice method
Authorization Flow:
graph TD
A[Remove Request] --> B{Requester Role?}
B -->|Owner/Admin| C{Target is Owner?}
B -->|Member| D[Error: Forbidden]
C -->|No| E[Remove Member]
C -->|Yes| F[Error: Cannot Remove Owner]
E --> G[System Message]
G --> H[Broadcast Update]
Error Responses:
{
"error": "Only room owner or admin can remove a user from rooms",
"statusCode": 403
}
Use Cases:
- Removing inactive members
- Moderating disruptive users
- Adjusting team composition
11. Update Room (updateRoom)
Updates room settings like name (owner/admin only).
Endpoint: PATCH /api/conversation-v2/room
Authentication: Required (JWT + conversation context)
Request Body:
{
"roomId": "507f1f77bcf86cd799439011",
"name": "Project Alpha - Q4 2025"
}
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha - Q4 2025",
"updated_at": "2025-10-08T10:30:00.000Z"
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | $set: { name } | Update room name |
Business Logic:
- Only owner or admin can update room settings
- Currently supports name changes
- Validates input with Joi schema
- System message: "User A renamed room to 'New Name'"
- Broadcasts update to all members
Validation Schema:
{
roomId: Joi.string().required(),
name: Joi.string().required()
}
Use Cases:
- Renaming project chats
- Updating room descriptions
- Seasonal naming updates
12. Snooze Room (snooze)
Temporarily mutes notifications from a room until a specified time.
Endpoint: POST /api/conversation-v2/room/:roomId/snooze
Authentication: Required (JWT + conversation context)
Request Body:
{
"time": 1633110000000
}
Response:
{
"success": true,
"room": {
"_id": "507f1f77bcf86cd799439011",
"snoozed_until": {
"conversation_id": "507f1f77bcf86cd799439012",
"time": 1633110000000
}
}
}
MongoDB Operations:
| Collection | Operation | Query/Update | Purpose |
|---|---|---|---|
rooms | updateOne | Update snooze settings | Set mute time |
Business Logic:
- Each user can independently snooze rooms
- Snooze time stored per-user in room document
- Notifications suppressed until timestamp expires
- Can snooze for:
- 30 minutes
- 1 hour
- 8 hours (overnight)
- 24 hours
- Custom time
Snooze Data Structure:
// In room document
snoozed_until: [
{
conversation_id: ObjectId,
time: number, // Unix timestamp
},
];
Snooze Workflow:
graph TD
A[User Snoozes Room] --> B[Store Snooze Time]
B --> C[Message Arrives]
C --> D{Check Snooze Status}
D -->|Active| E[No Notification]
D -->|Expired| F[Send Notification]
E --> G[Increment Unread Count]
F --> G
Use Cases:
- Muting busy group chats during focus time
- Overnight notification silence
- Temporary notification pause
13. Export Chat (exportChat)
Exports all messages from a room to a downloadable format.
Endpoint: GET /api/conversation-v2/room/:roomId/export
Authentication: Required (JWT + conversation context)
Response:
{
"success": true,
"data": {
"room": {
"_id": "507f1f77bcf86cd799439011",
"name": "Project Alpha Team",
"type": "group"
},
"messages": [
{
"sender": "John Doe",
"content": "Hello team",
"timestamp": "2025-10-08T10:30:00.000Z"
},
{
"sender": "Jane Smith",
"content": "Hi John!",
"timestamp": "2025-10-08T10:31:00.000Z"
}
],
"export_date": "2025-10-08T12:00:00.000Z",
"total_messages": 1247
}
}
MongoDB Operations:
| Collection | Operation | Query | Purpose |
|---|---|---|---|
rooms | findOne | Verify access | Check membership |
messages | find | Get all room messages | Export data |
Business Logic:
- Only room members can export
- Returns all non-deleted messages
- Includes message content, sender info, timestamps
- Can be formatted as:
- JSON
- CSV
- PDF (formatted)
- Plain text
Export Format (JSON):
{
"room_name": "Project Alpha Team",
"export_date": "2025-10-08T12:00:00.000Z",
"participants": ["John Doe", "Jane Smith", "Bob Johnson"],
"messages": [
{
"timestamp": "2025-10-08T10:30:00.000Z",
"sender": "John Doe",
"content": "Hello team",
"type": "text"
}
]
}
Use Cases:
- Archiving project conversations
- Compliance/audit requirements
- Backing up important discussions
- Migrating to other platforms
Data Models
Room Schema
{
_id: ObjectId;
type: 'direct' | 'group';
name?: string; // Group chats only
// Ownership & Roles
owner: ObjectId; // Conversation ID of owner
roles: Array<{
conversation_id: ObjectId;
type: 'owner' | 'admin' | 'member';
}>;
// Membership
members: Array<{
conversation_id: ObjectId;
joined_at: Date;
}>;
all_members: Array<{ // Historical members (includes left)
conversation_id: ObjectId;
joined_at: Date;
left_at?: Date;
}>;
// User Preferences (per-user)
favorites: ObjectId[]; // Conversation IDs who favorited
snoozed_until: Array<{
conversation_id: ObjectId;
time: number;
}>;
// Message Tracking (per-user)
last_message_read: Array<{
conversation_id: ObjectId;
message_id: ObjectId;
timestamp: Date;
}>;
// Room Metadata
last_message: {
content: string;
created_at: Date;
sender_id: ObjectId;
};
last_activity: Date;
// Timestamps
created_at: Date;
updated_at: Date;
}
Role Types
| Role | Permissions |
|---|---|
owner | Full control, transfer ownership, delete room |
admin | Add/remove members, change roles, update settings |
member | Send messages, leave room, view content |
Socket.IO Integration
Real-time Events
// Room created
socket.to(accountId).emit('room:created', {
room: roomObject,
});
// Room updated
socket.to(roomId).emit('room:updated', {
room_id: roomId,
update_type: 'name' | 'members' | 'roles',
});
// Member added
socket.to(roomId).emit('room:member_added', {
room_id: roomId,
member: memberObject,
});
// Member removed
socket.to(roomId).emit('room:member_removed', {
room_id: roomId,
conversation_id: removedUserId,
});
Multi-tenant Security
All room operations enforce multi-tenant isolation:
// Rooms belong to accounts
room.account_id === req.auth.account_id;
// Users can only access rooms they're members of
room.members.includes(req.auth.conversation.id);
Performance Considerations
Indexing Requirements
// rooms collection
db.rooms.createIndex({ 'members.conversation_id': 1, account_id: 1 });
db.rooms.createIndex({ favorites: 1 });
db.rooms.createIndex({ last_activity: -1 });
db.rooms.createIndex({ type: 1, account_id: 1 });
Query Optimization
- Room Listing: Index on
members+last_activityfor efficient filtering - Direct Message Check: Compound index on
type+membersarray - Favorites: Index on
favoritesarray for quick lookups
Error Handling
Common Errors
| Status Code | Error | Cause |
|---|---|---|
| 400 | Cannot access this room | User not room member |
| 403 | Only room owner can delete | Not authorized |
| 403 | Only admins can add members | Insufficient permissions |
| 404 | Room does not exist | Invalid room ID |
| 400 | Cannot leave direct message | Direct rooms permanent |
Testing Recommendations
describe('Room Controller', () => {
describe('createRoom', () => {
it('should create group chat', async () => {});
it('should prevent duplicate direct rooms', async () => {});
it('should set creator as owner', async () => {});
});
describe('addMembers', () => {
it('should allow owner to add members', async () => {});
it('should allow admin to add members', async () => {});
it('should reject member adding members', async () => {});
});
describe('leaveRoom', () => {
it('should transfer ownership when owner leaves', async () => {});
it('should delete room if last member leaves', async () => {});
});
});
Last Updated: October 8, 2025
Documented By: AI Documentation System
Source: internal/api/v1/conversation-v2/controllers/room.controller.js