Modelo de Dados¶
Diagrama Logico¶
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 | |
|---|---|