Actualizar README.md
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user