diff --git a/documentacion_workflow_n8n.md b/documentacion_workflow_n8n.md new file mode 100644 index 0000000..c866fae --- /dev/null +++ b/documentacion_workflow_n8n.md @@ -0,0 +1,237 @@ +# 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.