Schema
| Campo | Tipo | Descrição |
|---|
leadOrganizationId | string | PK — partition key. FK para LeadOrganization |
occurredAtId | string | SK — sort key. Formato: "2026-01-15T14:00:00Z#uuid" |
sourceType | enum | EXTERNAL, INTERNAL, DIRECT |
source | string | Identificador da origem, max 100. Ex: stripe, hotmart, messaging_service |
eventType | string | Tipo do evento normalizado, max 100. Ex: purchase_completed, conversation_ended |
objectId | string? | ID interno do objeto referenciado, max 255 |
objectIdRef | string? | ID externo/provider do objeto referenciado, max 255 |
payload | JSON | Dados normalizados e enriquecidos |
rawPayload | JSON? | Payload original intocado da origem (para debug e reprocessamento) |
externalEventId | string? | ID original da origem (para idempotência), max 255 |
receivedAt | datetime | Quando o Domínio Lead recebeu o evento |
Banco de dados: DynamoDB. Eventos vivem no DynamoDB por sua natureza append-only e alta cardinalidade — um único lead pode gerar milhares de eventos ao longo do tempo.
Eventos são
append-only — nunca são editados ou deletados. O campo
payload carrega os dados enriquecidos e normalizados. O
rawPayload preserva o original para debug e reprocessamento. Eventos são a
fonte da verdade —
LeadMemories são derivadas de eventos e podem ser reconstruídas ao reprocessá-los.
Indexes
GSI: idempotency-index
| Key | Campo |
|---|
| PK | source |
| SK | externalEventId |
Usado para verificar eventos duplicados antes da escrita. Se (source, externalEventId) já existir, o evento é ignorado.
GSI: event-type-index
| Key | Campo |
|---|
| PK | leadOrganizationId |
| SK | eventType#occurredAt |
Usado para consultar eventos filtrados por tipo. Ex: “todos os eventos purchase_completed do lead X nos últimos 30 dias”.
Origens (Sources)
| sourceType | source | Descrição |
|---|
EXTERNAL | stripe, hotmart, shopify, typeform | Via Webhook Domain |
INTERNAL | messaging_service | Sinais extraídos de conversas |
INTERNAL | dispatch_service | Resultados de entrega e engajamento de campanhas |
INTERNAL | ai_agents_service | Insights dos agentes de IA |
INTERNAL | billing_service | Eventos de assinatura e pagamento |
INTERNAL | ticketing_service | Eventos de tickets de suporte |
DIRECT | whatsapp, web, instagram | Lead iniciou interação em um canal |
Tipos de Evento
| Categoria | eventType | Campos do payload |
|---|
| Purchase | purchase_completed | productId, productName, category, amount, currency, paymentMethod |
| Purchase | purchase_abandoned | productIds, cartValue, stageAbandoned |
| Product | product_viewed | productId, productName, category |
| Product | product_asked | productId, question, channel |
| Interest | interest_detected | category, productId, confidence |
| Sentiment | sentiment_detected | score, label, context |
| Support | ticket_opened | ticketId, subject, productId, priority |
| Support | ticket_resolved | ticketId, resolution, satisfactionScore |
| Conversation | conversation_started | channel, context |
| Conversation | conversation_ended | channel, durationSeconds, messageCount, sentimentScore |
| Campaign | campaign_delivered | campaignId, campaignName, productId, channel |
| Campaign | campaign_engaged | campaignId, engagementType |
| Campaign | campaign_ignored | campaignId, daysSinceDelivery |
| Subscription | subscription_created | planId, planName, amount |
| Subscription | subscription_cancelled | planId, reason |
| Form | form_submitted | formId, formName, responses[] |
| Discount | discount_requested | context, productId |
| Discount | discount_accepted | discountPercent, productId |
| Agent | agent_insight | insightType, content, confidence |
| Objection | objection_raised | type, context, productId |
Regras de Negócio
- Eventos são append-only — nunca editados ou deletados
payload carrega os dados enriquecidos e normalizados. rawPayload preserva o original para debug
occurredAt é quando o fato aconteceu. receivedAt é quando o Domínio Lead recebeu o evento
- Idempotência é garantida via GSI
idempotency-index em (source, externalEventId)
- Eventos são a fonte da verdade — LeadMemories são derivadas de eventos e podem ser reconstruídas ao reprocessá-los
Exemplo
{
"PK": "ORG#org_01HX#LEAD#lead_01HX",
"SK": "EVT#2026-03-20T14:22:00Z#evt_01HX",
"eventType": "message.received",
"source": "WHATSAPP",
"payload": { "text": "Oi, quero saber mais sobre o plano enterprise", "mediaType": "text" },
"idempotencyKey": "whatsapp_msg_ABC123",
"ttl": 1758892800
}