Skip to main content

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:

CollectionOperationQueryPurpose
roomsfindMultiple filtersGet 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 conversation
  • group - 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:

CollectionOperationQueryPurpose
roomsfindOneCheck for existing direct roomPrevent duplicates
roomsinsertOneNew room documentCreate room

Business Logic:

  • Creator automatically becomes room owner
  • Uses Set to 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:

CollectionOperationQueryPurpose
roomsfind{ "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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOneToggle favoriteAdd/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:

CollectionOperationQueryPurpose
roomsdeleteOne{ _id: roomId }Delete room
messagesupdateManyMark messages deletedCleanup

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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOne$pull member from arraysRemove user

Business Logic:

  • Removes user from members array
  • Removes user from roles array
  • 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:

CollectionOperationQuery/UpdatePurpose
roomsfindOneGet roomVerify permissions
roomsupdateOne$addToSet membersAdd new members

Business Logic:

  • Only owner or admin can add members
  • Uses $addToSet to 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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOneUpdate owner + rolesTransfer 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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOneUpdate role in roles arrayChange 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:

CollectionOperationQuery/UpdatePurpose
roomsfindOneGet roomVerify permissions
roomsupdateOne$pull memberRemove 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 leaveRoom service 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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOne$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:

CollectionOperationQuery/UpdatePurpose
roomsupdateOneUpdate snooze settingsSet 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:

CollectionOperationQueryPurpose
roomsfindOneVerify accessCheck membership
messagesfindGet all room messagesExport 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

RolePermissions
ownerFull control, transfer ownership, delete room
adminAdd/remove members, change roles, update settings
memberSend 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

  1. Room Listing: Index on members + last_activity for efficient filtering
  2. Direct Message Check: Compound index on type + members array
  3. Favorites: Index on favorites array for quick lookups

Error Handling

Common Errors

Status CodeErrorCause
400Cannot access this roomUser not room member
403Only room owner can deleteNot authorized
403Only admins can add membersInsufficient permissions
404Room does not existInvalid room ID
400Cannot leave direct messageDirect 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

💬

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