Pular para conteúdo

Modelo de Dados

Diagrama de Relacionamentos

┌─────────────────┐
│     Tenant      │
└────────┬────────┘
         ├──────────────┬──────────────┬──────────────┬──────────────┐
         │              │              │              │              │
         ▼              ▼              ▼              ▼              ▼
   ┌──────────┐  ┌──────────┐  ┌──────────────┐  ┌──────────┐  ┌──────────┐
   │   User   │  │  Agent   │  │WhatsAppInstance│ │ AiModel  │  │ LlmUsage │
   └──────────┘  └────┬─────┘  └───────┬───────┘  └──────────┘  └──────────┘
                      │                │
         ┌────────────┼────────────┬──────────────┬────────────┐
         │            │            │              │            │
         ▼            ▼            ▼              ▼            │
   ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐      │
   │Knowledge │ │   FAQ    │ │Escalation│ │  Agent   │      │
   │  Block   │ │          │ │   Rule   │ │   Step   │      │
   └──────────┘ └──────────┘ └──────────┘ └─────┬────┘      │
                                                │            │
                                           ┌────┴─────┐      │
                                           │ Prompt   │      │
                                           │ Version  │◄─────┘
                                           └──────────┘
                                      ┌────────┴───────┐
                                      │  Conversation  │
                                      └────────┬───────┘
                                      ┌────────┴────────┐
                                      │                 │
                                      ▼                 ▼
                               ┌──────────┐      ┌──────────┐
                               │ Message  │      │Escalation│
                               └────┬─────┘      └──────────┘
                               ┌──────────┐
                               │ Reaction │
                               └──────────┘

┌─────────────────┐      ┌─────────────────┐
│InstanceWhitelist│      │InstanceBlacklist│
└─────────────────┘      └─────────────────┘
        ▲                        ▲
        └────────┬───────────────┘
          WhatsAppInstance

Nota: LlmUsage também referencia opcionalmente Agent, Conversation e Message

Entidades

Tenant

Empresa/organização que utiliza a plataforma (multi-tenancy).

Campo Tipo Descrição
Id Guid Identificador único
Name string Nome da empresa
Slug string Identificador URL-safe único
Settings string? Configurações JSON específicas
IsActive bool Se o tenant está ativo
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Relacionamentos: - 1:N Users - 1:N Agents - 1:N WhatsAppInstances - 1:N AiModels


User

Usuários do portal administrativo.

Campo Tipo Descrição
Id Guid Identificador único
TenantId Guid FK Tenant (obrigatório)
Email string Login único
PasswordHash string Senha BCrypt
Name string Nome de exibição
IsAdmin bool Admin do tenant
IsSuperAdmin bool Admin global (acesso a páginas admin)
IsActive bool Se pode fazer login
MustChangePassword bool Força troca de senha no próximo login
CreatedAt DateTime Data de criação
LastLoginAt DateTime? Último acesso

Regras de acesso: - IsSuperAdmin = true: Acesso a páginas admin (Tenants, LLM Usage, Settings) — dados filtrados pelo seu tenant - IsAdmin = true: Gerencia usuários e recursos do tenant - IsAdmin = false: Acesso limitado ao tenant

Restrições: - Email deve ser único globalmente (não apenas por tenant)


Agent

Agentes IA que processam conversas.

Campo Tipo Descrição
Id Guid Identificador único
TenantId Guid FK Tenant
Name string Nome do agente ("Suporte TI")
Description string? Descrição interna
SystemPrompt string Prompt principal do agente
OptimizedSystemPrompt string? Versão otimizada do prompt (gerada automaticamente)
IsActive bool Se está processando mensagens
IsArchived bool Se o agente está arquivado
ArchivedAt DateTime? Data de arquivamento
ErrorMessage string? Mensagem customizada de erro
WelcomeMessage string? Mensagem de boas-vindas
RateLimitMessage string? Mensagem de rate limit
OutOfHoursMessage string? Mensagem fora do horário
Tone AgentTone Tom de comunicação (Professional)
Language AgentLanguage Idioma das respostas (PtBr)
AllowEmojis bool Permite emojis nas respostas (true)
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Otimização de Prompt: - O OptimizedSystemPrompt é gerado automaticamente ao criar/atualizar o agente - Remove redundâncias, compacta linguagem e reorganiza sem perder semântica - Reduz consumo de tokens em ~30-35% por conversa - Veja prompt-optimization.md para detalhes

Relacionamentos: - 1:N WhatsAppInstances - 1:N AgentKnowledge - 1:N AgentFaq - 1:N AgentStep - 1:N EscalationRules - 1:N PromptVersions


AgentStep

Etapas de atendimento que guiam a IA por um fluxo estruturado. Quando configuradas, a IA segue as instruções da etapa atual e avança conforme os objetivos são cumpridos.

Campo Tipo Descrição
Id Guid Identificador único
AgentId Guid FK Agent
Name string Nome da etapa (máx 100)
Instructions string Instruções da etapa (máx 20000)
OptimizedInstructions string? Versão otimizada das instruções
Order int Posição na sequência
IsActive bool Se está ativa no fluxo
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Comportamento: - Sem etapas: agente responde livremente usando apenas o prompt base - Com etapas: IA segue a etapa atual, pode avançar/voltar conforme necessidade - IA pode pular etapas se todas as anteriores foram atendidas - Ao completar todas as etapas, a conversa é resolvida automaticamente - Instruções otimizadas são geradas automaticamente ao criar/atualizar

Relacionamentos: - N:1 Agent (cascade delete) - 1:N PromptVersions (via AgentStepId)


PromptVersion

Snapshot automático de prompts e instruções, criado a cada atualização de Agent.SystemPrompt ou AgentStep.Instructions.

Campo Tipo Descrição
Id Guid Identificador único
AgentId Guid FK Agent
AgentStepId Guid? FK AgentStep (null = prompt do Agent)
Version int Número sequencial da versão
Content string Conteúdo do prompt/instrução no momento do snapshot
OptimizedContent string? Versão otimizada no momento do snapshot
CreatedAt DateTime Data de criação

Discriminação: - AgentStepId == null: versão do Agent.SystemPrompt - AgentStepId != null: versão do AgentStep.Instructions

Comportamento: - Snapshot criado automaticamente ANTES de cada update (captura estado anterior) - Restaurar uma versão aplica o conteúdo e cria um novo snapshot do estado atual - Versões são sequenciais por escopo (por Agent ou por AgentStep)

Índices: - UNIQUE (agent_id, agent_step_id, version) — sequencialidade - (agent_id) WHERE agent_step_id IS NULL — histórico do agent - (agent_step_id) WHERE agent_step_id IS NOT NULL — histórico do step

Relacionamentos: - N:1 Agent (cascade delete) - N:1 AgentStep (cascade delete, opcional)


AgentKnowledge

Base de conhecimento em blocos para compor o contexto do agente. Utiliza busca semântica com pgvector para recuperar apenas os blocos relevantes para cada pergunta.

Campo Tipo Descrição
Id Guid Identificador único
AgentId Guid FK Agent
Title string Título do bloco
Content string Conteúdo (markdown, máx 25.000 caracteres)
DisplayOrder int Ordem de exibição
IsActive bool Se está incluído no prompt
Embedding Vector? Vetor de 1536 dimensões para busca semântica
EmbeddingUpdatedAt DateTime? Última atualização do embedding
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Busca Semântica: - Embeddings gerados automaticamente ao criar/atualizar blocos - Índice HNSW para busca eficiente por similaridade - Retorna os 5 blocos mais relevantes para cada pergunta - Veja knowledge-retrieval.md para detalhes


AgentFaq

Perguntas frequentes do agente. Cada FAQ é um par pergunta/resposta atômico que participa da busca semântica junto com a base de conhecimento.

Campo Tipo Descrição
Id Guid Identificador único
AgentId Guid FK Agent
Question string Pergunta (máx 500 caracteres)
Answer string Resposta
DisplayOrder int Ordem de exibição
IsActive bool Se está incluída na busca
Embedding Vector? Vetor de 1536 dimensões para busca semântica
EmbeddingUpdatedAt DateTime? Última atualização do embedding
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Diferença de AgentKnowledge: - AgentKnowledge: Blocos de texto/documentos que são divididos em chunks para embedding - AgentFaq: Pares Q&A atômicos com embedding direto na entidade (não precisa de chunks)

Busca Semântica: - Embeddings gerados no formato: "Pergunta: {Question}\nResposta: {Answer}" - Participam da mesma busca semântica que AgentKnowledge - Resultados combinados por relevância (distância de cosseno)


AiModel

Modelos de IA disponíveis para uso.

Campo Tipo Descrição
Id Guid Identificador único
TenantId Guid FK Tenant
DisplayName string Nome amigável ("Claude Sonnet")
ModelId string ID do modelo na API ("claude-sonnet-4-20250514")
IsActive bool Se está disponível para uso
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

WhatsAppInstance

Instância de conexão com WhatsApp via Evolution API.

Campo Tipo Descrição
Id Guid Identificador único (usado como nome da instância na Evolution API)
TenantId Guid FK Tenant
Name string Nome da instância
PhoneNumber string? Número conectado
Status ConnectionStatus Estado da conexão
AgentId Guid? FK Agent vinculado
ModelOverride string? ID do modelo LLM (sobrescreve o padrão do agent)
StartsWithAI bool Inicia conversas em modo IA
AiAvailabilityHoursJson string? Horários de atendimento da IA (JSONB)
SignatureText string? Texto da assinatura nas mensagens
SignaturePosition SignaturePosition Posição da assinatura (Disabled)
ShowTyping bool Mostra indicador de digitação (true)
DelaySeconds int Delay antes de enviar resposta (0-10)
IsArchived bool Se a instância está arquivada
ArchivedAt DateTime? Data de arquivamento
CreatedAt DateTime Data de criação
UpdatedAt DateTime Última atualização

Relacionamentos: - N:1 Agent - 1:N Conversations - 1:N InstanceWhitelist - 1:N InstanceBlacklist


InstanceWhitelist

Lista de contatos autorizados a interagir com a instância.

Campo Tipo Descrição
Id Guid Identificador único
InstanceId Guid FK WhatsAppInstance
PhoneNumber string Número no formato E.164
ContactName string? Nome do contato
Notes string? Observações
IsActive bool Se está ativo
CreatedAt DateTime Data de criação

Lógica: Se a whitelist estiver vazia ou todos desativados, aceita qualquer número.


InstanceBlacklist

Lista de contatos bloqueados (mensagens ignoradas).

Campo Tipo Descrição
Id Guid Identificador único
InstanceId Guid FK WhatsAppInstance
PhoneNumber string Número no formato E.164
Reason string? Motivo do bloqueio
BlockedAt DateTime Quando foi bloqueado
BlockedBy Guid? FK User que bloqueou

Prioridade: Blacklist é verificada ANTES da whitelist.


Conversation

Sessão de atendimento entre um contato e a instância.

Campo Tipo Descrição
Id Guid Identificador único
InstanceId Guid FK WhatsAppInstance
AgentId Guid? FK Agent (pode ser null)
ContactPhone string Número do contato
ContactName string? Nome (pushName)
ContactProfilePictureUrl string? URL da foto de perfil
Status ConversationStatus Active, Resolved, Escalated
Mode ConversationMode AI ou Manual
ModeChangedAt DateTime? Quando mudou de modo
StartedAt DateTime Início da conversa
LastMessageAt DateTime Última mensagem
LastReadAt DateTime? Última leitura do operador
ResolvedAt DateTime? Quando foi resolvida
Summary string? Resumo da conversa
CurrentStepId Guid? FK AgentStep — etapa atual do atendimento

Relacionamentos: - 1:N Messages - 1:1 Escalation (opcional) - N:1 AgentStep (opcional, SetNull on delete)


Message

Mensagem individual em uma conversa.

Campo Tipo Descrição
Id Guid Identificador único
ConversationId Guid FK Conversation
Role MessageRole User, Assistant, System
Type MessageType Text, Image, Audio, etc.
Content string? Conteúdo textual / caption original
ExtractedText string? Texto extraído (transcrição ou descrição de imagem)
MediaUrl string? URL da mídia (R2)
MediaMimeType string? MIME type do arquivo
MediaFileName string? Nome do arquivo
WhatsAppMessageId string? ID do WhatsApp (para status)
Status MessageStatus Pending, Sent, Delivered, Read, Failed
SentAt DateTime? Quando foi enviada
DeliveredAt DateTime? Quando foi entregue
ReadAt DateTime? Quando foi lida
CreatedAt DateTime Data de criação

Tracking de Tokens: - O tracking de tokens foi movido para a entidade LlmUsage - Permite tracking granular por operação, modelo e tipo de uso - Veja llm-usage.md para detalhes

Processamento de Mídia: - Áudios são transcritos via OpenAI Whisper → resultado em ExtractedText - Imagens são descritas via Claude Vision → resultado em ExtractedText - Veja media-processing.md para detalhes

Relacionamentos: - 1:N Reactions


Reaction

Reação (emoji) a uma mensagem.

Campo Tipo Descrição
Id Guid Identificador único
MessageId Guid FK Message
Emoji string Emoji da reação
SenderPhone string Quem reagiu
FromMe bool Se foi enviada pelo sistema
CreatedAt DateTime Data de criação

EscalationRule

Regras para escalação automática de conversas.

Campo Tipo Descrição
Id Guid Identificador único
AgentId Guid FK Agent
Keywords string? Palavras-chave (vírgula separadas)
MaxMessages int? Escalar após N mensagens
MaxDurationMinutes int? Escalar após N minutos
IsActive bool Se está ativa
CreatedAt DateTime Data de criação

Escalation

Registro de escalação de uma conversa.

Campo Tipo Descrição
Id Guid Identificador único
ConversationId Guid FK Conversation
RuleId Guid FK EscalationRule
Reason string Motivo da escalação
EscalatedAt DateTime Quando escalou
ResolvedAt DateTime? Quando foi resolvida
Notes string? Observações
ResolvedBy string? Quem resolveu

SystemSettings

Configurações globais do sistema (singleton).

Campo Tipo Descrição
Id Guid ID fixo (singleton)
DefaultErrorMessage string Mensagem padrão de erro
DefaultWelcomeMessage string Mensagem padrão de boas-vindas
DefaultRateLimitMessage string? Mensagem padrão de rate limit
DefaultOutOfHoursMessage string? Mensagem padrão fora do horário
UpdatedAt DateTime Última atualização

LlmUsage

Registro de uso de LLM para tracking de tokens e custos.

Campo Tipo Descrição
Id Guid Identificador único
TenantId Guid FK Tenant
Provider LlmProvider Anthropic, OpenAI
Model string ID do modelo (claude-3-5-sonnet-20241022)
OperationType LlmOperationType Tipo da operação
InputTokens int Tokens de entrada
OutputTokens int Tokens de saída
CacheCreationInputTokens int Tokens de criação de cache (prompt caching)
CacheReadInputTokens int Tokens lidos do cache (prompt caching)
EstimatedCost decimal? Custo estimado em USD (inclui custo de cache)
MessageId Guid? FK Message (opcional)
ConversationId Guid? FK Conversation (opcional)
AgentId Guid? FK Agent (opcional)
ReferenceContext string? Contexto adicional (JSONB)
CreatedAt DateTime Data de criação

Relacionamentos: - N:1 Tenant - N:1 Message (opcional) - N:1 Conversation (opcional) - N:1 Agent (opcional)

Índices: - (tenant_id, created_at) - Consultas por período - (tenant_id, operation_type, created_at) - Consultas por tipo - (agent_id, created_at) - Consultas por agente - (conversation_id) - Consultas por conversa


Enums

LlmProvider

Provider de LLM.

Valor Descrição
Anthropic Claude API
OpenAI OpenAI API

LlmOperationType

Tipo de operação com LLM.

Valor Descrição
Chat Resposta em conversa
Vision Descrição de imagem
Transcription Transcrição de áudio
Embedding Geração de embeddings
Chunking Processamento de knowledge
Playground Testes no playground

ConnectionStatus

Status de conexão da instância WhatsApp.

Valor Descrição
Disconnected Desconectado
Connecting Conectando
Connected Conectado
Open Conexão aberta
Close Conexão fechada

ConversationStatus

Status da conversa.

Valor Descrição
Active Conversa ativa
Resolved Conversa resolvida
Escalated Conversa escalada

ConversationMode

Modo de atendimento da conversa.

Valor Descrição
AI IA está atendendo
Manual Humano está atendendo

MessageRole

Papel do autor da mensagem.

Valor Descrição
User Mensagem do usuário (cliente)
Assistant Mensagem do assistente (IA ou operador)
System Mensagem do sistema

MessageType

Tipo de conteúdo da mensagem.

Valor Descrição
Text Texto
Image Imagem
Audio Áudio (voice message)
Video Vídeo
Document Documento
Sticker Sticker

MessageStatus

Status de entrega da mensagem no WhatsApp.

Valor Descrição
Pending Aguardando envio
Sent Enviada (✓)
Delivered Entregue (✓✓)
Read Lida (✓✓ azul)
Failed Falhou

AgentTone

Tom de comunicação do agente.

Valor Descrição
Formal Linguagem corporativa e respeitosa
Professional Profissional mas acolhedor (padrão)
Friendly Amigável e acessível

AgentLanguage

Idioma das respostas do agente.

Valor Descrição
PtBr Português do Brasil (padrão)
PtPt Português de Portugal
En Inglês
Es Espanhol

SignaturePosition

Posição da assinatura nas mensagens.

Valor Descrição
Disabled Sem assinatura (padrão)
StartSameLine Início da mensagem, mesma linha
StartNewLine Início da mensagem, nova linha
EndSameLine Final da mensagem, mesma linha
EndNewLine Final da mensagem, nova linha

Multi-tenancy

O sistema implementa multi-tenancy via query filters globais no EF Core:

// AppDbContext.cs
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Filtro global por TenantId
    modelBuilder.Entity<Agent>()
        .HasQueryFilter(a => a.TenantId == _tenantProvider.TenantId);
}
  • Todas as entidades com TenantId são automaticamente filtradas
  • Todo usuário (incluindo SuperAdmin) tem TenantId obrigatório — dados filtrados pelo tenant do JWT
  • TenantId é extraído do JWT via ITenantProvider

Convenções de Banco

Contexto Convenção
Tabelas e colunas snake_case (via NamingConventions)
Chaves primárias id (Guid)
Chaves estrangeiras {entidade}_id
Timestamps created_at, updated_at
Soft delete is_active (não usa deleted_at)