Primero el recorrido de un vendedor, paso a paso, con lo que ve en cada pantalla y de quién es cada responsabilidad. Después, para quien lo necesite, el detalle técnico: qué detona qué, campo por campo, cómo se inscribe y cómo vuelve lo que TNI cambia.
Carlos vende en la oficina de Guatemala. Así es su día con los dos sistemas conectados. En cada paso: qué hace, qué pasa por detrás, cómo se ve, y de quién es la responsabilidad.
Con su usuario de siempre. Nada cambia en su sistema.
Su sistema arma un pase con quién es, su país, su oficina y su rol, y lo manda a GlobalLink. El pase dura cinco minutos y sirve una vez.
Truly Nolen GlobalLink ↗Sin usuario ni contraseña. Entra a su tablero de Guatemala, oficina 679, con permisos de vendedor.
En «Prospectar» busca por sector, por zona o deja que el sistema le proponga. Encuentra el Hotel Los Volcanes, con teléfono, correo y la persona que decide.
Modo Manual: se lo queda él. Truly Rocket: el bot hace los primeros toques y le entrega la cita. En los dos casos el negocio nace con dueño.
GlobalLink crea la empresa, la persona y el negocio con su identificador, y deja el aviso en la cola. El programa de escritura elige la base de Guatemala, comprueba que el hotel no exista ya en la cartera de la oficina 679, y crea la ficha en estado Potencial con Carlos como vendedor. TNI devuelve el número de cliente y queda guardado en el negocio.
Vuelve a su sistema de gestión, filtra por estado Potencial y ahí está, con su nombre como vendedor. Puede abrir la ficha, imprimirla, o seguir trabajando como siempre.
| Customer Code | Customer | Status | Sales Person | Date |
|---|---|---|---|---|
| — | HOTEL LOS VOLCANES | Potential | Carlos M. | 04/09/2026 |
| GT-10231 | CLINICA SANTA LUCIA | Potential | Ana R. | 29/08/2026 |
Carlos llama o escribe desde GlobalLink; si eligió Rocket, el bot manda el primer correo. En TNI aparece un renglón en la bitácora del cliente: «contactado · correo · 4 de septiembre».
La agende él o la agende el bot. En TNI aparece otro renglón con la fecha programada. Es el momento en que el prospecto pasa a «potencial» según lo acordado el 10 de agosto.
| Date | Sales Person | Notes |
|---|---|---|
| 04/09/2026 | Carlos M. | GLOBALLINK · contactado · correo |
| 05/09/2026 | Carlos M. | GLOBALLINK · cita agendada para 09/09 10:00 |
Carlos registra la visita en el sistema de gestión, no en GlobalLink. Esa noche, el espejo trae ese renglón y GlobalLink lo pone en la línea de tiempo del negocio.
Desde GlobalLink, con el monto. En TNI: otro renglón en la bitácora, «propuesta enviada · USD 1.800 anuales».
Carlos cierra el negocio en GlobalLink. El programa crea en TNI el servicio y la propuesta, colgando del cliente. La ficha sigue en Potencial: activarla es de TNI.
Con su flujo de siempre: la ficha pasa de Potencial a Activo. Nadie de Catalizadora toca esa ficha.
El espejo trae el cambio de estado y el negocio queda como sincronizado con TNI. Si Carlos no lo había cerrado, se cierra solo. Si en cambio TNI diera de baja la ficha, el negocio pasaría a perdido, con el motivo.
El programa que escribe en TNI y el que lee lo que vuelve los construye y los opera Catalizadora. TNI provee accesos, dos columnas y dos confirmaciones.
idempotency_key con índice único en Clientes y Contactos. No afecta datos existentes.El prospecto vive como un cliente en estado 4, Potencial, en la ficha de clientes de TNI. Cada avance se registra como un renglón en su bitácora de contactos. Lo que TNI modifique en esa ficha o en esa bitácora vuelve a GlobalLink por el espejo nocturno.
Cada detonante deja un aviso en la cola de salida. El programa de escritura lo toma, elige la base por la oficina y escribe. Si falla, reintenta; si se repite, no duplica.
| Momento en GlobalLink | Aviso en la cola | Qué se escribe en TNI | Qué vuelve |
|---|---|---|---|
| El negocio queda con dueño Rocket o vendedor, en la misma transacción del alta | prospecto_creadonuevo | Alta en dbo.Clientes con estado 4 y todos los campos del cruce de ida | IdCliente → app.leads.id_cliente_creado |
| Primer contacto el negocio pasa a «contactado» | contactadonuevo | Renglón en dbo.Contactos: fecha, hora, vendedor, canal | IdContacto, sólo para auditoría |
| Cita agendada por el bot o a mano | lead_potencialya existe | Renglón en dbo.Contactos con la fecha programada de la visita | IdContacto |
| Propuesta enviada el negocio pasa a «negociación» | propuesta_enviadanuevo | Renglón en dbo.Contactos con el monto | IdContacto |
| Ganado | cierre_ganadoya existe | Alta en dbo.Servicios, alta en dbo.Propuestas, renglón en dbo.Contactos. La ficha sigue en estado 4. | IdServicio, IdPropuesta. Cuando TNI factura, el estado 1 vuelve por el espejo y cierra el ciclo. |
| Perdido con motivo | perdidonuevo | Renglón en dbo.Contactos con el motivo | Nada. TNI decide si da de baja la ficha. |
| Reactivado de perdido vuelve a nuevo | reactivadonuevo | Renglón en dbo.Contactos. No se crea otra ficha: se reutiliza el IdCliente guardado. | Nada |
Nombres reales de las dos bases. Las columnas de TNI son las que el proceso nocturno lee todas las noches, verificadas contra sus tres bases el 30 de julio.
| En GlobalLink | Transformación | En TNI | Estado |
|---|---|---|---|
| Alta del prospecto → dbo.Clientes · una fila por negocio | |||
| app.leads.prospecto_nombretexto · nombre de la empresa | Se recorta a 100 caracteres | dbo.Clientes.Clientenvarchar(100) · obligatorio | va |
| app.leads.id_oficinaentero · lleva la base adentro | Base = id ÷ 1.000.000.000 (0 Truly · 1 TrulyNew · 2 TrulyRuso). IdOficina = resto | dbo.Clientes.IdOficinaint · obligatorio · en la base que corresponda | va |
| constanteel programa la pone | Siempre 4 | dbo.Clientes.IdStatusClienteint · 4 = Potencial | crear acá confirmar |
| app.leads.assigned_rep_user_iduuid · el dueño del negocio | → public.users.id_empleado_tni (columna nueva). Si no hay puente, va vacío y se avisa | dbo.Clientes.IdVendedorint → dbo.Empleados | crear acá |
| app.companias.industriatexto | Tal cual | dbo.Clientes.Rubronvarchar | va |
| app.companias.direcciontexto | Tal cual | dbo.Clientes.Direccionnvarchar | va |
| app.leads.ciudadtexto · del enriquecimiento | Tal cual, si existe | dbo.Clientes.Localidadnvarchar | va |
| app.companias.telefonotexto | Formato local del país de la oficina, sin el prefijo internacional, como guarda TNI | dbo.Clientes.Telefononvarchar | va |
| app.contactos.moviltexto · el móvil de la persona | Misma regla de formato | dbo.Clientes.Movilnvarchar | va |
| app.companias.emailtexto | Tal cual | dbo.Clientes.Emailnvarchar | va |
| app.companias.sitio_webtexto | Tal cual | dbo.Clientes.Webnvarchar | va |
| enriquecimiento del padrónNIT, RFC, RUT, CUIT | Sólo si el registro oficial del país lo trajo. Nunca un provisional | dbo.Clientes.Identidadnvarchar | va |
| app.contactos.nombretexto · la persona que decide | Tal cual | dbo.Clientes.ContactoVentasnvarchar | va |
| app.contactos.email | Tal cual | dbo.Clientes.ContactoVentasEmailnvarchar | va |
| app.contactos.telefono_e164 | Formato local | dbo.Clientes.ContactoVentasTelefononvarchar · el código dice «…Tel» y no existe | arreglar |
| app.leads.fecha_creacionfecha y hora con zona | Fecha local de la oficina, sin hora. Hoy el código usa la fecha de cierre | dbo.Clientes.FechaAltadatetime | arreglar |
| app.leads.id_lead · origen · metodouuid + dos textos | GLOBALLINK:<id_lead> · origen=… · metodo=… | dbo.Clientes.Observacionesntext · la marca de trazabilidad | va |
| app.writeback_outbox.id_outboxuuid del aviso | Tal cual | dbo.Clientes.idempotency_keyuniqueidentifier · columna nueva con índice único | crear allá |
| Cada hito → dbo.Contactos · un renglón por aviso | |||
| app.leads.id_cliente_creadoel número que devolvió TNI | Resto de la división por base | dbo.Contactos.IdClienteint · obligatorio | crear acá |
| app.leads.id_oficina | Misma regla de base | dbo.Contactos.IdOficinaint | va |
| app.leads.assigned_rep_user_id | Por el puente de empleado | dbo.Contactos.IdVendedorint | crear acá |
| fecha del hitostage_entered_at · occurred_at | Fecha y hora local de la oficina, separadas | dbo.Contactos.FechaContacto · HoraContactodatetime · datetime | crear acá |
| app.lead_appointments.scheduled_atsólo en la cita | Fecha y hora local | dbo.Contactos.FechaProgramada · HoraIniciodatetime | crear acá |
| tipo de aviso + detallecanal · monto · motivo | GLOBALLINK:<id_lead>:<hito> · detalle | dbo.Contactos.Observacionesntext · con la marca, para no leerlo de vuelta | crear acá |
| app.writeback_outbox.id_outbox | Tal cual | dbo.Contactos.idempotency_keycolumna nueva | crear allá |
| Ganado → dbo.Servicios y dbo.Propuestas · ya construido | |||
| app.leads.id_cliente_creado | Resto de la división por base | dbo.Servicios.IdClienteint | va |
| app.leads.fecha_cierre | Fecha local | dbo.Servicios.FechaAlta · dbo.Propuestas.FechaPropuestadatetime | va |
| IdServicio devuelto | Tal cual | dbo.Propuestas.IdServicioint · Propuestas no tiene IdCliente | va |
CodigoCliente lo numera la oficina. IdTipoCliente es el canal de venta de TNI, con tres valores, y queda vacío hasta que TNI diga cuál corresponde. ContactoAdmin y ContactoTecnico son otros roles; el prospecto sólo trae el de ventas. El país no existe como columna: va implícito en la oficina y en la base.El espejo nocturno ya copia la ficha de clientes y la bitácora de contactos de TNI, y desde el 5 de agosto trae sólo las filas que cambiaron, usando la marca que pone el motor de SQL Server en cada modificación. Lo que falta es el paso siguiente: comparar lo que llegó contra los negocios de GlobalLink y aplicar el cambio.
| Cambió en TNI | Llega por el espejo a | Efecto en GlobalLink | Estado |
|---|---|---|---|
| La llave que une los dos lados | |||
| dbo.Clientes.IdClientelo asignó TNI al crear | silver.clientes.id_clientecon la base sumada | Se busca el negocio por app.leads.id_cliente_creado. Sin esa columna escrita no hay vuelta posible | crear acá |
| La ficha del cliente | |||
| dbo.Clientes.IdStatusCliente4 → 1 · TNI lo activó | silver.clientes.id_status_cliente | El negocio pasa a ganado si no lo estaba, y luego a sincronizado. Fecha de cierre: la de TNI | crear acá |
| dbo.Clientes.IdStatusCliente→ 3 · o FechaBaja con valor | silver.clientes.id_status_cliente · fecha_baja | El negocio pasa a perdido con motivo «dado de baja en TNI» | crear acá |
| dbo.Clientes.IdStatusCliente→ 2 · inactivo | silver.clientes.id_status_cliente | Sólo se anota en la línea de tiempo. Un prospecto no se vuelve inactivo: si TNI lo marca así, alguien lo revisa | crear acá |
| dbo.Clientes.IdVendedorcambió | silver.clientes.id_vendedor | Se reasigna el dueño del negocio por el puente de empleado. Si el empleado no tiene usuario en GlobalLink, se avisa al gerente de la oficina | crear acá |
| dbo.Clientes.Telefono · Movil · Email · Direccioncambiaron | silver.clientes.telefono · movil · email · direccion | Se actualizan la empresa y el contacto en GlobalLink. TNI manda sobre los datos del cliente una vez creado | crear acá |
| dbo.Clientes.ContactoVentas · Email · Telefonocambiaron | silver.clientes.contacto_ventas · _email · _tel | Se actualiza la persona de contacto del negocio | crear acá |
| La bitácora de contactos | |||
| dbo.Contactosrenglón nuevo para ese IdCliente, sin la marca GLOBALLINK | silver.contactoshoy trae 5 columnas; hay que sumar IdVendedor, IdMotivoContacto, HoraContacto, VentaDirecta | Entra a la línea de tiempo como «visita o llamada registrada en TNI por …». Si el negocio estaba en «nuevo», pasa a «contactado» | crear acá |
| dbo.Contactosrenglón con la marca GLOBALLINK | silver.contactos | Se ignora: lo escribimos nosotros. Sin esta regla, cada hito volvería como si TNI lo hubiera anotado | crear acá |
| Servicios | |||
| dbo.Serviciosservicio nuevo para ese IdCliente que no creamos nosotros | silver.servicios | Es la prueba de que se contrató por fuera de GlobalLink: el negocio pasa a ganado con la fecha del servicio | crear acá |
Sólo altas, con parámetros, en la base que corresponde a la oficina. El envoltorio de conexión rechaza cualquier otra instrucción antes de abrir la conexión.
-- 1 · el alta del prospecto · una sola vez por negocio INSERT INTO dbo.Clientes ([Cliente], [IdOficina], [IdStatusCliente], [IdVendedor], [Rubro], [Direccion], [Localidad], [Telefono], [Movil], [Email], [Web], [Identidad], [ContactoVentas], [ContactoVentasEmail], [ContactoVentasTelefono], [FechaAlta], [Observaciones], [idempotency_key]) OUTPUT INSERTED.IdCliente VALUES (@nombre, @id_oficina, 4, @id_vendedor, @rubro, @direccion, @localidad, @telefono, @movil, @email, @web, @identidad, @contacto_nombre, @contacto_email, @contacto_telefono, @fecha_alta, 'GLOBALLINK:' + @id_lead + ' · origen=' + @origen + ' · metodo=' + @metodo, @id_aviso); -- 2 · cada hito · un renglón en la bitácora INSERT INTO dbo.Contactos ([IdCliente], [IdOficina], [IdVendedor], [FechaContacto], [HoraContacto], [FechaProgramada], [HoraInicio], [Observaciones], [idempotency_key]) OUTPUT INSERTED.IdContacto VALUES (@id_cliente, @id_oficina, @id_vendedor, @fecha, @hora, @fecha_cita, @hora_cita, 'GLOBALLINK:' + @id_lead + ':' + @hito + ' · ' + @detalle, @id_aviso);
Primero por la marca GLOBALLINK en observaciones. Después por teléfono exacto o nombre normalizado contra la cartera de esa oficina en el espejo, con el mismo criterio que ya usa GlobalLink para rotular «ya es cliente». Si existe, se enlaza el número y no se crea.
El aviso lleva su propio identificador. Con la clave única que agrega TNI, el motor rechaza el segundo intento. Mientras no exista, la marca en observaciones cumple la misma función.
Cinco reintentos con espera creciente. Un fallo por dato inválido no se reintenta: queda marcado y visible. Cada intento, con su resultado, se guarda en la bitácora de escritura.
En horario laboral de la oficina; treinta fuera de horario. Tope mensual acordado: cinco mil clientes, doce mil renglones de bitácora.
Estado de la ficha, vendedor asignado, teléfono, correo, dirección. Lo que TNI cambie ahí se adopta en GlobalLink y queda anotado como cambio hecho en TNI.
Contactado, cita, negociación: esas etapas no existen en TNI. Se registran allá como renglones de bitácora, pero se deciden acá.
Un negocio se cierra como ganado en GlobalLink cuando el vendedor lo cierra o cuando TNI activa la ficha, lo que pase primero. Sólo TNI pasa la ficha de Potencial a Activo.
GlobalLink sólo agrega filas en TNI. Si algo tiene que cambiar en una ficha ya creada, lo cambia TNI y vuelve por el espejo.
La persona ya se identificó en el sistema de gestión. Al hacer clic, ese sistema emite un pase firmado que dura cinco minutos y sirve una vez; GlobalLink lo verifica y abre la sesión con el país, la oficina y el rol de esa persona. Ninguna contraseña viaja.
Truly Nolen GlobalLink ↗Reconstrucción de su pantalla. La pestaña nueva conserva el aspecto del sistema; la flecha avisa que abre otra aplicación.
TN GlobalLinkGuatemala · Oficina 679 Pablo EstradaCifras de ejemplo.
| Dato del pase | De dónde lo saca TNI | Para qué lo usa GlobalLink |
|---|---|---|
| subidentificador estable de la persona | Su tabla de usuarios: usuario_inter.id_usuario | Encontrar o crear la cuenta: public.users.external_sub |
| email · name | La misma tabla | Mostrar quién es y avisarle por correo |
| countrydos letras | El país del usuario | El alcance: qué datos puede ver |
| franchise_idla oficina | La oficina del usuario | La oficina de sus negocios y su Rocket |
| role | Su perfil, traducido a nuestros siete roles | Qué puede hacer: ver, crear, asignar |
| exp · jtivence en 5 min · único | Los genera el emisor | Rechazar pases viejos o repetidos |
TNI tiene una tabla de seguimiento comercial con 169.150 registros, con tareas agendadas por empleado y presupuestos. Encaja conceptualmente con un prospecto, y no es el camino por tres razones: el permiso de escritura acordado no la incluye; no está copiada en el espejo, así que no podríamos verificar lo escrito ni leer lo que vuelve; y tiene un circuito de aprobación propio dentro de su sistema. La ficha en estado Potencial da el mismo resultado con lo que ya está acordado, y la vuelta funciona porque esa tabla sí está en el espejo.
El mapeo de escritura usa ContactoVentasTel; la columna se llama ContactoVentasTelefono. El control que compara nombres contra el catálogo real sólo recorre la carpeta de la copia nocturna, y la prueba del mapeo de escritura sólo comprueba que no aparezcan columnas inventadas. Por eso hoy pasa en verde y la primera escritura real fallaría. Son tres literales en dos archivos.
SQL Server pone en cada fila una marca de versión que el motor mueve en cada alta y en cada modificación, sin que la aplicación participe. Se midió comparando dos fotos completas con tres días de diferencia: la marca capturó el 100 % de los cambios reales en clientes, contactos, servicios y órdenes. La fecha de modificación que escribe la aplicación, en cambio, no se movió en el 100 % de los cambios de contactos. Por eso el espejo usa la marca del motor. Lo único que la marca no ve son los borrados; una vez por semana una foto completa reconcilia.
TNI opera tres bases productivas y los números de oficina y de cliente se repiten entre ellas. GlobalLink guarda la base adentro del número de oficina y el programa la deshace antes de escribir; el mismo desplazamiento se aplica al leer. El país no viaja: se deduce de la oficina. La cuarta base del servidor es su copia de pruebas y está bloqueada por código.
El diseño está acordado por escrito entre los equipos técnicos desde el 5 de mayo de 2026: pase firmado con la llave privada de TNI, cinco minutos de vida, un solo uso, verificado por GlobalLink contra la llave pública, con rechazo de pases repetidos y comprobación de que el país y la oficina estén activos. Falta construirlo de los dos lados; hay un emisor de laboratorio para avanzar sin esperar. Si su plataforma no puede publicar una llave pública, la variante con secreto compartido cambia una línea de configuración de cada lado y nada más.
Verificación de acceso al sistema de gestión del 24 de julio; mapeo medido contra las tres bases el 30 de julio; censo de tablas del 27 de julio; medición de la cola del 16 de agosto; medición de la marca de motor del 5 de agosto; acta del 10 de agosto; acuerdo de entrega del 7 de agosto; especificación del pase del 5 de mayo; respuesta escrita de TNI del 31 de julio. Todo el estudio se hizo en lectura.