Sistema de Eventos
Visão Geral
Seção intitulada “Visão Geral”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 | vemitEvent() [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 correspondentesArquivos
Seção intitulada “Arquivos”| Arquivo | Descrição |
|---|---|
src/lib/events/event-emitter.ts | emitEvent() - função principal |
src/lib/events/constants.ts | Constantes de métricas + categorias |
src/lib/events/metric-mapping.ts | Mapeamento trigger <-> metric |
src/lib/events/metric-labels.ts | Labels i18n (pt-BR, en, es) |
emitEvent() (event-emitter.ts)
Seção intitulada “emitEvent() (event-emitter.ts)”Função principal para registrar eventos. Fire-and-forget na maioria dos usos (chamada com .catch(() => {})).
Parametros
Seção intitulada “Parametros”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)}Fluxo Detalhado
Seção intitulada “Fluxo Detalhado”- Validação de contactId: Se
contactIdausente, loga warning e retornanull - Validação de contato: Verifica que
contactIdpertence aoaccountIdvia query - Upsert metric: Cria registro em
metricsse não existir (evita duplicata com race condition) - Deduplicação: Se
sourceIdpresente, geraunique_event_id = "{source}:{entityType}:{sourceId}"e verifica se já existe - Insert evento: Insere em
eventscom todos os campos. Se duplicate key (23505), retorna ID existente - Dispatch automações: Chama
dispatchEventToAutomations()fire-and-forget
Deduplicação
Seção intitulada “Deduplicação”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.
Constantes de Métricas (constants.ts)
Seção intitulada “Constantes de Métricas (constants.ts)”Todas as Métricas
Seção intitulada “Todas as Métricas”E-Commerce (ecommerce)
Seção intitulada “E-Commerce (ecommerce)”| Constante | Valor |
|---|---|
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” |
Messaging (messaging)
Seção intitulada “Messaging (messaging)”| Constante | Valor |
|---|---|
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” |
Tracking (tracking)
Seção intitulada “Tracking (tracking)”| Constante | Valor |
|---|---|
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” |
Engagement (engagement)
Seção intitulada “Engagement (engagement)”| Constante | Valor |
|---|---|
METRIC_LINK_CLICKED | ”Link Clicked” |
Contact (contact)
Seção intitulada “Contact (contact)”| Constante | Valor |
|---|---|
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” |
Categorias
Seção intitulada “Categorias”| Categoria | Descrição |
|---|---|
ecommerce | Pedidos, checkout, carrinhos |
messaging | Mensagens WhatsApp, templates, campanhas |
tracking | Rastreamento de envios |
engagement | Cliques em links |
contact | Contatos, tags, conversas |
custom | Eventos customizados (fallback) |
getMetricCategory(metricName) retorna a categoria baseado no METRIC_CATEGORY_MAP.
Metric Mapping (metric-mapping.ts)
Seção intitulada “Metric Mapping (metric-mapping.ts)”Mapeia entre trigger types e metric names:
TRIGGER_TO_METRIC
Seção intitulada “TRIGGER_TO_METRIC”{ 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__",}METRIC_TO_TRIGGER (inverso)
Seção intitulada “METRIC_TO_TRIGGER (inverso)”{ "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",}Metric Labels (metric-labels.ts)
Seção intitulada “Metric Labels (metric-labels.ts)”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.
Modelo de Dados
Seção intitulada “Modelo de Dados”id UUID PKaccount_id UUID FKcontact_id UUID FKmetric_id UUID FK -> metricsmetric_name TEXTproperties JSONBvalue NUMERIC (nullable)currency TEXT (default: "BRL")source TEXTintegration_id UUID FK (nullable)unique_event_id TEXT UNIQUE (nullable)entity_type TEXT (nullable)entity_id TEXT (nullable)occurred_at TIMESTAMPTZreceived_at TIMESTAMPTZschema_version INTEGERcreated_at TIMESTAMPTZmetrics
Seção intitulada “metrics”id UUID PKaccount_id UUID FKname TEXTdisplay_name TEXTcategory (ecommerce|messaging|tracking|engagement|contact|custom)source TEXTis_system BOOLEANcreated_at TIMESTAMPTZUNIQUE(account_id, name)contact_metrics_summary
Seção intitulada “contact_metrics_summary”id UUID PKaccount_id UUID FKcontact_id UUID FKmetric_name TEXTevent_count INTEGERtotal_value NUMERICfirst_event_at TIMESTAMPTZlast_event_at TIMESTAMPTZupdated_at TIMESTAMPTZTabela materializada (provavelmente via trigger/pg_cron) para queries rapidas de analytics por contato.
Pipeline Completo
Seção intitulada “Pipeline Completo”Evento de e-commerce (ex: pedido pago no Shopify)
Seção intitulada “Evento de e-commerce (ex: pedido pago no Shopify)”1. Shopify envia webhook -> /api/integrations/shopify/webhook2. Webhook handler normaliza dados (normalizer.ts)3. Upsert contato + pedido no banco4. emitEvent("Order Paid", { contactId, properties: { order_id, total, ... }, value: 297.90 })5. Evento salvo na tabela events6. dispatchEventToAutomations("Order Paid", { contact_id, properties, value })7. Automações com trigger_metric "Order Paid" são encontradas e executadasEvento de WhatsApp (ex: mensagem recebida)
Seção intitulada “Evento de WhatsApp (ex: mensagem recebida)”1. Meta envia webhook -> /api/whatsapp/webhook2. Webhook handler processa mensagem3. 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 executadasEvento 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 sucesso2. emitEvent("Message Sent", { contactId, properties: { phone, wa_message_id, automation_execution_id } })3. dispatchEventToAutomations("Message Sent", ...) -- mas ignora se _fromAutomation = trueOnde emitEvent() e Chamado
Seção intitulada “Onde emitEvent() e Chamado”| Local | Métrica | Fonte |
|---|---|---|
| WhatsApp webhook (inbound msg) | Message Received | |
| WhatsApp webhook (status: delivered) | Message Delivered / Template Delivered | |
| WhatsApp webhook (status: read) | Message Read / Template Read | |
| WhatsApp webhook (status: failed) | Message Failed | |
| Step send_message | Message Sent | automation |
| Step send_template | Template Sent | automation |
| Step add_tag | Tag Added | automation |
| Step remove_tag | Tag Removed | automation |
| Step close_conversation | Conversation Closed | automation |
| Step ai_respond | AI Response Sent | automation |
| E-commercé webhooks | Order Placed, Order Paid, etc. | shopify/yampi/… |
| Campanha enviada | Campaign Sent | campaign |
| Link rastreado clicado | Link Clicked | tracking |