327 lines
17 KiB
Markdown
327 lines
17 KiB
Markdown
# #TheGLMWay — Workflow de Automatización Onboarding (n8n)
|
||
|
||
> **Sistema automatizado que detecta nuevos ingresos en BambooHR, los inscribe en la sesión de GLM Way correspondiente a su idioma, gestiona toda la comunicación pre-sesión y recolecta la evaluación post-sesión.**
|
||
>
|
||
> **ID Workflow:** `F1iPg8hktNAebZua` · **Nombre:** `GLMWay` · **Timezone:** `America/Santo_Domingo` · **Estado:** Activo
|
||
|
||
---
|
||
|
||
## 1. Propósito
|
||
|
||
Centralizar y automatizar el ciclo de vida completo de la capacitación **#TheGLMWay** para nuevos colaboradores:
|
||
|
||
1. Detectar el ingreso (hireDate) en **BambooHR** el día 1.
|
||
2. Asignar al colaborador a la **sesión más cercana** según su idioma (país → ES/EN).
|
||
3. Notificarle por email con fecha, hora localizada y enlace de Meet.
|
||
4. Avisar al **coordinador RRHH** del país y al **facilitador** 48h / 24h antes.
|
||
5. Enviar **recordatorio** al colaborador 24h antes.
|
||
6. Verificar **asistencia real** vía Google Meet API y enviar **evaluación** (Google Forms) post-sesión.
|
||
7. Medir métricas de evaluaciones enviadas/respondidas.
|
||
|
||
Todo persiste en **Supabase** (`inscritos_glmway`, `sesiones_glmway`, `coordinadores_rrhh_glmway`) y se sincroniza con **Google Calendar / Sheets / Chat**.
|
||
|
||
---
|
||
|
||
## 2. Arquitectura General
|
||
|
||
```
|
||
BambooHR (Webhook + Polling) ─┬─► Supabase (inscritos_glmway)
|
||
│
|
||
Google Calendar (ethen@) ─────┼─► Supabase (sesiones_glmway)
|
||
Google Sheets (Calendario) ───┼─► Supabase (coordinadores_rrhh_glmway)
|
||
│
|
||
├─► Gmail (notificación + recordatorio + evaluación)
|
||
├─► Google Chat (facilitador + coordinadores RRHH)
|
||
└─► WhatsApp Evolution API (alerta sin coordinador)
|
||
Meet API ─────────────────────► Asistencia ─► Evaluación
|
||
Gitea (git.digitalcompass.agency) ─► Backup JSON del workflow
|
||
```
|
||
|
||
**Credenciales utilizadas:**
|
||
|
||
| Servicio | Credencial n8n | Uso |
|
||
|---|---|---|
|
||
| BambooHR | `Eidan - BambooHR account` + `GLM Credential` (Basic Auth) | `Get an employee`, `HTTP /employees/{id}` |
|
||
| Supabase | `Sofia test - Supabase account` | Tablas `inscritos_glmway`, `sesiones_glmway`, `coordinadores_rrhh_glmway`, RPCs |
|
||
| Gmail | `Eidan - Gmail account` (OAuth2) | 10 nodos `Send a message` |
|
||
| Google Calendar | `Eidan - Google Calendar account` | Lectura `ethen@gomezleemarketing.com` query `#TheGLMWay` |
|
||
| Google Sheets | `Eidan - Google Sheets account` | Sheet `1Xs-MkeXiZvWeJuwm-IblcI-ilr7lyhMtED0R7wczmRg` |
|
||
| Google Chat | `Eidan - Chat account` (OAuth) | Spaces `AAQAgX1mjaY` (GLMWay), `AAQAQj1t9AA` (RRHH) |
|
||
| Google Contacts | `Eidan - Google Contacts account` | Resolución `contactId` para menciones `<users/...>` en Chat |
|
||
| Google Meet | `Eidan - Google account` (OAuth2) | `meet.googleapis.com/v2/conferenceRecords` |
|
||
| Gitea | `Eidan - gitea` (headerAuth) | Backup `mgomez/calendario-glm-way:glmway-workflow.json` |
|
||
| n8n API | `Eidan - n8n account` | `Get a workflow` para backup |
|
||
| WhatsApp | Evolution API `wsp.gomezleemarketing.com` `botsoporte` | Alerta a `18494105855@s.whatsapp.net` |
|
||
|
||
---
|
||
|
||
## 3. Modelo de Datos (Supabase)
|
||
|
||
### `inscritos_glmway`
|
||
| Campo | Tipo | Descripción |
|
||
|---|---|---|
|
||
| `empleado_id` | text PK | ID BambooHR |
|
||
| `nombre` | text | displayName |
|
||
| `email` | text | workEmail |
|
||
| `departamento` | text | department |
|
||
| `division` | text | division |
|
||
| `puesto` | text | jobTitle |
|
||
| `pais` | text | location (BambooHR) |
|
||
| `fecha_ingreso` | date | hireDate `YYYY-MM-DD` |
|
||
| `fecha_sesion_inscrito` | text | `"14 January"` (sesión asignada) |
|
||
| `sesion_id` | text | FK `sesiones_glmway.id` |
|
||
| `estado` | text | `inactivo` → `notificado` → `recordado` → `evaluacion_enviada` |
|
||
| `coordinador_rrhh` | text | nombre coordinador del país |
|
||
| `instructor` | text | actualizado post-sesión |
|
||
| `asistio_evento_glmway` | bool | asistencia detectada Meet |
|
||
| `fecha_sesion_inscrito` | text | reutilizado para cálculo 24h |
|
||
|
||
**Estados:** `inactivo` (registrado sin email), `notificado` (email inicial enviado), `recordado` (recordatorio 24h), `evaluacion_enviada` (evaluación enviada).
|
||
|
||
### `sesiones_glmway`
|
||
| Campo | Descripción |
|
||
|---|---|
|
||
| `id` / `meet_id` | ID evento Calendar / Meet |
|
||
| `titulo` | `"Entrenamiento #TheGLMWay"` o `"#TheGLMWay Training"` |
|
||
| `fecha_sesion` | `"14 January"` |
|
||
| `hora_inicio` / `hora_fin` | `HH:mm` (hora Santo Domingo) |
|
||
| `instructor` | Nombre del facilitador |
|
||
| `correo_instructor` | Email |
|
||
| `enlace_reunion` / `url` | Meet link |
|
||
| `idioma` | `ES` / `EN` |
|
||
| `participantes` | JSONB `{"RD": [{nombre, correo, departamento, division}], "Mexico": [...]}` |
|
||
|
||
RPCs: `insertar_participantes_sesion_glmway(p_sesion_id, p_pais, p_empleados)`, `sync_sesiones_glmway`, `insertar_coordinadores_rrhh_glmway`, `incrementar_evaluaciones_enviadas_glmway`, `incrementar_evaluaciones_resueltas_glmway`.
|
||
|
||
### `coordinadores_rrhh_glmway`
|
||
| Campo | Descripción |
|
||
|---|---|
|
||
| `pais` | País asignado |
|
||
| `nombre` | Nombre completo |
|
||
| `correo` | Email |
|
||
| `estado` | `no_notificado` (filtro) |
|
||
|
||
---
|
||
|
||
## 4. Lógica de Idioma por País
|
||
|
||
```js
|
||
// ES = país NO está en lista Caribe anglófono
|
||
// EN = país SÍ está en lista
|
||
["Jamaica","Trinidad and Tobago","Barbados","Saint Thomas","St. Croix","Tobago","Guyana","Aruba"]
|
||
```
|
||
|
||
Todos los nodos `Pais?`, `Pais?1`, `Pais?2`, `Pais?3`, `Pais?4` usan esta lista. Si falta coordinador para el país, se dispara alerta WhatsApp a Matos (`18494105855`).
|
||
|
||
Conversión de hora: todos los `Cambiar zona horaria*` (6 nodos) toman `hora_inicio` en `America/Santo_Domingo` como base y la convierten con `Intl.DateTimeFormat` al timezone del país del colaborador (mapa `TIMEZONES` con 25 países).
|
||
|
||
---
|
||
|
||
## 5. Flujos Detallados (10 sub-workflows en 1 workflow)
|
||
|
||
### Flujo A — Notificación Inicial (Webhook BambooHR)
|
||
**Trigger:** `Webhook POST /glmway` (BambooHR webhook nuevos ingresos)
|
||
```
|
||
Webhook → Get an employee → Info extra (hireDate, supervisorEmail, jobTitle)
|
||
→ Calcular fecha hireDate (isValid = hireDate <= today)
|
||
→ Tiene correo y pais? ─┬─ NO → Insertar inscritos (inactivo)
|
||
└─ SI → Entra hoy? ─┬─ NO → Insertar inscritos (inactivo)
|
||
└─ SI → Obtener coordinador3
|
||
→ Hay coordinador? ─ NO → Alerta WhatsApp + Pais?
|
||
SI → Pais? → [ES/EN]
|
||
→ Crear variable idioma
|
||
→ Obtener sesiones (filtro idioma)
|
||
→ Calcular sesion mas cercana
|
||
→ Guardar datos empleado+sesion (estado=notificado)
|
||
→ Convertir fecha a es/en
|
||
→ Cambiar zona horaria
|
||
→ Send Gmail (ES/EN)
|
||
→ Registrar empleado a sesión (RPC)
|
||
```
|
||
*Templates Gmail:* `Entrenamiento #TheGLMWay` / `#TheGLMWay Training` con `fechaFormateada`, `hora_convertida`, `enlace_reunion`.
|
||
|
||
### Flujo B — Reintento Inactivos (Polling Horario)
|
||
**Trigger:** `Schedule Trigger1` — cada hora
|
||
```
|
||
Obtener inactivos (estado=inactivo) → Loop Over Items (SplitInBatches)
|
||
→ Get an employee1 → Info extra 1 → Calcular fecha hireDate1 → Tiene correo y pais?1
|
||
→ Entra hoy?1 ─ SI → Obtener coordinador4 → Hay coordinador?1 → Pais?1 → (mismo camino ES/EN)
|
||
→ Actualizar datos del empleado y sesion asignada → ... → Send Gmail 1
|
||
→ NO → Wait2 2s → Loop
|
||
```
|
||
|
||
### Flujo C — Recordatorio 24h al Colaborador
|
||
**Trigger:** `Schedule Trigger2` — martes y miércoles 17:00
|
||
```
|
||
Obtener notificados (estado=notificado) → Loop Over Items1
|
||
→ Calcular falta 24h o es el mismo dia (parsea "14 December", diferenciaDias 0-1)
|
||
→ Falta 24h para el evento? ─ SI → Obtener sesion → Pais?2 → Convertir fecha 2
|
||
→ Cambiar zona horaria 4/5 → Send Gmail recordatorio
|
||
→ Actualizar estado a recordado → Wait1 2s → Loop
|
||
─ NO → Wait1 → Loop
|
||
```
|
||
*Asunto recordatorio ES:* `Entrenamiento #TheGLMWay` — *Texto:* “Te recordamos que la sesión será el {{fecha}} a las {{hora}}...”
|
||
|
||
### Flujo D — Notificación a Facilitador (48h / día del evento)
|
||
**Trigger:** `Schedule Trigger` — miércoles 16:00
|
||
```
|
||
Obtener sesion1 (todas) → Calcular sesion mas cercana4 (match hoy)
|
||
→ Obtener miembros (Chat Space AAQAgX1mjaY) → Limpiar id → Get a contact → Unir datos2
|
||
→ Hay inscritos? ─ SI → Es espanol o ingles1 (switch por idioma sesión)
|
||
→ Formatear datos ingles/espanol (card con totalParticipantes, enlace)
|
||
→ Enviar notificación a glmway notificaciones
|
||
─ NO → Es espanol o ingles (switch)
|
||
→ Formatear datos ingles1/espanol1 (card “No hay participantes”)
|
||
→ Enviar notificación
|
||
```
|
||
*Si hay inscritos:* `🔔 *Recordatorio de #TheGLMWay para hoy* \n Instructor: <users/...>` con `totalParticipantes` y `Entrar a reunión`. *Si no:* `🔔 *Aviso de sesión sin participantes*`.
|
||
|
||
### Flujo E — Notificación a Coordinador RRHH (48h + 24h)
|
||
**Trigger:** `Schedule Trigger3` — martes 16:00 + miércoles 16:00
|
||
```
|
||
Obtener sesiones (all) → Calcular falta 48h o 24h1 (sesión más cercana futura)
|
||
→ Hay inscritos en la sesion? ─ SI → Obtener coordinadores1 (estado=no_notificado filtro)
|
||
→ Matchear coordinador y pais inscrito (normaliza acentos)
|
||
→ Obtener miembros RRHH (AAQAQj1t9AA) → Limpiar id1 → Get a contact1
|
||
→ Unir datos3 (match nombre coordinador ↔ Google Contact)
|
||
→ Pais?3 → Formatear datos ingles2/espanol2
|
||
→ Enviar notificación a rrhh notificaciones
|
||
```
|
||
*Card RRHH:* `🔔 *Aviso para Coordinadores RRHH*` con `Total inscritos: X` + listado por país `📍 RD (2): • Nombre (Depto | División)`.
|
||
|
||
### Flujo F — Post-Sesión: Asistencia + Evaluación
|
||
**Trigger:** `Schedule Trigger7` — miércoles 19:50 (post-sesión)
|
||
```
|
||
Hora de la reunion (timestamp → startTime T22:50:24Z, endTime T24:00:00Z, fechaCorta "11 August")
|
||
→ Obtener conferenceRecord (Meet API v2) → Buscar sesion con hora UTC (filtra por fecha, distanciaMs mínima)
|
||
→ Obtener participantes (conferenceRecords/{name}/participants)
|
||
→ Detectar participantes en la sesion (extrae signedinUser.displayName)
|
||
→ Obtener sesion2 (por fecha_sesion) ─┬─→ Buscar participantes (match normalizado displayName ↔ nombre registrado)
|
||
│ └─→ Actualizar instructor de inscritos
|
||
→ Split Out (participantes) → Actualizar asistencia (supabase asistio_evento_glmway bool, wfts por nombre)
|
||
→ Asistio? (solo si asistio=false se envía evaluación — filtra asistentes? verificar lógica)
|
||
→ Cortar nombre (primerNombre) → Pais?4 → Send Gmail evaluación (HTML con branding GLM + botón Google Forms)
|
||
→ Actualizar estado a evaluacion_enviada → Incrementar conteo evaluaciones enviadas (RPC)
|
||
```
|
||
*Evaluación ES:* `Evaluación #TheGLMWay` → `https://docs.google.com/forms/d/e/1FAIpQLSf8QUfmXulvw4e9BwZjTFG4mEUWybdFSAes_dK-OFnWN-L43Q/viewform` con header `#2d3748` + logo GLM. *EN:* `#TheGLMWay Quiz` → `...Sf61KpkDr...`.
|
||
|
||
### Flujo G — Webhook Evaluación Respondida
|
||
**Trigger:** `Webhook1 POST /evaluacion-glmway`
|
||
```
|
||
Webhook1 → Incrementar conteo de evaluaciones respondidas (RPC incrementar_evaluaciones_resueltas_glmway)
|
||
```
|
||
|
||
### Flujo H — Sincronización Anual Calendario → Sheets
|
||
**Trigger:** `Schedule Trigger4` — `0 0 0 1 1 *` (1 de enero)
|
||
```
|
||
Obtener entrenamientos ingles y espanol (Calendar año completo query #TheGLMWay)
|
||
→ Formatear fecha (DD Month) → Borrar fechas (Sheets rango A2:D80) → Wait4 → Insertar fechas (appendOrUpdate por Fecha)
|
||
```
|
||
|
||
### Flujo I — Sincronización Diaria Coordinadores
|
||
**Trigger:** `Schedule Trigger5` — diario 11:00
|
||
```
|
||
Obtener coordinadores (Sheets “Coordinadores RRHH”) → Aggregate (input) → Insertar/actualizar coordinadores a la bd (RPC)
|
||
```
|
||
|
||
### Flujo J — Sincronización Diaria Sesiones
|
||
**Trigger:** `Schedule Trigger6` — miércoles 15:00
|
||
```
|
||
Obtener fechas e instructores (Sheets Calendario)
|
||
+ Obtener entrenamientos ingles y espanol1 (Calendar)
|
||
→ Formatear fecha y detectar idioma (detecta "#TheGLMWay Training"→EN, "Entrenamiento #TheGLMWay"→ES, extrae hora_inicio/fin, url)
|
||
→ Unir datos (merge por Fecha) → Edit Fields (meet_id, titulo, fecha_sesion, hora_inicio/fin, instructor, correo_instructor, enlace_reunion, idioma)
|
||
→ Aggregate1 → Insertar fechas1 (RPC sync_sesiones_glmway)
|
||
```
|
||
|
||
### Flujo K — Backup Automático del Workflow
|
||
**Trigger:** `When clicking ‘Execute workflow’` (manual)
|
||
```
|
||
Valores (mgomez / calendario-glm-way / glmway-workflow)
|
||
→ Obtener archivo (Gitea GET contents/*.json) ─┬─ éxito (onError continue) → Get a workflow1 → Code JS2 (base64 JSON + sha) → Actualizar archivo (PUT)
|
||
└─ error (no existe) → Get a workflow2 → Code JS4 (base64) → Subir archivo (POST)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Diagrama de Estados del Inscrito
|
||
|
||
```
|
||
[BambooHR hireDate futuro] ──► inactivo (insertado sin email/sin fecha)
|
||
│
|
||
▼ (hireDate == today, con coordinador)
|
||
notificado ──► (24h antes) ──► recordado
|
||
│
|
||
▼ (post-sesión Meet)
|
||
evaluacion_enviada ──► (webhook) conteo respondida++
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Notificaciones
|
||
|
||
| Destinatario | Canal | Cuándo | Formato |
|
||
|---|---|---|---|
|
||
| Nuevo ingreso | Gmail | Día 1 (Flujo A/B) | Texto plano ES/EN con fecha, hora local, Meet link |
|
||
| Nuevo ingreso | Gmail | 24h antes (Flujo C) | Recordatorio ES/EN |
|
||
| Facilitador | Google Chat `AAQAgX1mjaY` | Miércoles 16:00 (Flujo D) | CardV2 con mención `<users/...>` + total participantes |
|
||
| Coordinador RRHH | Google Chat `AAQAQj1t9AA` | Mar/Mié 16:00 (Flujo E) | CardV2 por país con listado detallado |
|
||
| Coordinador RRHH | WhatsApp | Sin coordinador (Flujo A/B) | `⚠️ No hay coordinador RRHH en el país...` |
|
||
| Inscrito | Gmail | Post-sesión 19:50 (Flujo F) | HTML evaluación con botón a Google Forms |
|
||
|
||
---
|
||
|
||
## 8. Instalación y Configuración
|
||
|
||
### Requisitos
|
||
- n8n ≥ 1.x con timezone `America/Santo_Domingo`
|
||
- Credenciales: BambooHR API Key, Supabase service_role, Google OAuth (Calendar, Sheets, Gmail, Meet, Chat, Contacts), Gitea token, Evolution WhatsApp API key
|
||
- Supabase: crear tablas + RPCs (`insertar_participantes_sesion_glmway`, `sync_sesiones_glmway`, etc.)
|
||
- Google Sheet `Calendario #TheGLMWay` con hojas `Calendario` (col Fecha) y `Coordinadores RRHH`
|
||
|
||
### Importar
|
||
1. n8n → `Import from File` → `GLMWay.json`
|
||
2. Reasignar credenciales (IDs en JSON son de instancia origen `Eidan`)
|
||
3. Activar workflow
|
||
4. Configurar webhook BambooHR → `https://<n8n>/webhook/glmway` (POST)
|
||
5. Verificar `Schedule Triggers` — respetar horario Santo Domingo
|
||
|
||
### Variables Clave a Revisar
|
||
- `WEBHOOK_URL` base, `wsp.gomezleemarketing.com` apikey, `git.digitalcompass.agency` repo, `ethen@gomezleemarketing.com` calendar, Chat Space keys/tokens (rotar — están hardcodeados en nodos HTTP), Supabase URL `dbit.digitalcompass.agency`.
|
||
|
||
---
|
||
|
||
## 9. Operación y Monitoreo
|
||
|
||
- **Error Workflow:** `lX5ITf9s4TSQglsM` (configurado en `settings.errorWorkflow`) — revisar ejecuciones fallidas.
|
||
- **Reintentos:** `Informacion extra del empleado` con retry 2s, otros con `retryOnFail: true`.
|
||
- **Loops:** `Loop Over Items` / `Loop Over Items1` con `Wait` 2s para evitar rate-limit BambooHR/Gmail.
|
||
- **Logs:** `console.log` en nodos Code (`Sesiones procesadas`, eventos ignorados).
|
||
- **PinData:** Triggers con datos de prueba agosto 2026 — remover en prod.
|
||
|
||
---
|
||
|
||
## 10. Riesgos y Recomendaciones
|
||
|
||
| Riesgo | Mitigación sugerida |
|
||
|---|---|
|
||
| Tokens Chat hardcodeados (`key=AIza...&token=...`) en URLs | Migrar a credencial `googleChatOAuth2Api` o variable de entorno, rotar tokens |
|
||
| `service_role` JWT expuesto en nodos HTTP | Mover a credencial Header Auth, no en claro |
|
||
| `TIMEZONES` incompleto (faltan países GLM) | Centralizar en tabla `paises_timezones` |
|
||
| Parseo fecha `"14 January"` frágil (locale/año) | Usar `date-fns` con año explícito o ISO en `sesiones_glmway` |
|
||
| Duplicados por webhook + polling horario | Añadir constraint único `empleado_id` + upsert |
|
||
| `Wait` fijo 2s puede exceder límites Gmail (100/día) | Batch con `SplitInBatches` size controlado |
|
||
|
||
---
|
||
|
||
## 11. Archivos Relacionados
|
||
|
||
- `GLMWay.json` — definición completa del workflow (importable en n8n)
|
||
- `README_GLMWay.md` — este documento
|
||
|
||
---
|
||
|
||
*Documentado a partir de `GLMWay.json` v`f657df3d-e5b6-445e-ad75-df66da81ebf3` — última edición inspeccionada 27/08/2026.*
|
||
*GomezLee Marketing — Automatización #TheGLMWay.*
|
||
|