# Documentação do Banco de Dados Este documento descreve o schema PostgreSQL definido em `migrations/migrations_v1.sql` para o projeto `php_api`. ## Visão geral O banco foi modelado para suportar uma operação multiempresa, com as seguintes áreas principais: - **Entidades centrais**: `company`, `user`, `operator`, `sku`, `integration`. - **Operação de atendimento**: `client`, `conversation`, `message`, `message_attachment`, `message_reaction`, `conversation_participant`, `webhook_event`. - **Análise e inteligência**: `conversation_analysis`, `aspect_feedback`, `emotion_snapshot`, `public_opinion`, `ai_action`. - **Estratégia e gestão**: `persona`, `client_persona`, `best_action`. - **Métricas e snapshots**: `volume_snapshot`, `sentiment_evolution`, `playbooks_monitor`, `operator_daily_stats`, `kpi_snapshot`. ## Convenções do schema - Todas as tabelas usam `SERIAL PRIMARY KEY` para o identificador principal. - Todas as colunas relevantes estão marcadas como `NOT NULL`. - Colunas de exclusão lógica usam o padrão: - `TIMESTAMP NOT NULL DEFAULT 'infinity'` - O valor `'infinity'` indica que o registro está ativo. - A tabela `user` é criada entre aspas (`"user"`) porque o nome é reservado em PostgreSQL. - As chaves estrangeiras foram declaradas com `CONSTRAINT` em linha única. - Alguns relacionamentos possuem `UNIQUE` para impedir duplicidade por empresa ou por data. ## Tabelas ### 1. `company` Tabela principal de empresas atendidas pelo sistema. | Coluna | Tipo | Descrição | | --- | --- | --- | | `company_id` | `SERIAL` | Identificador da empresa. | | `company_name` | `VARCHAR(100)` | Nome da empresa. | | `company_cnpj` | `VARCHAR(14)` | CNPJ da empresa. Único. | | `company_logo` | `TEXT` | Logo da empresa. | | `company_hmac_secret` | `VARCHAR(64)` | Segredo HMAC próprio da empresa, usado para validar os webhooks de CRM. Default vazio (tratado como "não configurado"). | | `company_created_at` | `TIMESTAMP` | Data de criação. | | `company_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 2. `user` Usuários do sistema vinculados a uma empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `user_id` | `SERIAL` | Identificador do usuário. | | `company_id` | `INT` | FK para `company.company_id`. | | `user_name` | `VARCHAR(100)` | Nome do usuário. | | `user_phone` | `VARCHAR(20)` | Telefone. | | `user_email` | `VARCHAR(100)` | E-mail. Único. | | `user_role` | `VARCHAR(10)` | Papel/perfil do usuário. | | `user_password` | `VARCHAR(255)` | Senha criptografada. | | `user_created_at` | `TIMESTAMP` | Data de criação. | | `user_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 3. `operator` Operadores/atendentes vinculados à empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `operator_id` | `SERIAL` | Identificador do operador. | | `company_id` | `INT` | FK para `company`. | | `operator_name` | `VARCHAR(100)` | Nome do operador. | | `operator_initials` | `VARCHAR(5)` | Iniciais do operador. | | `operator_email` | `VARCHAR(100)` | E-mail do operador. | | `operator_phone` | `VARCHAR(20)` | Telefone. | | `operator_department` | `VARCHAR(20)` | Departamento. | | `operator_status` | `VARCHAR(30)` | Status atual. Default: `'Disponível'`. | | `operator_available_for_escalation` | `BOOLEAN` | Indica disponibilidade para escalonamento. | | `operator_created_at` | `TIMESTAMP` | Data de criação. | | `operator_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 4. `operator_channel` Canais vinculados a cada operador. | Coluna | Tipo | Descrição | | --- | --- | --- | | `operator_channel_id` | `SERIAL` | Identificador do registro. | | `operator_id` | `INT` | FK para `operator`. | | `operator_channel` | `VARCHAR(20)` | Nome do canal. | | `operator_channel_created_at` | `TIMESTAMP` | Data de criação. | | `operator_channel_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 5. `sla_config` Configuração de SLA por empresa e departamento. | Coluna | Tipo | Descrição | | --- | --- | --- | | `sla_config_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `sla_config_department` | `VARCHAR(20)` | Departamento. | | `sla_config_response_hours` | `INT` | Tempo de resposta em horas. Default: `2`. | | `sla_config_resolution_hours` | `INT` | Tempo de resolução em horas. Default: `24`. | | `sla_config_updated_at` | `TIMESTAMP` | Data de atualização. | | `sla_config_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | **Restrição:** - `UNIQUE (company_id, sla_config_department)` ### 6. `sku` Cadastro de produtos/serviços da empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `sku_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `sku_name` | `VARCHAR(100)` | Nome do item. | | `sku_value` | `DECIMAL(12,2)` | Valor. | | `sku_sold` | `INT` | Quantidade vendida. Default: `0`. | | `sku_line` | `VARCHAR(50)` | Linha/categoria. | | `sku_created_at` | `TIMESTAMP` | Data de criação. | | `sku_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 7. `integration` Integrações externas da empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `integration_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `integration_provider` | `VARCHAR(30)` | Provedor da integração. | | `integration_account_id` | `TEXT` | ID da conta. | | `integration_external_account_id` | `TEXT` | ID externo da conta. | | `integration_account_name` | `VARCHAR(100)` | Nome da conta. | | `integration_status` | `VARCHAR(20)` | Status da integração. | | `integration_access_token` | `TEXT` | Token de acesso. | | `integration_refresh_token` | `TEXT` | Refresh token. | | `integration_is_connected` | `BOOLEAN` | Indica se está conectada. Default: `TRUE`. | | `integration_last_sync_at` | `TIMESTAMP` | Última sincronização. | | `integration_last_error` | `TEXT` | Último erro. | | `integration_created_at` | `TIMESTAMP` | Data de criação. | | `integration_updated_at` | `TIMESTAMP` | Data de atualização. | | `integration_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 8. `client` Clientes que interagem com a empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `client_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `client_provider_id` | `TEXT` | ID do cliente no provedor. | | `client_phone` | `VARCHAR(20)` | Telefone. | | `client_name` | `VARCHAR(100)` | Nome. | | `client_email` | `VARCHAR(100)` | E-mail. | | `client_segment` | `VARCHAR(100)` | Segmento. | | `client_is_registered` | `BOOLEAN` | Indica se o cliente está cadastrado. Default: `FALSE`. | | `client_created_at` | `TIMESTAMP` | Data de criação. | | `client_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | **Restrição:** - `UNIQUE (company_id, client_phone)` ### 9. `conversation` Conversas entre clientes e operadores/integrações. | Coluna | Tipo | Descrição | | --- | --- | --- | | `conversation_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `integration_id` | `INT` | FK para `integration`. | | `operator_id` | `INT` | FK para `operator`. | | `client_id` | `INT` | FK para `client`. | | `conversation_external_id` | `TEXT` | ID externo da conversa. | | `conversation_provider_id` | `TEXT` | ID no provedor. | | `conversation_channel` | `VARCHAR(20)` | Canal. | | `conversation_status` | `VARCHAR(20)` | Status da conversa. Default: `'open'`. | | `conversation_is_automated` | `BOOLEAN` | Indica automação. Default: `FALSE`. | | `conversation_started_at` | `TIMESTAMP` | Início. | | `conversation_closed_at` | `TIMESTAMP` | Encerramento. | | `conversation_sla_deadline` | `TIMESTAMP` | Prazo de SLA. | | `conversation_last_message_at` | `TIMESTAMP` | Data da última mensagem. | | `conversation_last_message_preview` | `TEXT` | Prévia da última mensagem. | | `conversation_last_message_from` | `VARCHAR(10)` | Origem da última mensagem. | | `conversation_impact_value` | `DECIMAL(12,2)` | Valor de impacto. | | `conversation_ticket_value` | `DECIMAL(12,2)` | Valor do ticket. | | `conversation_conversion_chance` | `INT` | Chance de conversão. | | `conversation_optimum_window` | `VARCHAR(20)` | Janela ideal. | | `conversation_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 10. `message` Mensagens associadas a uma conversa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `message_id` | `SERIAL` | Identificador. | | `conversation_id` | `INT` | FK para `conversation`. | | `quoted_message_id` | `INT` | FK auto-referenciada para `message`. | | `message_external_id` | `TEXT` | ID externo da mensagem. | | `message_provider_id` | `TEXT` | ID no provedor. | | `message_sender_provider_id` | `TEXT` | Remetente no provedor. | | `message_is_operator` | `BOOLEAN` | Indica se foi enviada por operador. | | `message_type` | `VARCHAR(20)` | Tipo da mensagem. Default: `'text'`. | | `message_content` | `TEXT` | Conteúdo. | | `message_seen` | `BOOLEAN` | Visualizada. | | `message_delivered` | `BOOLEAN` | Entregue. | | `message_edited` | `BOOLEAN` | Editada. Default: `FALSE`. | | `message_deleted` | `BOOLEAN` | Excluída. Default: `FALSE`. | | `message_hidden` | `BOOLEAN` | Oculta. Default: `FALSE`. | | `message_is_event` | `BOOLEAN` | Indica evento. Default: `FALSE`. | | `message_event_type` | `INT` | Tipo do evento. | | `message_sent_at` | `TIMESTAMP` | Data de envio. | | `message_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 11. `message_attachment` Anexos de mensagens. | Coluna | Tipo | Descrição | | --- | --- | --- | | `attachment_id` | `SERIAL` | Identificador. | | `message_id` | `INT` | FK para `message`. | | `attachment_external_id` | `TEXT` | ID externo. | | `attachment_url` | `TEXT` | URL do arquivo. | | `attachment_type` | `VARCHAR(50)` | Tipo do anexo. | | `attachment_mime_type` | `VARCHAR(100)` | MIME type. | | `attachment_file_name` | `VARCHAR(255)` | Nome do arquivo. | | `attachment_size` | `BIGINT` | Tamanho em bytes. | | `attachment_created_at` | `TIMESTAMP` | Data de criação. | | `attachment_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 12. `message_reaction` Reações vinculadas a mensagens. | Coluna | Tipo | Descrição | | --- | --- | --- | | `reaction_id` | `SERIAL` | Identificador. | | `message_id` | `INT` | FK para `message`. | | `reaction_sender_provider_id` | `TEXT` | Remetente da reação no provedor. | | `reaction_value` | `VARCHAR(20)` | Valor da reação. | | `reaction_is_sender` | `BOOLEAN` | Indica se foi enviada pelo remetente. Default: `FALSE`. | | `reaction_created_at` | `TIMESTAMP` | Data de criação. | | `reaction_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 13. `conversation_participant` Participantes de uma conversa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `participant_id` | `SERIAL` | Identificador. | | `conversation_id` | `INT` | FK para `conversation`. | | `participant_provider_id` | `TEXT` | ID do participante no provedor. | | `participant_name` | `VARCHAR(100)` | Nome do participante. | | `participant_is_admin` | `BOOLEAN` | Indica se é administrador. Default: `FALSE`. | | `participant_created_at` | `TIMESTAMP` | Data de criação. | | `participant_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 14. `webhook_event` Eventos recebidos por webhook. | Coluna | Tipo | Descrição | | --- | --- | --- | | `webhook_event_id` | `SERIAL` | Identificador. | | `integration_id` | `INT` | FK para `integration`. | | `webhook_event_type` | `VARCHAR(50)` | Tipo do evento. | | `webhook_event_external_id` | `TEXT` | ID externo do evento. | | `webhook_event_payload` | `JSONB` | Payload bruto do evento. | | `webhook_event_processed` | `BOOLEAN` | Processado. Default: `FALSE`. | | `webhook_event_received_at` | `TIMESTAMP` | Data de recebimento. | | `webhook_event_processed_at` | `TIMESTAMP` | Data de processamento. | | `webhook_event_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 15. `conversation_analysis` Resultado de análise de conversa por IA. | Coluna | Tipo | Descrição | | --- | --- | --- | | `analysis_id` | `SERIAL` | Identificador. | | `conversation_id` | `INT` | FK para `conversation`. Única. | | `company_id` | `INT` | FK para `company`. | | `conversation_analysis_sentiment` | `VARCHAR(20)` | Sentimento detectado. | | `conversation_analysis_sentiment_score` | `NUMERIC(3,2)` | Score do sentimento. | | `conversation_analysis_aspect` | `VARCHAR(50)` | Aspecto principal. | | `conversation_analysis_sub_aspect` | `VARCHAR(100)` | Subaspecto. | | `conversation_analysis_analyzed_at` | `TIMESTAMP` | Data da análise. | | `conversation_analysis_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 16. `aspect_feedback` Feedback de aspecto da conversa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `aspect_feedback_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `conversation_id` | `INT` | FK para `conversation`. | | `aspect_feedback_aspect` | `VARCHAR(50)` | Aspecto. | | `aspect_feedback_sentiment` | `VARCHAR(20)` | Sentimento. | | `aspect_feedback_text` | `TEXT` | Texto do feedback. | | `aspect_feedback_created_at` | `TIMESTAMP` | Data de criação. | | `aspect_feedback_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 17. `emotion_snapshot` Snapshot de emoções por empresa e data. | Coluna | Tipo | Descrição | | --- | --- | --- | | `emotion_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `emotion_snapshot_date` | `DATE` | Data do snapshot. | | `emotion_happiness` | `NUMERIC(5,2)` | Felicidade. Default: `0`. | | `emotion_sadness` | `NUMERIC(5,2)` | Tristeza. Default: `0`. | | `emotion_anger` | `NUMERIC(5,2)` | Raiva. Default: `0`. | | `emotion_fear` | `NUMERIC(5,2)` | Medo. Default: `0`. | | `emotion_anticipation` | `NUMERIC(5,2)` | Antecipação. Default: `0`. | | `emotion_confidence` | `NUMERIC(5,2)` | Confiança. Default: `0`. | | `emotion_surprise` | `NUMERIC(5,2)` | Surpresa. Default: `0`. | | `emotion_total_analyzed` | `INT` | Total analisado. Default: `0`. | **Restrição:** - `UNIQUE (company_id, emotion_snapshot_date)` ### 18. `public_opinion` Opiniões públicas classificadas por conversa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `opinion_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `conversation_id` | `INT` | FK para `conversation`. | | `opinion_is_positive` | `BOOLEAN` | Indica se a opinião é positiva. | | `opinion_classified_at` | `TIMESTAMP` | Data da classificação. | | `opinion_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 19. `alert` Alertas gerados pelo sistema. | Coluna | Tipo | Descrição | | --- | --- | --- | | `alert_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `client_id` | `INT` | FK para `client`. | | `alert_type` | `VARCHAR(20)` | Tipo do alerta. | | `alert_priority` | `VARCHAR(10)` | Prioridade. | | `alert_title` | `TEXT` | Título. | | `alert_description` | `TEXT` | Descrição. | | `alert_tips` | `TEXT` | Dicas. | | `alert_is_resolved` | `BOOLEAN` | Indica se foi resolvido. Default: `FALSE`. | | `alert_created_at` | `TIMESTAMP` | Data de criação. | | `alert_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 20. `ai_action` Sugestões/ações geradas por IA. | Coluna | Tipo | Descrição | | --- | --- | --- | | `ai_action_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `ai_action_idea` | `TEXT` | Ideia gerada. | | `ai_action_is_accepted` | `BOOLEAN` | Indica aceitação. | | `ai_action_created_at` | `TIMESTAMP` | Data de criação. | | `ai_action_responded_at` | `TIMESTAMP` | Data de resposta. | | `ai_action_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 21. `persona` Perfis/personas da empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `persona_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `persona_name` | `VARCHAR(100)` | Nome da persona. | | `persona_type` | `VARCHAR(50)` | Tipo da persona. Default: `'O PERFIL'`. | | `persona_description` | `TEXT` | Descrição. | | `persona_details` | `TEXT` | Detalhes. | | `persona_risk_level` | `VARCHAR(10)` | Nível de risco. Default: `'Médio'`. | | `persona_churn_risk_pct` | `NUMERIC(5,2)` | Percentual de risco de churn. | | `persona_expansion_potential` | `VARCHAR(20)` | Potencial de expansão. | | `persona_expansion_strategy` | `TEXT` | Estratégia de expansão. | | `persona_engagement_strategy` | `TEXT` | Estratégia de engajamento. | | `persona_created_at` | `TIMESTAMP` | Data de criação. | | `persona_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 22. `client_persona` Relacionamento entre cliente e persona. | Coluna | Tipo | Descrição | | --- | --- | --- | | `client_persona_id` | `SERIAL` | Identificador. | | `client_id` | `INT` | FK para `client`. | | `persona_id` | `INT` | FK para `persona`. | | `client_persona_assigned_at` | `TIMESTAMP` | Data de associação. | | `client_persona_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 23. `best_action` Melhor ação sugerida por empresa e persona. | Coluna | Tipo | Descrição | | --- | --- | --- | | `best_action_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `persona_id` | `INT` | FK para `persona`. | | `best_action_type` | `VARCHAR(20)` | Tipo da ação. | | `best_action_idea` | `TEXT` | Ideia da ação. | | `best_action_created_at` | `TIMESTAMP` | Data de criação. | | `best_action_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | ### 24. `volume_snapshot` Snapshot de volume por canal, empresa e data. | Coluna | Tipo | Descrição | | --- | --- | --- | | `volume_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `volume_snapshot_date` | `DATE` | Data do snapshot. | | `volume_channel` | `VARCHAR(20)` | Canal. | | `volume_message_count` | `INT` | Quantidade de mensagens. Default: `0`. | | `volume_conversation_count` | `INT` | Quantidade de conversas. Default: `0`. | **Restrição:** - `UNIQUE (company_id, volume_snapshot_date, volume_channel)` ### 25. `sentiment_evolution` Evolução de sentimento por empresa e data. | Coluna | Tipo | Descrição | | --- | --- | --- | | `evolution_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `evolution_snapshot_date` | `DATE` | Data do snapshot. | | `evolution_sentiment_score` | `NUMERIC(3,2)` | Score do sentimento. | **Restrição:** - `UNIQUE (company_id, evolution_snapshot_date)` ### 26. `playbooks_monitor` Monitoramento de playbooks por data. | Coluna | Tipo | Descrição | | --- | --- | --- | | `playbook_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `playbook_snapshot_date` | `DATE` | Data do snapshot. | | `playbook_new_detected` | `INT` | Quantidade de novos detectados. Default: `0`. | | `playbook_converted` | `INT` | Quantidade convertida. Default: `0`. | | `playbook_client_type` | `VARCHAR(10)` | Tipo de cliente. Default: `'new'`. | **Restrição:** - `UNIQUE (company_id, playbook_snapshot_date)` ### 27. `operator_daily_stats` Estatísticas diárias por operador. | Coluna | Tipo | Descrição | | --- | --- | --- | | `stat_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `operator_id` | `INT` | FK para `operator`. | | `operator_stat_date` | `DATE` | Data da estatística. | | `operator_attendances_count` | `INT` | Quantidade de atendimentos. Default: `0`. | | `operator_avg_response_seconds` | `INT` | Tempo médio de resposta em segundos. Default: `0`. | | `operator_sla_compliance_pct` | `NUMERIC(5,2)` | Percentual de SLA. Default: `0`. | | `operator_sales_amount` | `DECIMAL(12,2)` | Valor de vendas. Default: `0`. | **Restrição:** - `UNIQUE (operator_id, operator_stat_date)` ### 28. `kpi_snapshot` Snapshot consolidado de KPIs da empresa. | Coluna | Tipo | Descrição | | --- | --- | --- | | `kpi_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `kpi_snapshot_date` | `DATE` | Data do snapshot. | | `kpi_current_sales` | `DECIMAL(12,2)` | Vendas atuais. Default: `0`. | | `kpi_avg_ticket` | `DECIMAL(12,2)` | Ticket médio. Default: `0`. | | `kpi_lifetime_at_risk` | `DECIMAL(12,2)` | Valor em risco. Default: `0`. | | `kpi_critical_risk_clients` | `INT` | Clientes em risco crítico. Default: `0`. | | `kpi_sla_compliance_pct` | `NUMERIC(5,2)` | Percentual de compliance do SLA. Default: `0`. | | `kpi_churn_low_pct` | `NUMERIC(5,2)` | Churn baixo. Default: `0`. | | `kpi_churn_moderate_pct` | `NUMERIC(5,2)` | Churn moderado. Default: `0`. | | `kpi_churn_high_pct` | `NUMERIC(5,2)` | Churn alto. Default: `0`. | | `kpi_churn_critical_pct` | `NUMERIC(5,2)` | Churn crítico. Default: `0`. | | `kpi_ltv_total` | `DECIMAL(12,2)` | LTV total. Default: `0`. | | `kpi_ltv_at_risk` | `DECIMAL(12,2)` | LTV em risco. Default: `0`. | | `kpi_total_registered_clients` | `INT` | Total de clientes cadastrados. Default: `0`. | | `kpi_total_active_operators` | `INT` | Total de operadores ativos. Default: `0`. | | `kpi_general_emotion` | `VARCHAR(20)` | Emoção geral. | **Restrição:** - `UNIQUE (company_id, kpi_snapshot_date)` ### 29. `sale` Histórico de vendas recebido do CRM. Cada linha é uma venda com a data em que ocorreu, permitindo apurar faturamento por dia, semana ou mês. | Coluna | Tipo | Descrição | | --- | --- | --- | | `sale_id` | `SERIAL` | Identificador. | | `company_id` | `INT` | FK para `company`. | | `sku_id` | `INT` | Produto vendido. `0` quando não vinculado. | | `client_id` | `INT` | Cliente da venda. `0` quando não vinculado. | | `operator_id` | `INT` | Operador responsável. `0` quando não vinculado. | | `sale_external_id` | `TEXT` | ID da venda no CRM (idempotência). | | `sale_amount` | `DECIMAL(12,2)` | Valor faturado. | | `sale_quantity` | `INT` | Quantidade vendida. Default: `1`. | | `sale_occurred_at` | `TIMESTAMP` | Data/hora em que a venda ocorreu. | | `sale_created_at` | `TIMESTAMP` | Data de criação do registro. | | `sale_deleted_at` | `TIMESTAMP` | Exclusão lógica, padrão `'infinity'`. | **Restrições:** - `UNIQUE (company_id, sale_external_id)` (parcial, registros ativos) — evita duplicar faturamento em reenvios. - Índice `(company_id, sale_occurred_at)` para consultas de faturamento por período. ## Relacionamentos principais - **`user.company_id` → `company.company_id`** - **`operator.company_id` → `company.company_id`** - **`operator_channel.operator_id` → `operator.operator_id`** - **`sla_config.company_id` → `company.company_id`** - **`sku.company_id` → `company.company_id`** - **`integration.company_id` → `company.company_id`** - **`client.company_id` → `company.company_id`** - **`conversation.company_id` → `company.company_id`** - **`conversation.integration_id` → `integration.integration_id`** - **`conversation.operator_id` → `operator.operator_id`** - **`conversation.client_id` → `client.client_id`** - **`message.conversation_id` → `conversation.conversation_id`** - **`message.quoted_message_id` → `message.message_id`** - **`message_attachment.message_id` → `message.message_id`** - **`message_reaction.message_id` → `message.message_id`** - **`conversation_participant.conversation_id` → `conversation.conversation_id`** - **`webhook_event.integration_id` → `integration.integration_id`** - **`conversation_analysis.conversation_id` → `conversation.conversation_id`** - **`conversation_analysis.company_id` → `company.company_id`** - **`aspect_feedback.company_id` → `company.company_id`** - **`aspect_feedback.conversation_id` → `conversation.conversation_id`** - **`emotion_snapshot.company_id` → `company.company_id`** - **`public_opinion.company_id` → `company.company_id`** - **`public_opinion.conversation_id` → `conversation.conversation_id`** - **`alert.company_id` → `company.company_id`** - **`alert.client_id` → `client.client_id`** - **`ai_action.company_id` → `company.company_id`** - **`persona.company_id` → `company.company_id`** - **`client_persona.client_id` → `client.client_id`** - **`client_persona.persona_id` → `persona.persona_id`** - **`best_action.company_id` → `company.company_id`** - **`best_action.persona_id` → `persona.persona_id`** - **`volume_snapshot.company_id` → `company.company_id`** - **`sentiment_evolution.company_id` → `company.company_id`** - **`playbooks_monitor.company_id` → `company.company_id`** - **`operator_daily_stats.company_id` → `company.company_id`** - **`operator_daily_stats.operator_id` → `operator.operator_id`** - **`kpi_snapshot.company_id` → `company.company_id`** - **`sale.company_id` → `company.company_id`** ## Observações importantes - O campo `*_deleted_at = 'infinity'` indica registro ativo. - A lógica da aplicação deve considerar esse valor para filtros de registros válidos. - O setup do projeto recria o banco PostgreSQL antes de aplicar a migration. - A migration atual é a fonte de verdade da estrutura do banco. ## Resumo O schema foi projetado para armazenar: - cadastro de empresas e usuários, - operação de atendimento e conversas, - mensagens e anexos, - processamento de IA, - estratégia comercial, - métricas por dia e por empresa.