diff --git a/src/config/telephony.defaults.ts b/src/config/telephony.defaults.ts index 1aec702..e28751f 100644 --- a/src/config/telephony.defaults.ts +++ b/src/config/telephony.defaults.ts @@ -62,7 +62,8 @@ export const DEFAULT_TELEPHONY_CONFIG: TelephonyConfig = { // Field-by-field mapping from legacy env var names to config paths. Used by // the first-boot seeder. Keep in sync with the migration target sites. export const TELEPHONY_ENV_SEEDS: Array<{ env: string; path: string[] }> = [ - { env: 'OZONETEL_AGENT_ID', path: ['ozonetel', 'agentId'] }, + // OZONETEL_AGENT_ID removed — agentId is per-user on the Agent entity, + // not a sidecar-level config. All endpoints require agentId from caller. { env: 'OZONETEL_AGENT_PASSWORD', path: ['ozonetel', 'agentPassword'] }, { env: 'OZONETEL_DID', path: ['ozonetel', 'did'] }, { env: 'OZONETEL_SIP_ID', path: ['ozonetel', 'sipId'] }, diff --git a/src/maint/maint.controller.ts b/src/maint/maint.controller.ts index 1003461..0a2349d 100644 --- a/src/maint/maint.controller.ts +++ b/src/maint/maint.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Post, UseGuards, Logger } from '@nestjs/common'; +import { Body, Controller, HttpException, Post, UseGuards, Logger } from '@nestjs/common'; import { MaintGuard } from './maint.guard'; import { OzonetelAgentService } from '../ozonetel/ozonetel-agent.service'; import { PlatformGraphqlService } from '../platform/platform-graphql.service'; @@ -22,11 +22,14 @@ export class MaintController { ) {} @Post('force-ready') - async forceReady() { + async forceReady(@Body() body: { agentId: string }) { + if (!body?.agentId) throw new HttpException('agentId required', 400); + const agentId = body.agentId; const oz = this.telephony.getConfig().ozonetel; - const agentId = oz.agentId || 'agent3'; - const password = oz.agentPassword || 'Test123$'; - const sipId = oz.sipId || '521814'; + const password = oz.agentPassword; + if (!password) throw new HttpException('agent password not configured', 400); + const sipId = oz.sipId; + if (!sipId) throw new HttpException('SIP ID not configured', 400); this.logger.log(`[MAINT] Force ready: agent=${agentId}`); @@ -48,8 +51,9 @@ export class MaintController { } @Post('unlock-agent') - async unlockAgent() { - const agentId = this.telephony.getConfig().ozonetel.agentId || 'agent3'; + async unlockAgent(@Body() body: { agentId: string }) { + if (!body?.agentId) throw new HttpException('agentId required', 400); + const agentId = body.agentId; this.logger.log(`[MAINT] Unlock agent session: ${agentId}`); try { diff --git a/src/ozonetel/ozonetel-agent.controller.ts b/src/ozonetel/ozonetel-agent.controller.ts index 3a83f51..8a89bff 100644 --- a/src/ozonetel/ozonetel-agent.controller.ts +++ b/src/ozonetel/ozonetel-agent.controller.ts @@ -20,15 +20,9 @@ export class OzonetelAgentController { private readonly supervisor: SupervisorService, ) {} - // Read-through accessors so admin updates take effect immediately. - private get defaultAgentId(): string { - return this.telephony.getConfig().ozonetel.agentId || 'agent3'; - } - private get defaultAgentPassword(): string { - return this.telephony.getConfig().ozonetel.agentPassword; - } - private get defaultSipId(): string { - return this.telephony.getConfig().ozonetel.sipId || '521814'; + private requireAgentId(agentId: string | undefined | null): string { + if (!agentId) throw new HttpException('agentId required', 400); + return agentId; } @Post('agent-login') @@ -67,17 +61,18 @@ export class OzonetelAgentController { @Post('agent-state') async agentState( - @Body() body: { state: 'Ready' | 'Pause'; pauseReason?: string }, + @Body() body: { agentId: string; state: 'Ready' | 'Pause'; pauseReason?: string }, ) { if (!body.state) { throw new HttpException('state required', 400); } + const agentId = this.requireAgentId(body.agentId); - this.logger.log(`[AGENT-STATE] ${this.defaultAgentId} → ${body.state} (${body.pauseReason ?? 'none'})`); + this.logger.log(`[AGENT-STATE] ${agentId} → ${body.state} (${body.pauseReason ?? 'none'})`); try { const result = await this.ozonetelAgent.changeAgentState({ - agentId: this.defaultAgentId, + agentId, state: body.state, pauseReason: body.pauseReason, }); @@ -86,7 +81,7 @@ export class OzonetelAgentController { // Auto-assign missed call when agent goes Ready if (body.state === 'Ready') { try { - const assigned = await this.missedQueue.assignNext(this.defaultAgentId); + const assigned = await this.missedQueue.assignNext(agentId); if (assigned) { this.logger.log(`[AGENT-STATE] Auto-assigned missed call ${assigned.id}`); return { ...result, assignedCall: assigned }; @@ -112,7 +107,7 @@ export class OzonetelAgentController { @Body() body: { ucid: string; disposition: string; - agentId?: string; + agentId: string; callerPhone?: string; direction?: string; durationSec?: number; @@ -125,7 +120,7 @@ export class OzonetelAgentController { throw new HttpException('ucid and disposition required', 400); } - const agentId = body.agentId ?? this.defaultAgentId; + const agentId = this.requireAgentId(body.agentId); const ozonetelDisposition = this.mapToOzonetelDisposition(body.disposition); // Cancel the ACW auto-dispose timer — the frontend submitted disposition @@ -200,7 +195,7 @@ export class OzonetelAgentController { // Auto-assign next missed call to this agent try { - await this.missedQueue.assignNext(this.defaultAgentId); + await this.missedQueue.assignNext(agentId); } catch (err) { this.logger.warn(`Auto-assignment after dispose failed: ${err}`); } @@ -209,7 +204,7 @@ export class OzonetelAgentController { this.eventBus.emit(Topics.CALL_COMPLETED, { callId: null, ucid: body.ucid, - agentId: this.defaultAgentId, + agentId, callerPhone: body.callerPhone ?? '', direction: body.direction ?? 'INBOUND', durationSec: body.durationSec ?? 0, @@ -224,13 +219,13 @@ export class OzonetelAgentController { @Post('dial') async dial( - @Body() body: { phoneNumber: string; agentId?: string; campaignName?: string; leadId?: string }, + @Body() body: { phoneNumber: string; agentId: string; campaignName?: string; leadId?: string }, ) { if (!body.phoneNumber) { throw new HttpException('phoneNumber required', 400); } - const agentId = body.agentId ?? this.defaultAgentId; + const agentId = this.requireAgentId(body.agentId); const did = this.telephony.getConfig().ozonetel.did; const campaignName = body.campaignName || this.telephony.getConfig().ozonetel.campaignName @@ -323,7 +318,7 @@ export class OzonetelAgentController { @Get('performance') async performance(@Query('date') date?: string, @Query('agentId') agentId?: string) { - const agent = agentId ?? this.defaultAgentId; + const agent = this.requireAgentId(agentId); const targetDate = date ?? new Date().toISOString().split('T')[0]; this.logger.log(`Performance: date=${targetDate} agent=${agent}`);