From eb1619c56c4f8d8a468feffbd51104e0304237d4 Mon Sep 17 00:00:00 2001 From: Francisco Gaona Date: Thu, 5 Feb 2026 03:02:02 +0100 Subject: [PATCH] WIP - fix AI suggestions during call progress --- backend/src/tenant/tenant.controller.ts | 63 +++++++++++++++---------- backend/src/voice/voice.service.ts | 18 +++++-- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/backend/src/tenant/tenant.controller.ts b/backend/src/tenant/tenant.controller.ts index da8ebc2..ba47918 100644 --- a/backend/src/tenant/tenant.controller.ts +++ b/backend/src/tenant/tenant.controller.ts @@ -16,26 +16,45 @@ import { TenantId } from './tenant.decorator'; export class TenantController { constructor(private readonly tenantDbService: TenantDatabaseService) {} + /** + * Helper to find tenant by ID or domain + */ + private async findTenant(identifier: string) { + const centralPrisma = getCentralPrisma(); + + // Check if identifier is a CUID (tenant ID) or a domain + const isCUID = /^c[a-z0-9]{24}$/i.test(identifier); + + if (isCUID) { + // Look up by tenant ID directly + return centralPrisma.tenant.findUnique({ + where: { id: identifier }, + select: { id: true, integrationsConfig: true }, + }); + } else { + // Look up by domain + const domainRecord = await centralPrisma.domain.findUnique({ + where: { domain: identifier }, + include: { tenant: { select: { id: true, integrationsConfig: true } } }, + }); + return domainRecord?.tenant; + } + } + /** * Get integrations configuration for the current tenant */ @Get('integrations') - async getIntegrationsConfig(@TenantId() domain: string) { - const centralPrisma = getCentralPrisma(); - - // Look up tenant by domain - const domainRecord = await centralPrisma.domain.findUnique({ - where: { domain }, - include: { tenant: { select: { id: true, integrationsConfig: true } } }, - }); + async getIntegrationsConfig(@TenantId() tenantIdentifier: string) { + const tenant = await this.findTenant(tenantIdentifier); - if (!domainRecord?.tenant || !domainRecord.tenant.integrationsConfig) { + if (!tenant || !tenant.integrationsConfig) { return { data: null }; } // Decrypt the config const config = this.tenantDbService.decryptIntegrationsConfig( - domainRecord.tenant.integrationsConfig as any, + tenant.integrationsConfig as any, ); // Return config with sensitive fields masked @@ -49,31 +68,26 @@ export class TenantController { */ @Put('integrations') async updateIntegrationsConfig( - @TenantId() domain: string, + @TenantId() tenantIdentifier: string, @Body() body: { integrationsConfig: any }, ) { const { integrationsConfig } = body; - if (!domain) { - throw new Error('Domain is missing from request'); + if (!tenantIdentifier) { + throw new Error('Tenant identifier is missing from request'); } - // Look up tenant by domain - const centralPrisma = getCentralPrisma(); - const domainRecord = await centralPrisma.domain.findUnique({ - where: { domain }, - include: { tenant: { select: { id: true, integrationsConfig: true } } }, - }); + const tenant = await this.findTenant(tenantIdentifier); - if (!domainRecord?.tenant) { - throw new Error(`Tenant with domain ${domain} not found`); + if (!tenant) { + throw new Error(`Tenant with identifier ${tenantIdentifier} not found`); } // Merge with existing config to preserve masked values let finalConfig = integrationsConfig; - if (domainRecord.tenant.integrationsConfig) { + if (tenant.integrationsConfig) { const existingConfig = this.tenantDbService.decryptIntegrationsConfig( - domainRecord.tenant.integrationsConfig as any, + tenant.integrationsConfig as any, ); // Replace masked values with actual values from existing config @@ -86,8 +100,9 @@ export class TenantController { ); // Update in database + const centralPrisma = getCentralPrisma(); await centralPrisma.tenant.update({ - where: { id: domainRecord.tenant.id }, + where: { id: tenant.id }, data: { integrationsConfig: encryptedConfig as any, }, diff --git a/backend/src/voice/voice.service.ts b/backend/src/voice/voice.service.ts index a2eccf5..244cf0f 100644 --- a/backend/src/voice/voice.service.ts +++ b/backend/src/voice/voice.service.ts @@ -478,20 +478,28 @@ export class VoiceService { const { callSid, tenantId, userId } = params; try { - // Get OpenAI config - tenantId might be a domain, so look it up + // Get OpenAI config - tenantId might be a domain or a tenant ID (UUID or CUID) const centralPrisma = getCentralPrisma(); - // Try to find tenant by domain first (if tenantId is like "tenant1") + // Detect if tenantId looks like an ID (UUID or CUID) or a domain name + // UUIDs: 8-4-4-4-12 hex format + // CUIDs: 25 character alphanumeric starting with 'c' + const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(tenantId); + const isCUID = /^c[a-z0-9]{24}$/i.test(tenantId); + const isId = isUUID || isCUID; + let tenant; - if (!tenantId.match(/^[0-9a-f]{8}-[0-9a-f]{4}-/i)) { - // Looks like a domain, not a UUID + if (!isId) { + // Looks like a domain, not an ID + this.logger.log(`Looking up tenant by domain: ${tenantId}`); const domainRecord = await centralPrisma.domain.findUnique({ where: { domain: tenantId }, include: { tenant: { select: { id: true, integrationsConfig: true } } }, }); tenant = domainRecord?.tenant; } else { - // It's a UUID + // It's an ID (UUID or CUID) + this.logger.log(`Looking up tenant by ID: ${tenantId}`); tenant = await centralPrisma.tenant.findUnique({ where: { id: tenantId }, select: { id: true, integrationsConfig: true },