# Documentación Técnica del Workflow: Encuesta de Terminación Voluntaria (n8n) Este documento detalla el diseño, la lógica de negocio y la configuración paso a paso de los nodos del flujo automatizado desarrollado en n8n para la gestión inteligente de encuestas de salida laboral de **GomezLee Marketing**. --- ## 1. Descripción del Proyecto y Alcance El propósito fundamental de este flujo es optimizar la recolección y análisis de datos procedentes de las encuestas de salida de los empleados con terminación voluntaria. ### El Problema Históricamente, muchos empleados seleccionan o escriben motivos genéricos como **"Motivos Personales"** o proveen respuestas sin sentido o ambiguas en los formularios de salida. Esto impide que el departamento de Recursos Humanos (RRHH) obtenga información de valor (*insights*) para implementar planes de retención y mejoras internas. ### La Solución Automatizada El workflow soluciona este problema mediante un ciclo inteligente dividido en tres fases principales (visibles en la estructura del flujo de `image_ec77fb.jpg`): 1. **Fase de Envío Automatizado:** Identifica bajas voluntarias del sistema central (BambooHR) y envía la encuesta formal de manera automatizada. 2. **Fase de Análisis y Homologación Inicial (IA):** Recibe la respuesta del formulario, utiliza Inteligencia Artificial (Google Gemini) para clasificar el motivo real, detectar subcategorías, evaluar el sentimiento e insertarlo en una base de datos (Google Sheets). 3. **Fase de Excepción y Recolección de Datos (RRHH + Email Loop):** Si el motivo detectado o declarado cae bajo "Motivos Personales" o es "No Declarado", se activa un condicional que notifica inmediatamente al analista de RRHH del país correspondiente. RRHH llama al exempleado, obtiene el motivo detallado y responde un correo electrónico formateado. El sistema procesa esta respuesta vía email, re-homologa la información con IA y actualiza el registro inicial en el Google Sheets de manera transparente. --- ## 2. Diagrama Estructural del Workflow De acuerdo al archivo técnico y a la imagen de referencia `image_ec77fb.jpg`, el workflow se compone de 4 sub-procesos o bloques lógicos claramente demarcados: * **Sub-proceso 1 (Arriba):** Trigger Webhook de terminación y validación en BambooHR de que sea baja voluntaria del mes en curso para el envío de la encuesta de salida. * **Sub-proceso 2 (Centro):** Webhook de recepción de respuestas del formulario, procesamiento por IA (Gemini), guardado en Google Sheets, filtro condicional de excepción e inicio del bucle de correos hacia RRHH. * **Sub-proceso 3 (Abajo - Recepción):** Listener / Trigger de Gmail que captura los correos de RRHH cuando la información es refinada, re-clasifica el motivo real con IA y actualiza la fila correspondiente en Google Sheets. * **Sub-proceso 4 (Fondo):** Flujo técnico de respaldo/automatización interna para guardar copias del JSON del workflow en un repositorio Git centralizado. --- ## 3. Configuración Nodo por Nodo y Valores Recomendados A continuación se detallan los parámetros y valores específicos que deben colocarse en cada nodo para garantizar el funcionamiento preciso del sistema: ### Bloque A: Envío de la Encuesta (Bajas Voluntarias) #### 1. Webhook (Entrada de Terminación) * **Tipo de Nodo:** `n8n-nodes-base.webhook` * **HTTP Method:** `POST` * **Path:** `terminacion` * **Función:** Recibe las notificaciones de eventos de personal/bajas desde el core de RRHH. #### 2. If (Validación de Tipo) * **Tipo de Nodo:** `n8n-nodes-base.if` * **Condición (String):** * **Value 1:** `{{ $json.body.employees[0].fields['Tipo de despido'] }}` * **Operator:** `Equal` * **Value 2:** `Resignation (Voluntary)` #### 3. Fecha de terminacion * **Tipo de Nodo:** `n8n-nodes-base.httpRequest` * **Method:** `GET` * **URL:** `https://api.bamboohr.com/api/gateway.php/glm/v1/employees/{{ $json.body.employees[0].id }}?fields=terminationDate` * **Authentication:** `HTTP Basic Auth` -> Usar credenciales `GLM Credential`. * **Headers:** `accept: application/json` #### 4. Code in JavaScript3 (Filtro Temporal) * **Tipo de Nodo:** `n8n-nodes-base.code` * **Código JS:** ```javascript const terminationDate = $json.terminationDate; if (!terminationDate) return [{ json: { pass: false } }]; const termDate = new Date(terminationDate); const now = new Date(); const sameMonth = termDate.getMonth() === now.getMonth(); const sameYear = termDate.getFullYear() === now.getFullYear(); return [{ json: { pass: sameMonth && sameYear } }]; ``` #### 5. Terminacion fue este mes? * **Tipo de Nodo:** `n8n-nodes-base.if` * **Condición (Boolean):** * **Value 1:** `{{ $json.pass }}` * **Operator:** `is True` #### 6. Send a message (Gmail) * **Tipo de Nodo:** `n8n-nodes-base.gmail` * **Resource:** `Message` * **Operation:** `Send` * **Send To:** `{{ $('Webhook').item.json.body.employees[0].fields['Correo electrónico personal'] }}` * **Subject:** `GomezLee Marketing: Encuesta de salida – Queremos escuchar tu opinión` * **Body Type:** `HTML` * **Message:** *(Insertar el código HTML provisto en la definición del flujo que renderiza la plantilla corporativa con el botón directo a la encuesta de Google Forms).* --- ### Bloque B: Procesamiento de Respuestas de Encuesta e IA #### 7. Webhook1 (Recepción del Formulario) * **Tipo de Nodo:** `n8n-nodes-base.webhook` * **HTTP Method:** `POST` * **Path:** `encuesta` #### 8. Code in JavaScript (Timestamping) * **Tipo de Nodo:** `n8n-nodes-base.code` * **Código JS:** Genera una estampa de tiempo formateada (`MM/DD/YYYY HH:MM:SS`) para consistencia en la hoja de cálculo. #### 9. AI Agent + Google Gemini Chat Model (Clasificador Inicial) * **Tipo de Nodo:** `@n8n/n8n-nodes-langchain.agent` conectado a `lmChatGoogleGemini`. * **Model Name:** `models/gemini-3.1-pro-preview` * **Prompt Text:** `={{ $('Webhook1').item.json.body['¿Por qué elegiste dejar la empresa?'] }}` * **System Message (Clave):** Debe instruirse rigurosamente al modelo a actuar como un analista experto de RRHH para trade marketing y mapear el texto a etiquetas estructuradas de salida. Los labels válidos requeridos son: * `"Motivos Personales"` * `"Remuneración"` * `"Liderazgo / Jefe Directo"` * `"Otro Trabajo / Traslado de Agencia"` * `"Ambiente Laboral / Compañeros"` * `"Work Life Balance / Horarios"` * `"Marca / Cliente / Condiciones del Punto"` * `"Onboarding / Procesos / Organización"` * `"Way of Work / Soporte Operativo"` * `"Reclutamiento / Expectativa vs Realidad"` * `"No quiso responder"`, `"Motivo No Declarado"`, o `"Otros"`. * **Estructura del Output Requerido (JSON puro sin backticks):** ```json { "homologacion": "string", "homologado_2": "string | null", "sentimiento": "Positivo | Neutro | Negativo", "insight_rrhh": "frase breve con hallazgo clave" } ``` #### 10. Code in JavaScript1 (Limpieza de Formato IA) * **Tipo de Nodo:** `n8n-nodes-base.code` * **Objetivo:** Elimina bloques de markdown (como \`\`\`json) en caso de que el LLM rompa las restricciones de formato, aislando la cadena JSON cruda. #### 11. Edit Fields & Eliminar espacios vacios * **Tipo de Nodos:** `n8n-nodes-base.set` y `n8n-nodes-base.code`. * **Función:** Mapean y remueven espacios en blanco colindantes en los nombres y cadenas para evitar inconsistencias de llaves primarias. #### 12. Añadir a Responses (Google Sheets) * **Tipo de Nodo:** `n8n-nodes-base.googleSheets` * **Operation:** `Append` * **Document ID:** `1_vEMMGBclOZxaTeuHLXO_ucN0GmJ03Gm7jzOlzkVMFA` * **Sheet Name:** `Respuestas` * **Mapeo de Columnas (Expresiones):** * `Homologacion_IA`: `{{ $('Edit Fields').item.json.cleaned.homologacion }}` * `Subcategoria_IA`: `{{ $('Edit Fields').item.json.cleaned.homologado_2 }}` * `Sentimiento_IA`: `{{ $('Edit Fields').item.json.cleaned.sentimiento }}` * `Insight_RRHH`: `{{ $('Edit Fields').item.json.cleaned.insight_rrhh }}` * `Timestamp`: `{{ $('Webhook1').item.json.body.timestamp }}` * `Email Address`: `{{ $('Webhook1').item.json.body.email }}` * `Nombre Completo`: `{{ $json.name }}` * `¿Por qué elegiste dejar la empresa?`: `{{ $('Webhook1').item.json.body['¿Por qué elegiste dejar la empresa?'] }}` #### 13. Es motivo personal? (El Enrutador de Excepciones) * **Tipo de Nodo:** `n8n-nodes-base.if` * **Lógica de Evaluación Expresa (JavaScript Emulado):** ```javascript {{ (() => { const allowed = ["motivos personales", "motivo no declarado"]; const homol = ($json.Homologacion_IA ?? "").toLowerCase().trim(); const sub = ($json.Subcategoria_IA ?? "").toLowerCase().trim(); const homolOk = homol === "" || allowed.includes(homol); const subOk = sub === "" || allowed.includes(sub); const anyFilled = homol !== "" || sub !== ""; return anyFilled && homolOk && subOk; })() }} ``` * **Operator:** `is True` * **Comportamiento:** Si da verdadero (True), significa que la respuesta de la persona no es accionable y requiere intervención de RRHH. #### 14. Paises (Ruteo Geográfico de RRHH) * **Tipo de Nodo:** `n8n-nodes-base.code` * **Propósito:** Mapea el país del empleado al correo del analista encargado en esa región. * **Diccionario de Mapeo:** * Dominicana: `nlaureano@gomezleemarketing.com` * Guatemala: `rgalvez@gomezleemarketing.com` * El Salvador: `cmalta@gomezleemarketing.com` * Honduras: `mchang@gomezleemarketing.com` * Nicaragua: `yestrada@gomezleemarketing.com` * Costa Rica: `lchaves@gomezleemarketing.com` * México: `ccastro@gomezleemarketing.com` * Colombia: `rrhhcolombia@gomezleemarketing.com` * Panamá: `dpenalba@gomezleemarketing.com` #### 15. Enviar revision (Notificación a Analista) * **Tipo de Nodo:** `n8n-nodes-base.gmail` * **Send To:** `{{ $json.hhrr_email }}` * **Subject:** `Seguimiento requerido – Encuesta de Salida` * **Contenido:** Envía un correo con la ficha del exempleado pidiendo realizar la llamada y especificando que deben responder al sistema manteniendo el asunto: **"Motivo de Salida Actualizado"** e incluyendo en el cuerpo obligatoriamente las líneas: ```text Nombre completo: [Nombre Exacto] Motivo: [Nuevo Motivo Detallado] ``` --- ### Bloque C: Procesamiento del Correo de Actualización (RRHH Loop) #### 16. Gmail Trigger (Listener de Respuestas de RRHH) * **Tipo de Nodo:** `n8n-nodes-base.gmailTrigger` * **Filters:** * **Search Query (q):** `Motivo de Salida Actualizado` * **Read Status:** `Read` #### 17. Limpiar texto * **Tipo de Nodo:** `n8n-nodes-base.code` * **Código JS:** Remueve firmas automáticas y descargos legales buscando el marcador corporativo `'gomezlee marketing'` para evitar ruidos en el análisis sintáctico de la IA. #### 18. AI Agent1 + Google Gemini Chat Model1 (Re-homologación) * **Tipo de Nodo:** `@n8n/n8n-nodes-langchain.agent` * **Model Name:** `models/gemini-3.1-pro-preview` * **Prompt Text:** `={{ $json.body }}` * **Instrucciones del Sistema:** Extrae el `nombre_completo` y el nuevo `motivo`. Re-clasifica según las categorías estándar de la organización y genera un nuevo output estructurado: ```json { "nombre_completo": "string", "homologacion": "string", "homologado_2": "string | null", "sentimiento": "Positivo | Neutro | Negativo", "insight_rrhh": "string", "motivo": "string" } ``` #### 19. Añadir a Responses1 (Google Sheets Update) * **Tipo de Nodo:** `n8n-nodes-base.googleSheets` * **Operation:** `Update` * **Document ID:** `1_vEMMGBclOZxaTeuHLXO_ucN0GmJ03Gm7jzOlzkVMFA` * **Sheet Name:** `Respuestas` * **Columnas a Actualizar:** * `Homologacion_IA`: `{{ $('Edit Fields1').item.json.output.homologacion }}` * `Subcategoria_IA`: `{{ $('Edit Fields1').item.json.output.homologado_2 }}` * `Sentimiento_IA`: `{{ $('Edit Fields1').item.json.output.sentimiento }}` * `Insight_RRHH`: `{{ $('Edit Fields1').item.json.output.insight_rrhh }}` * `¿Por qué elegiste dejar la empresa?`: `{{ $('Edit Fields1').item.json.output.motivo }}` * **Key/Matching Columns:** `Nombre Completo` *(Garantiza la sobreescritura exacta del registro que antes estaba bloqueado en motivos personales).* --- ## 4. Instrucciones de Despliegue y Pruebas 1. **Credenciales:** Asegurarse de enlazar la cuenta OAuth2 de Google Sheets (`Eidan - Google Sheets account`), Gmail (`Eidan - Gmail account`), Google Gemini (`Eidan - Google Gemini(PaLM) Api account`) y la API de BambooHR. 2. **Activación de Triggers:** Pasar el estado del workflow en n8n de `Inactive` a `Active`. 3. **Monitoreo:** En caso de errores en la estructura del JSON devuelto por Gemini, el nodo intermedio `Code in JavaScript1` y `Limpiar texto` actuarán como capas de sanitización automáticas.