Pular para conteúdo

Modelo de Dados

Diagrama Logico

Text Only
+----------------+         +-------------------+         +-------------------+
|   User (auth)  |         |  ContactGroup     |         |     Contact       |
+----------------+         +-------------------+         +-------------------+
| id             |         | id                |         | id                |
| username       |         | name              |  M:N    | phone (unique)    |
| email          |         | description       |--+----->| name              |
| password       |         | color             |         | groups (FK M:N)   |
| permissions    |         | is_active         |         | created_at        |
+--------+-------+         +-------------------+         +---------+---------+
         |                                                         |
         | 1:N (operator)                                          | 1:N
         |                                                         |
         v                                                         v
+--------+--------------+                                +---------+---------+
|     MessageLog        |                                |    SurveyRun      |
+-----------------------+         +----------+           +-------------------+
| id                    |   FK    |  Survey  |    1:N    | id                |
| direction (in|out)    | <-----+-+----------+---------> | survey (FK)       |
| phone                 |       | | id       |           | contact (FK)      |
| payload (JSONB)       |       | | code     |           | token             |
| source (survey|chat)  |       | | title    |           | started_at        |
| status                |       | | version  |           | completed_at      |
| operator (FK User)    |       | | is_active|           | last_activity_at  |
| wa_message_id         |       | +----+-----+           | status            |
| run (FK SurveyRun)    | <-+   |      |                 | current_question  |
| created_at            |   |   |      | 1:N             | is_scheduled      |
| updated_at            |   |   |      v                 | scheduled_at      |
+-----------------------+   |   | +----+-----------+     | sent_at           |
                            |   | | SurveyQuestion |     | meta (JSONB)      |
                            |   | +----------------+     | created_at        |
                            |   | | id             |     | updated_at        |
                            |   | | number         |     +---------+---------+
                            |   | | kind           |               |
                            |   | | text           |               | 1:N
                            |   | | options        |               v
                            |   | | required       |     +---------+---------+
                            |   | | conditions  *  |     |   SurveyAnswer    |
                            |   | +-------+--------+     +-------------------+
                            |   |         |              | id                |
                            |   |         | 1:N          | run (FK)          |
                            |   |         v              | question (FK)     |
                            |   | +-------+----------+   | number            |
                            |   | | QuestionCondition|   | answer_text       |
                            |   | +------------------+   | answer_numeric    |
                            |   | | condition_type   |   | answer_option     |
                            |   | | condition_value  |   | answered_at       |
                            |   | | next_question    |   +-------------------+
                            |   | | terminates       |
                            |   | +------------------+
                            |   |
                            +---+--- 1:N (run)
                            |
                            v
                  +---------+---------+
                  |   Conversation    |  (chat livre)
                  +-------------------+
                  | id                |
                  | phone             |
                  | contact (FK)      |
                  | status (active|   |
                  |   archived)       |
                  | assigned_to (User)|
                  | last_message_at   |
                  +-------------------+

Tabelas Principais

contacts_contact

Cadastro de contatos que recebem pesquisas.

Campo Tipo Constraint Descricao
id bigint PK
phone varchar(20) unique, indexed Numero com DDI (ex: 5511999999999)
name varchar(255) nullable Nome do contato
created_at timestamp auto
updated_at timestamp auto

Relacionamento M:N com ContactGroup via tabela contacts_contact_groups.

contacts_contactgroup

Agrupamento logico de contatos (ex: "Cirurgias Maio", "Pacientes VIP").

Campo Tipo Constraint
id bigint PK
name varchar(100) required
description text
color varchar(7) hex color
is_active boolean default True

surveys_survey

Definicao da pesquisa (template). Uma Survey pode ser executada N vezes (gerando N SurveyRun).

Campo Tipo Constraint Descricao
id bigint PK
code varchar(50) unique Codigo curto (ex: "01")
title varchar(255) required Titulo
version int default 1 Versionamento
is_active boolean default True
welcome_messages JSONB Mensagens de boas vindas se nao usa template
completion_message text Texto generico de conclusao
use_conditional_flow boolean default False Permite ramificacoes
use_whatsapp_template boolean Usa template aprovado da Meta
whatsapp_template_name varchar Nome do template (ex: "highlas")
whatsapp_template_language varchar Codigo (ex: "pt_BR")
whatsapp_template_params JSONB Mapeamento de parametros do template

surveys_surveyquestion

Perguntas de uma pesquisa, na ordem definida por number.

Campo Tipo Constraint Descricao
id bigint PK
survey FK Survey CASCADE
number int required Ordem (1, 2, 3...)
kind varchar choices nps, csat, ces, likert, yesno, multi, open
text text required Texto da pergunta
options JSONB nullable Opcoes para multi
required boolean default True
response_type varchar choices numeric, buttons, list, quick_reply
button_options JSONB Botoes/itens da lista
is_terminal boolean default False Termina o fluxo apos resposta
default_next_question FK SurveyQuestion nullable Proxima se nenhuma condicional bater

surveys_questioncondition

Regras de ramificacao apos uma pergunta. Multiplas conditions podem existir para a mesma question, ordenadas por priority.

Campo Tipo Descricao
id bigint
question FK SurveyQuestion CASCADE
condition_type varchar choices: range_numeric, equals_value, button_selected, text_contains, any
condition_value varchar Ex: "0-6" para range, "sim" para equals
next_question FK SurveyQuestion Proxima se a condicao bater
priority int Avaliacao em ordem (menor = primeiro)
terminates_survey boolean Se True, finaliza
termination_message text Mensagem custom de conclusao

responses_surveyrun

Execucao de uma pesquisa para um contato especifico.

Campo Tipo Constraint Descricao
id bigint PK
survey FK Survey CASCADE
contact FK Contact CASCADE
token uuid nullable Para deeplinks
started_at timestamp nullable Quando entrou em in_progress
completed_at timestamp nullable Quando entrou em status final
last_activity_at timestamp nullable, indexed Ultima resposta do cliente
status varchar choices pending, in_progress, completed, expired, opt_out
current_question int default 1 Pergunta atual
meta JSONB nullable Dados auxiliares (campanha, etc)
scheduled_at timestamp nullable Quando deve ser enviada (futuro)
is_scheduled boolean default False
sent_at timestamp nullable Quando template foi enviado
created_at timestamp auto
updated_at timestamp auto

Indices: - (status, scheduled_at) - para task send_scheduled_surveys - (survey, status) - relatorios por pesquisa - (contact, status) - busca de runs ativas - (is_scheduled, sent_at) - agendados pendentes - (status, last_activity_at) - task expire_stale_runs

responses_surveyanswer

Respostas individuais a uma pergunta.

Campo Tipo Descricao
id bigint
run FK SurveyRun CASCADE, related_name='answers'
question FK SurveyQuestion
number int Copia de question.number para facilitar consultas
answer_text text Para abertas, yesno, etc
answer_numeric decimal(5,2) Para NPS, CSAT, CES
answer_option varchar Codigo da opcao escolhida
answered_at timestamp Quando respondeu

Constraint: unique_together = (run, question) - uma resposta por pergunta por execucao.


whatsapp_messagelog

Log de TODAS as mensagens trocadas (in e out, survey e chat).

Campo Tipo Descricao
id bigint
direction varchar(3) "in" ou "out"
phone varchar(20) indexed
payload JSONB Payload completo da Meta API
status varchar sent, delivered, read, failed
source varchar(10) survey, chat, system, indexed
operator FK User nullable, related_name='sent_messages'
wa_message_id varchar(128) indexed, nullable, "wamid..."
run FK SurveyRun nullable (SET_NULL), indexed
created_at timestamp auto
updated_at timestamp auto

Indices: - (direction, created_at) - (phone, created_at) - (run, direction) - (status,) - (source, phone, created_at)

Tabela com alto volume - cresce N x M (mensagens x contatos). Considerar particionamento por mes em volumes >1M registros.


chat_conversation

Estado das conversas livres (operador-cliente), separadas das mensagens isoladas em MessageLog.

Campo Tipo Descricao
id bigint
phone varchar(20) unique
contact FK Contact nullable
status varchar active, archived
assigned_to FK User operador responsavel
last_message_at timestamp para ordenar por recencia
last_message_preview text para sidebar
unread_count int mensagens nao lidas pelo operador

Cardinalidades Tipicas

Estimativa para o cliente Highlas em 1 ano de uso:

Entidade Volume esperado
Contact 5.000 - 50.000
ContactGroup <100
Survey <50
SurveyQuestion (por Survey) 3-10
QuestionCondition (por Question) 0-5
SurveyRun 50.000 - 500.000
SurveyAnswer 200.000 - 2.500.000
MessageLog 500.000 - 5.000.000

Estrategias de Limpeza

Dados sensiveis (LGPD)

MessageLog.payload armazena o JSON original do webhook Meta, que inclui: - Numero do remetente - Texto/midia da mensagem - Nome do perfil do WhatsApp

Para conformidade LGPD, considerar: - Anonimizacao apos N anos (substituir phone por hash) - Direito ao esquecimento (endpoint para remover dados de um contato)

Backup periodico

Vide backup-restauracao.md.


Migrations Importantes

App Migration Mudanca
responses 0001_initial Modelos base
responses 0003_surveyrun_scheduling_fields Adicionou is_scheduled, scheduled_at, sent_at
responses 0005_create_periodic_tasks Task send_scheduled_surveys
responses 0006_add_last_activity_at Campo para detectar abandono
responses 0007_create_expire_runs_task Task expire_stale_runs
whatsapp (multiple) Adicao gradual de source, wa_message_id, operator
chat 0001_initial Sistema de chat livre

Para listar:

Bash
docker compose exec backend python manage.py showmigrations