Disponible en el plan Corporate. Esta funcionalidad forma parte de las capacidades empresariales de woku. Conversa con nuestro equipo comercial.
- NPS bajo asigna a supervisor: cuando una respuesta de NPS marca menor a 7, asigna al supervisor de la sucursal y le manda un WhatsApp.
- Texto con queja crítica: si la respuesta menciona la palabra “denuncia” o “abogado”, manda un email al equipo legal y abre un webhook a Salesforce.
- SLA vulnerado: si una respuesta lleva más de 60 minutos sin
ser atendida, escala a la jefatura y cambia el estado a
urgent.
Anatomía de una regla
| Campo | Tipo | Descripción |
|---|---|---|
name | string | Nombre visible. |
description | string opcional | Para qué sirve. |
trigger | { type: 'event' | 'cron', events?, cronExpression? } | Cómo se activa. |
conditions | { all: [...] } o { any: [...] } | Grupo top-level de condiciones (compatible con json-rules-engine). |
actions | array | Acciones inmediatas al matchear (orden importa). |
escalations | array | Sub-listas con afterMin para acciones diferidas. |
enabled | booleano | Si está activa. |
priority | número | Prioridad de evaluación (menor = primero). |
metrics | { totalFired, totalEscalated, lastFiredAt } | Contadores en vivo. |
Triggers
event, la regla se evalúa en cadaform-response.created. La evaluación corre en un listener, no en el path del HTTP, así que no agrega latencia al endpoint que crea la respuesta.cron, la regla se evalúa cada 5 minutos (V1) sobre las respuestas no cerradas en las últimas 72 horas. Aquí caen las reglas tipo SLA o detección de volumen bajo.
Condiciones
conditions es exactamente lo que consume json-rules-engine. La
forma mínima es:
equal, notEqual, lessThan, lessThanInclusive, greaterThan,
greaterThanInclusive, in, notIn, contains, doesNotContain.
Operadores custom Woku:
stringContains,factValue.toLowerCase().includes(jsonValue.toLowerCase()).
all representa AND, any representa OR. Para V1 el builder visual
soporta árboles de un solo nivel; la API acepta árboles anidados a
cualquier profundidad, un JSON guardado a mano funciona.
Facts disponibles
El evaluador construye un fact bag por respuesta:| Fact | Origen |
|---|---|
score | Primer valor numérico en answers. Apunta al NPS por convención. |
textConcat | Concatenación lowercased de todos los strings en answers. Útil para stringContains. |
formResponseId, formId, companyId | Ids del contexto. |
createdAt | ISO timestamp. |
sla_elapsed | Solo en cron: minutos transcurridos desde createdAt. |
cualquier key de answers | Cada campo del formulario es un fact independiente. |
Acciones
| Tipo | Parámetros | Efecto |
|---|---|---|
assign_user | userId | FormResponse.assignedTo = userId. |
change_status | status | FormResponse.status = status. Si el status nuevo cae en {closed, resolved, dismissed}, dispara cancelación de escalamientos pendientes. |
send_webhook | url, headers? | POST con { alertRuleId, alertRuleExecutionId, companyId, formResponseId, formId, facts, firedAt, isEscalation }. Timeout 10 s, retry 3x exponencial. |
send_email | to, subject? | V1 logged-only; el módulo de mail engancha esta rama en un follow-up. |
send_whatsapp | to, template?, params? | V1 logged-only; mismo plan que send_email. |
alertActionsQueue, concurrencia
10) y se ejecutan independientemente. El orden de la lista se
preserva en la cola.
Escalamientos
Cada entrada deescalations define un retraso y una sub-lista de
acciones:
delay = afterMin * 60_000. Si después la respuesta entra en un
status terminal (closed/resolved/dismissed), los jobs pendientes
se cancelan y la ejecución se marca como cerrada.
Además, los jobs de escalamiento chequean execution.closedAt antes
de ejecutarse: si el cierre fue muy reciente, el job se vuelve no-op
incluso si el removeJob no llegó a tiempo. Esto cubre la ventana
de carrera entre el cambio de estado y la cancelación.
Builder
El menú Reglas de alerta lleva al listado por empresa. Desde ahí se puede crear, editar, eliminar o probar una regla. El builder tiene cinco pestañas:- General: nombre, descripción, tipo de trigger, prioridad, habilitada.
- Condiciones: lista de condiciones leaf con operador raíz
AND/OR. Cada fila pide
fact,operator,value. La serialización convierte"7"a7,"true"atrue, valores con coma a arrays parain/notIn. - Acciones: lista drag-to-reorder con
@dnd-kit. El tipo de acción determina los campos que pide. - Escalamientos: lista de
{ afterMin, actions, cancelIfClosed }, con la misma UI de acciones anidada. - Vista previa: render del JSON exacto que se envía al servidor.
Simulador
El botón Probar en cada fila del listado abre un modal que ejecuta una simulación (dry-run). Pide un JSON conanswers y
opcionalmente extraFacts, y devuelve:
matched: si la regla habría coincidido.actionsWouldFire: la lista de acciones que se dispararían.facts: el fact bag exacto que vio el motor.
FormResponse, no envía
emails ni webhooks. Es la herramienta para validar una regla antes
de exponerla a producción.
Garantías
- Aislamiento entre reglas: cada regla se evalúa en su propio try/catch. Una regla con un operador inexistente o condiciones malformadas no impide que las demás se evalúen.
- Backpressure: las acciones corren en una cola dedicada con concurrencia 10. Una racha de respuestas no bloquea el path síncrono.
- Idempotencia: cada fire crea un
AlertRuleExecutionconactionJobIds+escalationJobIds. Los jobs de escalamiento vuelven a chequearclosedAtantes de ejecutarse. - Dedup en cron: el evaluador cron-based no dispara dos veces la misma regla contra la misma respuesta dentro de una ventana de 24 horas (la ejecución previa es el token).
- Auditable: cada CRUD de regla queda registrado en el audit
log como
alert-rule.create/update/delete.
Limitaciones conocidas (V1)
send_emailysend_whatsappson stubs que loguean la intención. El módulo de mail y el de WhatsApp engancharán esas ramas en una iteración siguiente sin cambiar el contrato del dispatcher.- Sin builder de árboles anidados: el editor visual cubre un
nivel
alloany. Para reglas con anidamiento dealldentro deany(o viceversa) hay que editar el JSON directamente vía API. - Sin agente IA como acción: el plan original menciona acciones de LangChain, quedan para una iteración futura.
- Statuses terminales hard-coded: V1 considera
{closed, resolved, dismissed}como terminales. Una iteración siguiente permitirá overrides por empresa. - El cron corre cada 5 minutos. Para reglas de SLA con SLAs muy cortos (< 5 min) la latencia perceptible es esa frecuencia.