diff --git a/backend/src/voice/voice.controller.ts b/backend/src/voice/voice.controller.ts index 17ed440..15178ed 100644 --- a/backend/src/voice/voice.controller.ts +++ b/backend/src/voice/voice.controller.ts @@ -164,25 +164,40 @@ export class VoiceController { this.logger.log(`Full body: ${JSON.stringify(body)}`); try { - // Extract tenant domain from phone number mapping - // For now, we'll need to determine which tenant owns this phone number - // TODO: Add phone number to tenant mapping in database + // Extract tenant domain from Host header + const host = req.headers.host || ''; + const tenantDomain = host.split('.')[0]; // e.g., "tenant1" from "tenant1.routebox.co" - // For multi-tenant, we need to route to the correct user's browser Device - // The Device identity is the userId we used when generating the access token + this.logger.log(`Extracted tenant domain: ${tenantDomain}`); + + // Get all connected users for this tenant + const connectedUsers = this.voiceGateway.getConnectedUsers(tenantDomain); - // For now, let's dial ALL connected clients (you can refine this later) - // Using a simple approach: dial the most recently connected user + this.logger.log(`Connected users for tenant ${tenantDomain}: ${connectedUsers.length}`); + + if (connectedUsers.length === 0) { + // No users online - send to voicemail or play message + const twiml = ` + + Sorry, no agents are currently available. Please try again later. + +`; + this.logger.log(`No users online - returning unavailable message`); + return res.type('text/xml').send(twiml); + } + + // Build TwiML to dial all connected clients (first to answer gets the call) + const clientElements = connectedUsers.map(userId => ` ${userId}`).join('\n'); const twiml = ` Connecting your call - - e6d45fa3-a108-4085-81e5-a8e05e85e6fb + +${clientElements} `; - this.logger.log(`Returning inbound TwiML - dialing Client`); + this.logger.log(`Returning inbound TwiML - dialing ${connectedUsers.length} client(s)`); res.type('text/xml').send(twiml); } catch (error: any) { this.logger.error(`Error generating inbound TwiML: ${error.message}`); diff --git a/backend/src/voice/voice.gateway.ts b/backend/src/voice/voice.gateway.ts index 231effc..cf7daba 100644 --- a/backend/src/voice/voice.gateway.ts +++ b/backend/src/voice/voice.gateway.ts @@ -290,4 +290,20 @@ export class VoiceGateway socket.emit('ai:action', data); } } + + /** + * Get connected users for a tenant + */ + getConnectedUsers(tenantDomain?: string): string[] { + const userIds: string[] = []; + + for (const [userId, socket] of this.connectedUsers.entries()) { + // If tenantDomain specified, filter by tenant + if (!tenantDomain || socket.tenantSlug === tenantDomain) { + userIds.push(userId); + } + } + + return userIds; + } }