From c3a3df704e5a23a51a03ee5f37141afb7fa1ca8d Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Wed, 18 Mar 2026 16:49:13 +0530 Subject: [PATCH] feat: Implement real-time message delivery for conversations via WebSocket integration and update admin seed email. --- prisma/seed.ts | 2 +- src/messages/messages.controller.ts | 24 ++++++++++++++++++++++-- src/messages/messages.gateway.ts | 15 ++++++++------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/prisma/seed.ts b/prisma/seed.ts index 108f245..abc1613 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1317,7 +1317,7 @@ async function main() { // ============================================= console.log('👤 Seeding Admin User...'); - const adminEmail = process.env.ADMIN_EMAIL || 'admin@realestate.com'; + const adminEmail = process.env.ADMIN_EMAIL || 'admin@re-quest.com'; const adminPassword = process.env.ADMIN_PASSWORD || 'Admin@123456'; // Hash password with Argon2 (more secure than bcrypt) diff --git a/src/messages/messages.controller.ts b/src/messages/messages.controller.ts index 76178e5..b2aa024 100644 --- a/src/messages/messages.controller.ts +++ b/src/messages/messages.controller.ts @@ -20,6 +20,7 @@ import { ApiParam, } from '@nestjs/swagger'; import { MessagesService } from './messages.service'; +import { MessagesGateway } from './messages.gateway'; import { CreateMessageDto, StartConversationDto } from './dto'; import { JwtAuthGuard } from '../auth/guards'; import { CurrentUser } from '../auth/decorators'; @@ -30,7 +31,10 @@ import { UserRole } from '@prisma/client'; @UseGuards(JwtAuthGuard) @ApiBearerAuth('JWT-auth') export class MessagesController { - constructor(private readonly messagesService: MessagesService) {} + constructor( + private readonly messagesService: MessagesService, + private readonly messagesGateway: MessagesGateway, + ) {} // ========================================== // GET CONVERSATIONS LIST @@ -177,7 +181,23 @@ export class MessagesController { @CurrentUser('id') userId: string, @Body() dto: CreateMessageDto, ) { - return this.messagesService.createMessage(conversationId, userId, dto); + const message = await this.messagesService.createMessage(conversationId, userId, dto); + + // Broadcast via WebSocket so the other party gets real-time delivery + try { + const participants = await this.messagesService.getConversationParticipants(conversationId); + if (participants) { + const otherUserId = userId === participants.userId + ? participants.agentUserId + : participants.userId; + // Send to the other participant's socket(s) + this.messagesGateway.sendToUser(otherUserId, 'new_message', message); + } + } catch { + // Socket broadcast failure shouldn't fail the REST response + } + + return message; } // ========================================== diff --git a/src/messages/messages.gateway.ts b/src/messages/messages.gateway.ts index 82ef9b9..830cf08 100644 --- a/src/messages/messages.gateway.ts +++ b/src/messages/messages.gateway.ts @@ -175,13 +175,8 @@ export class MessagesGateway implements OnGatewayConnection, OnGatewayDisconnect data.message, ); - // Broadcast to other clients in the conversation room (exclude sender) - client - .to(`conversation:${data.conversationId}`) - .emit('new_message', message); - - // Also send directly to the other participant's socket(s) - // so they receive the message even if they haven't joined this room + // Send directly to the other participant's socket(s) + // This is the primary delivery mechanism — works even if they haven't joined the room try { const participants = await this.messagesService.getConversationParticipants(data.conversationId); if (participants) { @@ -194,6 +189,12 @@ export class MessagesGateway implements OnGatewayConnection, OnGatewayDisconnect this.logger.warn(`Failed to get participants for direct delivery in ${data.conversationId}: ${participantError.message}`); } + // Also broadcast to the conversation room as a fallback + // (client.to excludes sender; recipients dedup by message ID) + client + .to(`conversation:${data.conversationId}`) + .emit('new_message', message); + return { success: true, message }; } catch (error) { return { error: error.message };