Pular para o conteúdo

Sistema de Eventos

O sistema de eventos é responsável por registrar TODAS as atividades da plataforma em um formato padronizado. Cada evento é armazenado na tabela events e pode disparar automações via dispatchEventToAutomations().

Fonte do Evento
|
v
emitEvent() [event-emitter.ts]
|
+-> Validar contactId existe no account
+-> Upsert metric (tabela metrics)
+-> Deduplicar via unique_event_id
+-> Inserir evento (tabela events)
+-> dispatchEventToAutomations() [trigger-dispatcher.ts]
|
+-> Buscar automações com trigger_metric = metricName
+-> Executar automações correspondentes
ArquivoDescrição
src/lib/events/event-emitter.tsemitEvent() - função principal
src/lib/events/constants.tsConstantes de métricas + categorias
src/lib/events/metric-mapping.tsMapeamento trigger <-> metric
src/lib/events/metric-labels.tsLabels i18n (pt-BR, en, es)

Função principal para registrar eventos. Fire-and-forget na maioria dos usos (chamada com .catch(() => {})).

interface EmitEventParams {
accountId: string // Conta dona do evento
contactId: string | null // Contato associado (obrigatório para registro)
metricName: string // Nome da métrica (ex: "Order Placed")
properties: Record<string, unknown> // Dados adicionais do evento
value?: number // Valor numérico (ex: valor do pedido)
currency?: string // Moeda (padrão: "BRL")
source: string // Fonte (ex: "whatsapp", "shopify", "automation")
sourceId?: string // ID único na fonte (para deduplicação)
integrationId?: string // ID da integração e-commerce
entityType?: string // Tipo da entidade (ex: "message", "order")
entityId?: string // ID da entidade
occurredAt?: string // Quando ocorreu (padrão: now)
}
  1. Validação de contactId: Se contactId ausente, loga warning e retorna null
  2. Validação de contato: Verifica que contactId pertence ao accountId via query
  3. Upsert metric: Cria registro em metrics se não existir (evita duplicata com race condition)
  4. Deduplicação: Se sourceId presente, gera unique_event_id = "{source}:{entityType}:{sourceId}" e verifica se já existe
  5. Insert evento: Insere em events com todos os campos. Se duplicate key (23505), retorna ID existente
  6. Dispatch automações: Chama dispatchEventToAutomations() fire-and-forget

O unique_event_id previne que o mesmo evento seja registrado duas vezes (ex: webhook duplicado).

Formato: {source}:{entityType || "event"}:{sourceId} Exemplo: whatsapp:message:wamid.HBgM...

Se um insert falha com código 23505 (unique constraint), o sistema busca o evento existente e retorna seu ID.

ConstanteValor
METRIC_ORDER_PLACED”Order Placed”
METRIC_ORDER_PAID”Order Paid”
METRIC_ORDER_CANCELLED”Order Cancelled”
METRIC_ORDER_FULFILLED”Order Fulfilled”
METRIC_ORDER_REFUNDED”Order Refunded”
METRIC_CHECKOUT_STARTED”Checkout Started”
METRIC_CHECKOUT_ABANDONED”Checkout Abandoned”
METRIC_CHECKOUT_RECOVERED”Checkout Recovered”
METRIC_CUSTOMER_CREATED”Customer Created”
ConstanteValor
METRIC_MESSAGE_RECEIVED”Message Received”
METRIC_MESSAGE_SENT”Message Sent”
METRIC_MESSAGE_DELIVERED”Message Delivered”
METRIC_MESSAGE_READ”Message Read”
METRIC_MESSAGE_FAILED”Message Failed”
METRIC_TEMPLATE_SENT”Template Sent”
METRIC_TEMPLATE_DELIVERED”Template Delivered”
METRIC_TEMPLATE_READ”Template Read”
METRIC_CAMPAIGN_SENT”Campaign Sent”
METRIC_AI_RESPONSE_SENT”AI Response Sent”
ConstanteValor
METRIC_SHIPMENT_CREATED”Shipment Created”
METRIC_SHIPMENT_IN_TRANSIT”Shipment In Transit”
METRIC_SHIPMENT_OUT_FOR_DELIVERY”Shipment Out For Delivery”
METRIC_SHIPMENT_DELIVERED”Shipment Delivered”
METRIC_SHIPMENT_EXCEPTION”Shipment Exception”
ConstanteValor
METRIC_LINK_CLICKED”Link Clicked”
ConstanteValor
METRIC_CONTACT_CREATED”Contact Created”
METRIC_CONTACT_UPDATED”Contact Updated”
METRIC_TAG_ADDED”Tag Added”
METRIC_TAG_REMOVED”Tag Removed”
METRIC_CONVERSATION_OPENED”Conversation Opened”
METRIC_CONVERSATION_CLOSED”Conversation Closed”
METRIC_CONVERSATION_ASSIGNED”Conversation Assigned”
CategoriaDescrição
ecommercePedidos, checkout, carrinhos
messagingMensagens WhatsApp, templates, campanhas
trackingRastreamento de envios
engagementCliques em links
contactContatos, tags, conversas
customEventos customizados (fallback)

getMetricCategory(metricName) retorna a categoria baseado no METRIC_CATEGORY_MAP.

Mapeia entre trigger types e metric names:

{
order_created: "Order Placed",
order_paid: "Order Paid",
checkout_created: "Checkout Started",
cart_abandoned: "Checkout Abandoned",
tracking_updated: "Shipment In Transit",
message_received: "Message Received",
new_contact: "Contact Created",
tag_added: "Tag Added",
webhook: "__webhook__",
schedule: "__schedule__",
}
{
"Order Placed": "order_created",
"Order Paid": "order_paid",
"Checkout Started": "checkout_created",
"Checkout Abandoned": "cart_abandoned",
"Shipment In Transit": "tracking_updated",
"Message Received": "message_received",
"Contact Created": "new_contact",
"Tag Added": "tag_added",
}

Labels internacionalizados para exibição na UI:

getMetricLabel("Order Placed", "pt-BR") // "Pedido Criado"
getMetricLabel("Order Placed", "en") // "Order Placed"
getMetricLabel("Order Placed", "es") // "Pedido Creado"

33 métricas com labels em 3 idiomas: pt-BR, en, es.

id UUID PK
account_id UUID FK
contact_id UUID FK
metric_id UUID FK -> metrics
metric_name TEXT
properties JSONB
value NUMERIC (nullable)
currency TEXT (default: "BRL")
source TEXT
integration_id UUID FK (nullable)
unique_event_id TEXT UNIQUE (nullable)
entity_type TEXT (nullable)
entity_id TEXT (nullable)
occurred_at TIMESTAMPTZ
received_at TIMESTAMPTZ
schema_version INTEGER
created_at TIMESTAMPTZ
id UUID PK
account_id UUID FK
name TEXT
display_name TEXT
category (ecommerce|messaging|tracking|engagement|contact|custom)
source TEXT
is_system BOOLEAN
created_at TIMESTAMPTZ
UNIQUE(account_id, name)
id UUID PK
account_id UUID FK
contact_id UUID FK
metric_name TEXT
event_count INTEGER
total_value NUMERIC
first_event_at TIMESTAMPTZ
last_event_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

Tabela materializada (provavelmente via trigger/pg_cron) para queries rapidas de analytics por contato.

1. Shopify envia webhook -> /api/integrations/shopify/webhook
2. Webhook handler normaliza dados (normalizer.ts)
3. Upsert contato + pedido no banco
4. emitEvent("Order Paid", { contactId, properties: { order_id, total, ... }, value: 297.90 })
5. Evento salvo na tabela events
6. dispatchEventToAutomations("Order Paid", { contact_id, properties, value })
7. Automações com trigger_metric "Order Paid" são encontradas e executadas
1. Meta envia webhook -> /api/whatsapp/webhook
2. Webhook handler processa mensagem
3. emitEvent("Message Received", { contactId, properties: { phone, message_type, wa_message_id } })
4. dispatchTrigger("message_received", { contact_id, message, from, ... })
5. Automações com trigger_type "message_received" são encontradas e executadas

Evento de automação (ex: mensagem enviada por step)

Seção intitulada “Evento de automação (ex: mensagem enviada por step)”
1. Step send_message executa com sucesso
2. emitEvent("Message Sent", { contactId, properties: { phone, wa_message_id, automation_execution_id } })
3. dispatchEventToAutomations("Message Sent", ...) -- mas ignora se _fromAutomation = true
LocalMétricaFonte
WhatsApp webhook (inbound msg)Message Receivedwhatsapp
WhatsApp webhook (status: delivered)Message Delivered / Template Deliveredwhatsapp
WhatsApp webhook (status: read)Message Read / Template Readwhatsapp
WhatsApp webhook (status: failed)Message Failedwhatsapp
Step send_messageMessage Sentautomation
Step send_templateTemplate Sentautomation
Step add_tagTag Addedautomation
Step remove_tagTag Removedautomation
Step close_conversationConversation Closedautomation
Step ai_respondAI Response Sentautomation
E-commercé webhooksOrder Placed, Order Paid, etc.shopify/yampi/…
Campanha enviadaCampaign Sentcampaign
Link rastreado clicadoLink Clickedtracking