GoWeBaKnowledge Center

LA BIBLIA DE LA PLATAFORMA UNIFICADA — ADDENDUM 06

Migración × Contactos × WebaBox — Gestor Multi-Contacto

Versión: 1.0
Fecha: 6 de junio de 2026
Autor: Alain Bessette, CFO/Product Owner, ABI Conglomerate
Dominio: GoWeBa.com
Estado: Addendum Estratégico Oficial — Especificación Vinculante
Restricciones: CERO pérdida de datos · CERO restablecimiento forzado · CERO interrupción en el envío/recepción de correos


⚠️ AVISO CRÍTICO
Este addendum tiene la MISMA autoridad que la Parte 1, la Parte 2 y todos los Addendums anteriores de la Biblia.
Todos los cambios descritos aquí están desplegados en producción y registrados como puntos de control.
No se realizaron cambios que rompan el esquema. Todas las modificaciones son compatibles con versiones anteriores.

📋 TABLA DE CONTENIDOS

  1. Fase A — Corrección de Categoría WebaBox
  2. Fase B.1 — Botón Eliminar en Migración
  3. Fase B.2 — Desconexión de Cuenta Google
  4. Fase B.3 — Enriquecimiento Automático Durante la Migración
  5. Fase B.4 — Motor de Clasificación WebaCategory + Archivado a 90 Días
  6. Fase C.1 — Pestaña Línea de Tiempo del Contacto
  7. Fase C.2 — Pestaña Archivos Adjuntos (Código de Color + Vista Previa + Pantalla Completa)
  8. Fase C.3 — Pestaña Registro de Fusiones
  9. Fase C.4 — Pestaña Análisis de IA
  10. Fase D — Enriquecimiento por Lotes Post-Migración y Verificación
  11. Fase E — Gestor Multi-Contacto (Enriquecimiento Relacional + Seguridad en Fusiones)
  12. Correcciones de Errores
  13. Archivos Modificados — Inventario Completo
  14. Cronología de Puntos de Control

<a id="phase-a"></a>

SECCIÓN 1: FASE A — CORRECCIÓN DE CATEGORÍA WEBABOX

1.1 Descripción del Problema

La API PATCH de WebaBox (/api/inbox/threads/[id]) estaba asignando webaCategory: 'CONVERSATIONS' cuando un usuario respondía a un hilo URGENT. Sin embargo, CONVERSATIONS no es un valor válido en el enum WebaCategory.

Valores válidos del enum: URGENT, IMPORTANT, JOURNAL, OFFICE, NONE.

1.2 Causa Raíz

En webabox-client.tsx, el manejador de respuestas tenía codificado de forma fija webaCategory: 'CONVERSATIONS' en lugar del valor correcto webaCategory: 'NONE'.

1.3 Corrección Aplicada

Archivo: app/(app)/webabox/webabox-client.tsx
Cambio: webaCategory: 'CONVERSATIONS' → webaCategory: 'NONE'

1.4 Comportamiento Después de la Corrección

AcciónAntesDespués
Responder a un hilo URGENTEl hilo se mueve a "Conversations" con categoría inválidaEl hilo se mueve al filtro Conversations (NONE + messageCount > 1)
Contadores de tarjetas WebaBoxPodían mostrar conteos fantasmaConteos precisos en las 12 tarjetas

1.5 Aclaración Clave — Arquitectura de 12 Tarjetas WebaBox

Las 12 tarjetas WebaBox utilizan 5 valores de BD + 7 filtros inteligentes:

TarjetaFuente
UrgentwebaCategory = URGENT
ImportantwebaCategory = IMPORTANT
JournalwebaCategory = JOURNAL
OfficewebaCategory = OFFICE
NonewebaCategory = NONE Y messageCount = 1
ConversationswebaCategory = NONE Y messageCount > 1
Reply LaterisReplyLater = true
Set AsideisSetAside = true
StarredisStarred = true
SpamisSpam = true
TrashdeletedAt IS NOT NULL
All EmailsTodos los hilos no eliminados

<a id="phase-b1"></a>

SECCIÓN 2: FASE B.1 — BOTÓN ELIMINAR EN MIGRACIÓN

2.1 Descripción del Problema

El botón Eliminar en las tarjetas de proyectos de migración solo era visible para los estados CREATED, COMPLETED, FAILED y CANCELLED. Los proyectos con estado IMPORTING, SCANNING o PLANNING no mostraban el botón Eliminar, dejando a los usuarios sin posibilidad de cancelar una migración bloqueada.

2.2 Cambios Aplicados

Frontend — app/(app)/migration/migration-client.tsx

// Antes
const canDelete = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED'].includes(project.status);

// Después
const canDelete = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED', 'IMPORTING', 'SCANNING', 'PLANNING'].includes(project.status);

Backend — app/api/migration/projects/[id]/route.ts

// Antes
const deletableStatuses = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED'];

// Después
const deletableStatuses = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED', 'IMPORTING', 'SCANNING', 'PLANNING'];

2.3 Resultado

Los usuarios ahora pueden eliminar proyectos de migración en cualquier estado, incluyendo importaciones activas.


<a id="phase-b2"></a>

SECCIÓN 3: FASE B.2 — DESCONEXIÓN DE CUENTA GOOGLE

Ya existía en la plataforma. El botón Desconectar era funcional en la página de Migración. No se requirieron cambios.


<a id="phase-b3"></a>

SECCIÓN 4: FASE B.3 — ENRIQUECIMIENTO AUTOMÁTICO DURANTE LA MIGRACIÓN

4.1 Descripción General

Cuando los contactos se importan durante una migración de Google Workspace, el sistema ahora los enriquece automáticamente mediante:

  1. Creación/vinculación de registros CompanyContact basados en el nombre de la empresa o el dominio del correo electrónico
  2. Creación de vínculos ContactCompanyRole entre Contact y CompanyContact
  3. Análisis de firmas de correo electrónico mediante LLM para extraer datos adicionales

4.2 Nuevas Funciones

Archivo: lib/migration/migration-actions.ts

enrichContactPostCreation(contactId, normalizedContact, organizationId, userId)

  • Disparador: Se llama de forma asíncrona (fire-and-forget) después de createContactEntity() en el flujo de ejecución de la migración
  • Lógica:
    1. Si companyName está presente → buscar o crear CompanyContact (coincidencia por nombre sin distinción de mayúsculas/minúsculas O dominio de correo)
    2. Extraer dominio del correo, omitir proveedores genéricos (gmail, yahoo, hotmail, etc.)
    3. Crear vínculo ContactCompanyRole con jobTitle como rol
  • Manejo de errores: Fire-and-forget — los fallos se registran pero nunca interrumpen la migración

analyzeSignatureWithLLM(bodyHtml, bodyText)

  • Propósito: Extraer datos estructurados de firmas de correo electrónico
  • Modelo: primary (gpt-4.1) mediante el wrapper LLM de WEBA
  • Campos extraídos:
    • jobTitle
    • companyName
    • phone
    • website
    • address
    • bookingUrl ← NUEVO (Calendly, Cal.com, HubSpot meetings, Acuity, etc.)
  • Estrategia: Toma los últimos 600 caracteres del cuerpo del correo como bloque de firma
  • Salida: Respuesta JSON analizada, devuelve null si no se encuentran datos útiles

4.3 Punto de Integración

Archivo: app/api/migration/projects/[id]/execute/route.ts

// Después de createContactEntity()
enrichContactPostCreation(contact.id, normalized, organizationId, userId).catch(() => {});

<a id="phase-b4"></a>

SECCIÓN 5: FASE B.4 — MOTOR DE CLASIFICACIÓN WEBACATEGORY + ARCHIVADO A 90 DÍAS

5.1 Motor de Clasificación

Archivo: lib/migration/weba-classify.ts

Clasificación basada en reglas con respaldo opcional de LLM para hilos ambiguos.

Motor de Reglas (Sin costo de LLM)

CategoríaPatrones Regex/Regla
JOURNALReportes DMARC, noreply@, no-reply@, recibos, notificaciones de envío, confirmaciones de entrega, alertas del sistema, respuestas automáticas, mensajes de rebote
OFFICEBoletines informativos, notificaciones de redes sociales, correos promocionales, "unsubscribe", etiquetas de categoría de Gmail (CATEGORY_PROMOTIONS, CATEGORY_SOCIAL, CATEGORY_UPDATES, CATEGORY_FORUMS)
URGENTMensajes destacados de Gmail, etiqueta IMPORTANT
IMPORTANTContactos conocidos en la organización (correo en la tabla ContactEmail), hilos con 3+ mensajes (conversaciones activas)
NONEValor predeterminado de respaldo

Respaldo LLM (Opcional)

classifyAmbiguousWithLLM() — Clasifica en lote los hilos que obtuvieron NONE con baja confianza. Disponible para una pasada post-migración, pero no se llama durante la importación inicial para mantener los costos bajos.

5.2 Punto de Integración

Archivo: app/api/migration/projects/[id]/execute/route.ts

// Antes de la creación del hilo
const webaCategory = classifyWebaCategory(threadData, gmailLabels, orgContactEmails);
// webaCategory se pasa a EmailThread.create()

5.3 API de Archivado a 90 Días

Archivo: app/api/migration/archive-old-threads/route.ts

  • Endpoint: POST /api/migration/archive-old-threads
  • Cuerpo: { days?: number } (predeterminado: 90)
  • Acción: Establece isArchived: true en hilos con más de N días de antigüedad
  • Auditoría: Registrado como migration.archive_old_threads

<a id="phase-c1"></a>

SECCIÓN 6: FASE C.1 — PESTAÑA LÍNEA DE TIEMPO DEL CONTACTO

6.1 Nueva Pestaña

Archivos:

  • app/api/contacts/[id]/timeline/route.ts — Endpoint de API
  • app/(app)/contacts/[id]/timeline-tab.tsx — Componente de interfaz

6.2 Funcionalidades

  • Lista cronológica de todos los intercambios de correo con el contacto
  • Agrega datos de TODAS las direcciones de correo del contacto (principal + registros ContactEmail)
  • Código de color por dirección:
    • ENTRANTE ↓ — Indicadores verdes
    • SALIENTE ↑ — Indicadores azules
  • Se muestra asunto, fragmento, fecha y direcciones de/para
  • Capacidad de exportación a PDF

<a id="phase-c2"></a>

SECCIÓN 7: FASE C.2 — PESTAÑA ARCHIVOS ADJUNTOS (CÓDIGO DE COLOR + VISTA PREVIA + PANTALLA COMPLETA)

7.1 Reescritura Completa

Archivo: app/(app)/contacts/[id]/attachments-tab.tsx

7.2 Funcionalidades

  • Lista todos los archivos adjuntos de correo de los hilos del contacto
  • Código de color por dirección: Insignias verdes para ENTRANTE, azules para SALIENTE
  • Botón de vista previa (👁): Abre un diálogo con vista previa en línea para:
    • Imágenes (todos los formatos)
    • PDFs (mediante iframe)
    • Video (reproductor HTML5)
    • Audio (reproductor HTML5)
    • Archivos de texto (visualización en fuente monoespaciada)
  • Modo pantalla completa (⛶): Botón maximizar en el diálogo de vista previa → superposición negra inmersiva
  • Botón de descarga: Disponible tanto en la lista como en el modal de vista previa
  • API de vista previa: Utiliza el endpoint existente /api/inbox/attachments/[id]?action=preview para URLs en línea prefirmadas

<a id="phase-c3"></a>

SECCIÓN 8: FASE C.3 — PESTAÑA REGISTRO DE FUSIONES

8.1 Nueva Pestaña

Archivos:

  • app/api/contacts/[id]/merge-log/route.ts — Endpoint de API
  • app/(app)/contacts/[id]/merge-log-tab.tsx — Componente de interfaz

8.2 Funcionalidades

  • Muestra el historial de todas las operaciones de fusión que involucran a este contacto
  • Muestra: fecha de fusión, contactos de origen, actor (quién realizó la fusión)
  • Datos obtenidos de registros AuditLog con la acción contact.merge

<a id="phase-c4"></a>

SECCIÓN 9: FASE C.4 — PESTAÑA ANÁLISIS DE IA

9.1 Arquitectura

API: app/api/contacts/[id]/ai-insights/route.ts
Interfaz: app/(app)/contacts/[id]/ai-insights-tab.tsx

9.2 Análisis LLM

  • Disparador: Bajo demanda — el usuario hace clic en el botón "Lancer l'analyse"
  • Datos recopilados: Detalles del contacto, todas las direcciones de correo, teléfonos, roles en empresas, interacciones recientes (asunto + cuerpo), notas
  • Modelo: primary (gpt-4.1) mediante el wrapper LLM de WEBA
  • Prompt: Prompt estructurado en francés que solicita:
    • Résumé de la relation
    • Points clés de communication
    • Statistiques d'interaction
    • Recommandations
    • Signaux de risque ou d'opportunité

9.3 Funcionalidades de la Interfaz

  • CTA "Lancer l'analyse" con estilo degradado
  • Estado de carga con spinner animado
  • Secciones de markdown analizadas (encabezados, viñetas)
  • Barra de estadísticas: conteo de correos, tiempo de respuesta, tokens utilizados
  • Botón "Réanalyser" para actualizar
  • Color de la pestaña: Acento violeta (coherente con las funcionalidades de IA)

<a id="phase-d"></a>

SECCIÓN 10: FASE D — ENRIQUECIMIENTO POR LOTES POST-MIGRACIÓN Y VERIFICACIÓN

10.1 API de Enriquecimiento por Lotes

Archivo: app/api/migration/batch-enrich/route.ts

  • Endpoint: POST /api/migration/batch-enrich
  • Propósito: Enriquecer contactos sin jobTitle NI companyName analizando sus firmas de correo electrónico
  • Flujo:
    1. Encontrar contactos sin jobTitle/companyName (límite: 50-200 por lote)
    2. Para cada contacto, encontrar el correo ENTRANTE más reciente (mediante vínculo de hilo o participantEmails)
    3. Llamar a analyzeSignatureWithLLM() sobre el cuerpo del correo
    4. Actualizar campos del contacto (jobTitle, companyName, website, calendarBookingUrl)
    5. Crear registro ContactPhone si se extrajo un teléfono
    6. Crear CompanyContact + ContactCompanyRole si se encontró una empresa
  • Deduplicación: Verifica registros existentes antes de crear
  • Auditoría: Registrado como migration.batch_enrich

10.2 API de Verificación Post-Migración

Archivo: app/api/migration/post-verify/route.ts

  • Endpoint: POST /api/migration/post-verify
  • Propósito: Ejecutar una verificación integral de salud post-migración
  • Devuelve:
    • Análisis de duplicados: Utiliza el detectDuplicates() existente (coincidencia por correo, nombre, teléfono)
    • Estadísticas de completitud: Conteos de contactos sin jobTitle, companyName, teléfono, correo
    • Vínculos de empresa: Conteo de contactos con asociaciones CompanyContact
    • Estadísticas de hilos: Total, archivados, distribución de WebaCategory
    • Estadísticas del proyecto: Si se proporciona projectId, devuelve el estado del proyecto de migración
  • Auditoría: Registrado como migration.post_verify

<a id="phase-e"></a>

SECCIÓN 11: FASE E — GESTOR MULTI-CONTACTO

11.1 Visión

Un solo contacto puede tener:

  • 4+ empresas (mediante ContactCompanyRole → CompanyContact)
  • 4+ números de teléfono (mediante registros ContactPhone)
  • 5-6 correos electrónicos (mediante registros ContactEmail)
  • Múltiples direcciones (mediante registros ContactAddress — oficinas, propiedades, internacionales)
  • Múltiples perfiles sociales (mediante registros ContactSocialMedia)
  • URL de reserva (campo calendarBookingUrl)

11.2 Problema Identificado

La Inteligencia de Firma extraía los datos correctamente pero los guardaba solo en campos planos:

DatoGuardado en (❌ Antes)La pestaña lee de
TeléfonoContact.primaryPhone (texto)ContactPhone (tabla relacional)
EmpresaContact.companyName (texto)ContactCompanyRole → CompanyContact (relaciones)
Facebook/InstagramContact.socialLinks (JSON)ContactSocialMedia (tabla relacional)

Resultado: Las pestañas mostraban (0) a pesar de que los datos habían sido extraídos.

11.3 Corrección — E.1: Enriquecimiento Relacional

Archivo: app/api/email/extract-signature/route.ts

La API de Inteligencia de Firma ahora crea registros relacionales además de los campos planos:

Creación de ContactPhone

  • Crea ContactPhone para el phone extraído (etiqueta: work) y mobilePhone (etiqueta: mobile)
  • Establece isPrimary: true para el primer teléfono si el contacto no tiene teléfonos existentes
  • Deduplicación: verifica registros ContactPhone existentes antes de crear

CompanyContact + ContactCompanyRole

  • Busca CompanyContact existente por nombre (sin distinción de mayúsculas/minúsculas) o dominio de correo
  • Crea nuevo CompanyContact si no se encuentra (con dominio, sitio web)
  • Crea vínculo ContactCompanyRole con jobTitle como rol/título
  • Establece isPrimary: true para el primer rol de empresa

ContactSocialMedia

  • Crea registros individuales para cada plataforma social encontrada:
    • LinkedIn → LINKEDIN
    • Twitter/X → TWITTER_X
    • Facebook → FACEBOOK
    • Instagram → INSTAGRAM
    • GitHub → GITHUB
    • YouTube → YOUTUBE
    • TikTok → TIKTOK
  • El identificador se extrae de la URL (elimina protocolo/www)
  • Deduplicación: verifica la combinación plataforma:identificador

11.4 Corrección — E.2: Deduplicación en Fusiones (ContactCompanyRole)

Archivo: lib/contacts/contact-merge.ts

Antes: updateMany movía TODOS los registros ContactCompanyRole → FALLO por restricción de unicidad contactId_companyContactId si el destino y el origen comparten la misma empresa.

Después: Verificación por registro:

// Para cada rol de origen:
if (targetRoleSet.has(role.companyContactId)) {
  // Misma empresa → eliminar el duplicado del origen
  await prisma.contactCompanyRole.delete({ where: { id: role.id } });
} else {
  // Empresa diferente → mover al destino
  await prisma.contactCompanyRole.update({ where: { id: role.id }, data: { contactId: targetId } });
}

11.5 Corrección — E.3: Deduplicación en Fusiones (ContactSocialMedia)

Archivo: lib/contacts/contact-merge.ts

Mismo patrón — verifica la combinación plataforma:identificador antes de mover:

if (targetSocialSet.has(`${s.platform}:${s.handle.toLowerCase()}`)) {
  await prisma.contactSocialMedia.delete({ where: { id: s.id } });
} else {
  await prisma.contactSocialMedia.update({ where: { id: s.id }, data: { contactId: targetId } });
}

11.6 Corrección — E.4: El Destino Hereda los Mejores Campos Después de la Fusión

Archivo: lib/contacts/contact-merge.ts

Después de la fusión, el contacto destino ahora hereda los mejores datos disponibles de los orígenes fusionados:

for (const source of sources) {
  if (!target.jobTitle && source.jobTitle) updates.jobTitle = source.jobTitle;
  if (!target.companyName && source.companyName) updates.companyName = source.companyName;
  if (!target.website && source.website) updates.website = source.website;
  if (!target.calendarBookingUrl && source.calendarBookingUrl) updates.calendarBookingUrl = source.calendarBookingUrl;
  if (!target.socialLinks && source.socialLinks) updates.socialLinks = source.socialLinks;
}

11.7 Flujo Completo de Fusión (16 Pasos)

Al fusionar N contactos en 1 destino:

#RelaciónEstrategia
1ContactEmailMover no duplicados, eliminar duplicados
2ContactPhoneMover no duplicados, eliminar duplicados
3ContactInteractionMover todos
4ContactNoteMover todos
5ContactTagMover no duplicados, eliminar duplicados
6ContactAddressMover todos
7ContactSocialMediaMover no duplicados, eliminar duplicados (E.3)
8ContactCompanyRoleMover no duplicados, eliminar duplicados (E.2)
9ContactGroupMemberMover no duplicados, eliminar duplicados
10ContactObjectLinkMover (omitir duplicados mediante restricción de unicidad)
11FileAssetRevincular todos
12ClientInvoiceRevincular todos
13EmailThreadRevincular todos
14StudioFormSubmissionRevincular todos
15ContractSignatoryRevincular todos
16CalendarEventAttendeeRevincular todos

Luego: establecer mergedIntoId en los orígenes, heredar los mejores campos en el destino.


<a id="bugfixes"></a>

SECCIÓN 12: CORRECCIONES DE ERRORES

12.1 Pestaña Línea de Tiempo — Bucle de Carga Infinita

Causa raíz: La función de traducción t de useT() estaba incluida en las dependencias de useCallback. La función t cambia de referencia en cada renderizado, causando bucles de recarga infinita.

Corrección: Se eliminó t del arreglo de dependencias de useCallback en timeline-tab.tsx.

12.2 Pestaña Registro de Fusiones — Bucle de Carga Infinita

Misma causa raíz y corrección que la Pestaña Línea de Tiempo, en merge-log-tab.tsx.

12.3 API de Eliminación — Estado IMPORTING Bloqueado

Problema: La API de backend rechazaba la eliminación para proyectos en estado IMPORTING/SCANNING/PLANNING.
Corrección: Se agregaron estos estados al arreglo deletableStatuses en app/api/migration/projects/[id]/route.ts.

12.4 BookingUrl No Extraída

Problema: analyzeSignatureWithLLM() no extraía URLs de reserva de calendario.
Corrección: Se agregó bookingUrl al prompt del LLM, la firma de tipo, la verificación hasData y applyEnrichment(). Se mapea a Contact.calendarBookingUrl.


<a id="files"></a>

SECCIÓN 13: ARCHIVOS MODIFICADOS — INVENTARIO COMPLETO

Nuevos Archivos Creados

ArchivoPropósito
lib/migration/weba-classify.tsMotor de clasificación WebaCategory (reglas + LLM)
app/api/migration/archive-old-threads/route.tsAPI de archivado de hilos a 90 días
app/api/migration/batch-enrich/route.tsAPI de enriquecimiento por lotes post-migración
app/api/migration/post-verify/route.tsAPI de verificación post-migración
app/api/contacts/[id]/ai-insights/route.tsAPI de análisis de Análisis de IA
app/(app)/contacts/[id]/ai-insights-tab.tsxComponente de interfaz de Análisis de IA

Archivos Modificados

ArchivoCambios
app/(app)/webabox/webabox-client.tsxCorrección CONVERSATIONS → NONE
app/(app)/migration/migration-client.tsxSe agregó IMPORTING/SCANNING/PLANNING a canDelete
app/api/migration/projects/[id]/route.tsSe agregó IMPORTING/SCANNING/PLANNING a deletableStatuses
app/api/migration/projects/[id]/execute/route.tsSe agregaron llamadas a enrichContactPostCreation + classifyWebaCategory
lib/migration/migration-actions.tsSe agregaron enrichContactPostCreation() + analyzeSignatureWithLLM() + bookingUrl
app/(app)/contacts/[id]/timeline-tab.tsxCorrección de bucle infinito (se eliminó t de las dependencias de useCallback)
app/(app)/contacts/[id]/merge-log-tab.tsxCorrección de bucle infinito (se eliminó t de las dependencias de useCallback)
app/(app)/contacts/[id]/attachments-tab.tsxReescritura completa: modal de vista previa + pantalla completa
app/(app)/contacts/[id]/contact-detail-client.tsxSe agregó la pestaña Análisis de IA
app/api/email/extract-signature/route.tsSe agregó enriquecimiento relacional (ContactPhone, CompanyContact, ContactSocialMedia)
lib/weba/signature-extraction.tsReferencia — buildContactEnrichmentData (sin cambios)
lib/contacts/contact-merge.tsE.2/E.3: deduplicación de ContactCompanyRole + ContactSocialMedia; E.4: herencia de los mejores campos

<a id="checkpoints"></a>

SECCIÓN 14: CRONOLOGÍA DE PUNTOS DE CONTROL

#Punto de ControlDescripción
1Corrección Fase AURGENT → NONE (no CONVERSATIONS) en webabox-client.tsx
2Fase B.1-B.2Botón Eliminar visible + Desconexión de Google (preexistente)
3Fase C.1-C.3Pestañas Línea de Tiempo, Archivos Adjuntos (código de color), Registro de Fusiones
4Corrección eliminar línea de tiempo registro de fusiones vista previaEliminación IMPORTING + correcciones de bucle infinito + vista previa/pantalla completa de Archivos Adjuntos
5Pestaña C.4 Análisis de IA en contactosPestaña de análisis LLM bajo demanda
6B.3 auto-enriquecimiento CompanyContact migraciónEnriquecimiento automático durante la ejecución de la migración
7B.4 clasificación WebaCategory archivado 90dMotor de clasificación + API de archivado
8APIs D batch-enrich post-verifyEndpoints de enriquecimiento por lotes + verificación
9Corrección API eliminar permitir estado IMPORTINGCorrección de API de backend para eliminación en estado IMPORTING
10Agregar extracción de bookingUrl desde firmasBookingUrl agregada a la extracción de firmas LLM
11E enriquecimiento relacional multi-contacto fusiónEnriquecimiento relacional + deduplicación en fusiones

SECCIÓN 15: IMPACTO EN EL ESQUEMA

Cero Cambios en el Esquema

Todas las modificaciones utilizan modelos y campos existentes de Prisma:

  • Contact — jobTitle, companyName, website, calendarBookingUrl, socialLinks, primaryPhone, primaryEmail
  • ContactPhone — phone, label, isPrimary
  • ContactEmail — email, isPrimary
  • ContactCompanyRole — contactId, companyContactId, role, title, isPrimary
  • CompanyContact — name, domain, website, organizationId
  • ContactSocialMedia — platform (enum SocialPlatform), handle, url, isPrimary
  • ContactAddress — campos completos de dirección
  • EmailThread — webaCategory (enum WebaCategory), isArchived
  • ContactInteraction — subject, body
  • ContactNote — content

No se requiere prisma db push. No se requiere --force-reset. No se requiere --accept-data-loss.


SECCIÓN 16: ENDPOINTS DE API CREADOS

MétodoEndpointPropósito
POST/api/migration/batch-enrichEnriquecimiento por lotes de contactos sin jobTitle/companyName mediante análisis LLM de firmas de correo
POST/api/migration/post-verifyVerificación post-migración (duplicados + estadísticas de completitud)
POST/api/migration/archive-old-threadsArchivar hilos con más de N días de antigüedad (predeterminado: 90)
POST/api/contacts/[id]/ai-insightsAnálisis LLM bajo demanda de la relación con el contacto

SECCIÓN 17: PESTAÑAS DE DETALLE DEL CONTACTO (LISTA COMPLETA)

Fila 1

PestañaFuente de Datos
OverviewContactForm (campos editables)
CompaniesContactCompanyRole → CompanyContact
EmailRegistros ContactEmail
PhoneRegistros ContactPhone
AddressesRegistros ContactAddress
Social MediaRegistros ContactSocialMedia

Fila 2

PestañaFuente de Datos
ActivityRegistros ContactInteraction
NotesRegistros ContactNote
TagsContactTag → Tag
CalendarCalendarEvent (mediante asistentes)
Signature IntelExtracción LLM de correos entrantes
TimelineAgregación de EmailMessage (NUEVA)
Merge LogAuditLog con action=contact.merge (NUEVA)
AttachmentsEmailAttachment con vista previa/pantalla completa (REESCRITA)
AI InsightsAnálisis LLM bajo demanda (NUEVA)
ContractsRegistros ContractSignatory

Fin del Addendum 06

"Un solo WEBA. Cada canal. En tiempo real, siempre."


Documento preparado por: Agente de Desarrollo WEBA
Validado por: Alain Bessette
Fecha: 6 de junio de 2026
Clasificación: Interno — Especificación Técnica

© 2024–2026 GOWEBA INC. — Make it Simple, Make it Possible, Make it Real.