From c5ebbd50b5507489c8213ba46476a245553ea835 Mon Sep 17 00:00:00 2001 From: Rafael Lopes Date: Fri, 24 Jul 2026 15:22:26 -0300 Subject: [PATCH] =?UTF-8?q?REFACTOR:=20Estrutura=20de=20migrations=20com?= =?UTF-8?q?=20rastreamento=20e=20separa=C3=A7=C3=A3o=20de=20seeds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduz schema_migrations para controle de migrations já aplicadas: apenas arquivos novos rodam a cada deploy, eliminando re-execuções - Renumera migrations de 001 a 026 sem lacunas (gaps em 013 e 024 fechados) - Adiciona 008_mensagens.sql: CREATE TABLE que estava ausente do repositório - Corrige idempotência de 015_configurable_triage_flow: adiciona UNIQUE (flow_id, label) e (audience_id, label) e targets explícitos no ON CONFLICT que antes duplicava dados a cada deploy - Separa dados de demonstração em database/seeds/ (só roda em dev/uat) - Remove seeds e migrations sem propósito: seeds/002 e 027 tornados obsoletos com a remoção dos opening templates - Atualiza deploy-dev.yml: loop com checagem de tracking + passo de seeds --- .gitea/workflows/deploy-dev.yml | 38 +++++++++++++++++-- database/migrations/000_schema_migrations.sql | 38 +++++++++++++++++++ .../{004_whatsapp.sql => 003_whatsapp.sql} | 0 ...mplates.sql => 004_whatsapp_templates.sql} | 0 ....sql => 005_whatsapp_assignment_queue.sql} | 0 ...tate.sql => 006_whatsapp_triage_state.sql} | 0 ...08_agent_notes.sql => 007_agent_notes.sql} | 0 database/migrations/008_mensagens.sql | 17 +++++++++ ... 011_whatsapp_awaiting_customer_reply.sql} | 0 .../011_whatsapp_opening_templates.sql | 19 ---------- ...sql => 012_whatsapp_template_workflow.sql} | 0 ...pause.sql => 013_agent_presence_pause.sql} | 0 ....sql => 014_hr_decision_tree_keywords.sql} | 0 ...w.sql => 015_configurable_triage_flow.sql} | 12 +++--- ...tep.sql => 016_triage_resolution_step.sql} | 0 ...w_builder.sql => 017_bot_flow_builder.sql} | 0 ...delete.sql => 018_bot_flow_close_node.sql} | 0 ...ts.sql => 019_admin_audit_ai_contents.sql} | 0 ...sql => 020_whatsapp_template_category.sql} | 0 ...ls.sql => 021_agenda_contact_channels.sql} | 0 ...app_config.sql => 022_whatsapp_config.sql} | 0 ...hsm.sql => 023_whatsapp_templates_hsm.sql} | 0 ...ns.sql => 024_mensagens_media_columns.sql} | 0 ...e.sql => 025_mensagens_media_filename.sql} | 0 ...ates.sql => 026_remove_fake_templates.sql} | 0 .../030_remove_opening_templates.sql | 18 --------- .../001_demo_access.sql} | 0 27 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 database/migrations/000_schema_migrations.sql rename database/migrations/{004_whatsapp.sql => 003_whatsapp.sql} (100%) rename database/migrations/{005_templates.sql => 004_whatsapp_templates.sql} (100%) rename database/migrations/{006_whatsapp_assignment_queue.sql => 005_whatsapp_assignment_queue.sql} (100%) rename database/migrations/{007_whatsapp_triage_state.sql => 006_whatsapp_triage_state.sql} (100%) rename database/migrations/{008_agent_notes.sql => 007_agent_notes.sql} (100%) create mode 100644 database/migrations/008_mensagens.sql rename database/migrations/{012_whatsapp_awaiting_customer_reply.sql => 011_whatsapp_awaiting_customer_reply.sql} (100%) delete mode 100644 database/migrations/011_whatsapp_opening_templates.sql rename database/migrations/{014_whatsapp_template_workflow.sql => 012_whatsapp_template_workflow.sql} (100%) rename database/migrations/{015_agent_presence_pause.sql => 013_agent_presence_pause.sql} (100%) rename database/migrations/{016_hr_decision_tree_keywords.sql => 014_hr_decision_tree_keywords.sql} (100%) rename database/migrations/{017_configurable_triage_flow.sql => 015_configurable_triage_flow.sql} (94%) rename database/migrations/{018_triage_resolution_step.sql => 016_triage_resolution_step.sql} (100%) rename database/migrations/{019_bot_flow_builder.sql => 017_bot_flow_builder.sql} (100%) rename database/migrations/{020_bot_flow_close_node_and_area_delete.sql => 018_bot_flow_close_node.sql} (100%) rename database/migrations/{021_admin_audit_ai_contents.sql => 019_admin_audit_ai_contents.sql} (100%) rename database/migrations/{022_whatsapp_template_category.sql => 020_whatsapp_template_category.sql} (100%) rename database/migrations/{023_agenda_contact_channels.sql => 021_agenda_contact_channels.sql} (100%) rename database/migrations/{025_whatsapp_config.sql => 022_whatsapp_config.sql} (100%) rename database/migrations/{026_whatsapp_templates_hsm.sql => 023_whatsapp_templates_hsm.sql} (100%) rename database/migrations/{027_mensagens_media_columns.sql => 024_mensagens_media_columns.sql} (100%) rename database/migrations/{028_mensagens_media_filename.sql => 025_mensagens_media_filename.sql} (100%) rename database/migrations/{029_remove_fake_templates.sql => 026_remove_fake_templates.sql} (100%) delete mode 100644 database/migrations/030_remove_opening_templates.sql rename database/{migrations/003_demo_access.sql => seeds/001_demo_access.sql} (100%) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index ed97a13..5774426 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -62,8 +62,40 @@ jobs: PGHOST="${PGHOST//[$'\t\r\n ']}" PGPORT="${PGPORT//[$'\t\r\n ']}" export PGHOST PGPORT - echo "Aplicando migrations..." - for f in $(ls "$DEPLOY_PATH/database/migrations/"*.sql | sort); do - echo "Aplicando: $(basename "$f")" + + echo "Inicializando controle de migrations..." + psql -v ON_ERROR_STOP=1 -f "$DEPLOY_PATH/database/migrations/000_schema_migrations.sql" + + echo "Aplicando migrations pendentes..." + for f in $(ls "$DEPLOY_PATH/database/migrations/"[0-9][0-9][0-9]_*.sql | sort); do + filename=$(basename "$f") + already_run=$(psql -tAc "SELECT COUNT(*) FROM schema_migrations WHERE filename = '$filename'") + if [ "$already_run" = "0" ]; then + echo "Aplicando: $filename" + psql -v ON_ERROR_STOP=1 -f "$f" + psql -c "INSERT INTO schema_migrations (filename) VALUES ('$filename') ON CONFLICT DO NOTHING" + echo "OK: $filename" + else + echo "Ignorando (ja aplicada): $filename" + fi + done + + - name: Executar seeds (dev) + shell: bash + env: + PGHOST: ${{ secrets.DB_HOST }} + PGPORT: ${{ secrets.DB_PORT }} + PGUSER: ${{ secrets.DB_USER }} + PGDATABASE: ${{ secrets.DB_NAME }} + PGPASSWORD: ${{ secrets.DB_PASSWORD }} + run: | + set -euo pipefail + PGHOST="${PGHOST//[$'\t\r\n ']}" + PGPORT="${PGPORT//[$'\t\r\n ']}" + export PGHOST PGPORT + + echo "Aplicando seeds de desenvolvimento..." + for f in $(ls "$DEPLOY_PATH/database/seeds/"*.sql | sort); do + echo "Seed: $(basename "$f")" psql -v ON_ERROR_STOP=1 -f "$f" done diff --git a/database/migrations/000_schema_migrations.sql b/database/migrations/000_schema_migrations.sql new file mode 100644 index 0000000..4025320 --- /dev/null +++ b/database/migrations/000_schema_migrations.sql @@ -0,0 +1,38 @@ +-- Migration 000: Controle de migrations aplicadas +-- Este arquivo roda sempre (antes do loop principal) e e idempotente. +-- Cria a tabela de rastreamento e marca todas as migrations existentes +-- como ja aplicadas para que nao re-executem em ambientes ja provisionados. + +CREATE TABLE IF NOT EXISTS schema_migrations ( + filename VARCHAR(255) PRIMARY KEY, + applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO schema_migrations (filename) VALUES + ('001_auth.sql'), + ('002_area.sql'), + ('003_whatsapp.sql'), + ('004_whatsapp_templates.sql'), + ('005_whatsapp_assignment_queue.sql'), + ('006_whatsapp_triage_state.sql'), + ('007_agent_notes.sql'), + ('008_mensagens.sql'), + ('009_customer_contacts.sql'), + ('010_agenda_contatos.sql'), + ('011_whatsapp_awaiting_customer_reply.sql'), + ('012_whatsapp_template_workflow.sql'), + ('013_agent_presence_pause.sql'), + ('014_hr_decision_tree_keywords.sql'), + ('015_configurable_triage_flow.sql'), + ('016_triage_resolution_step.sql'), + ('017_bot_flow_builder.sql'), + ('018_bot_flow_close_node.sql'), + ('019_admin_audit_ai_contents.sql'), + ('020_whatsapp_template_category.sql'), + ('021_agenda_contact_channels.sql'), + ('022_whatsapp_config.sql'), + ('023_whatsapp_templates_hsm.sql'), + ('024_mensagens_media_columns.sql'), + ('025_mensagens_media_filename.sql'), + ('026_remove_fake_templates.sql') +ON CONFLICT DO NOTHING; diff --git a/database/migrations/004_whatsapp.sql b/database/migrations/003_whatsapp.sql similarity index 100% rename from database/migrations/004_whatsapp.sql rename to database/migrations/003_whatsapp.sql diff --git a/database/migrations/005_templates.sql b/database/migrations/004_whatsapp_templates.sql similarity index 100% rename from database/migrations/005_templates.sql rename to database/migrations/004_whatsapp_templates.sql diff --git a/database/migrations/006_whatsapp_assignment_queue.sql b/database/migrations/005_whatsapp_assignment_queue.sql similarity index 100% rename from database/migrations/006_whatsapp_assignment_queue.sql rename to database/migrations/005_whatsapp_assignment_queue.sql diff --git a/database/migrations/007_whatsapp_triage_state.sql b/database/migrations/006_whatsapp_triage_state.sql similarity index 100% rename from database/migrations/007_whatsapp_triage_state.sql rename to database/migrations/006_whatsapp_triage_state.sql diff --git a/database/migrations/008_agent_notes.sql b/database/migrations/007_agent_notes.sql similarity index 100% rename from database/migrations/008_agent_notes.sql rename to database/migrations/007_agent_notes.sql diff --git a/database/migrations/008_mensagens.sql b/database/migrations/008_mensagens.sql new file mode 100644 index 0000000..4110916 --- /dev/null +++ b/database/migrations/008_mensagens.sql @@ -0,0 +1,17 @@ +-- Migration 008: Tabela de mensagens do WhatsApp +CREATE TABLE IF NOT EXISTS mensagens ( + id SERIAL PRIMARY KEY, + wamid VARCHAR(255) NOT NULL, + chat_id VARCHAR(255) NOT NULL, + from_me BOOLEAN NOT NULL DEFAULT FALSE, + type VARCHAR(50) NOT NULL, + body TEXT, + sender_name VARCHAR(255), + status VARCHAR(50), + timestamp BIGINT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + UNIQUE (wamid) +); + +CREATE INDEX IF NOT EXISTS idx_mensagens_chat_id ON mensagens (chat_id); +CREATE INDEX IF NOT EXISTS idx_mensagens_timestamp ON mensagens (timestamp DESC); diff --git a/database/migrations/012_whatsapp_awaiting_customer_reply.sql b/database/migrations/011_whatsapp_awaiting_customer_reply.sql similarity index 100% rename from database/migrations/012_whatsapp_awaiting_customer_reply.sql rename to database/migrations/011_whatsapp_awaiting_customer_reply.sql diff --git a/database/migrations/011_whatsapp_opening_templates.sql b/database/migrations/011_whatsapp_opening_templates.sql deleted file mode 100644 index 7fc3bc6..0000000 --- a/database/migrations/011_whatsapp_opening_templates.sql +++ /dev/null @@ -1,19 +0,0 @@ --- ============================================================ --- Migration 011: Templates de abertura ativa do WhatsApp --- Tabela: whatsapp_templates --- ============================================================ - -INSERT INTO whatsapp_templates (name, content) VALUES -('abertura_atendimento_padrao', 'Ola, {nome}. Tudo bem? Estamos entrando em contato pelo atendimento. Podemos seguir por aqui?'), -('abertura_retorno_contato', 'Ola, {nome}. Estamos retornando seu contato para dar continuidade ao seu atendimento.'), -('abertura_suporte', 'Ola, {nome}. Aqui e do suporte. Estamos entrando em contato para te ajudar com sua solicitacao.'), -('abertura_financeiro', 'Ola, {nome}. Aqui e do financeiro. Estamos entrando em contato para tratar de uma informacao importante sobre seu atendimento.'), -('abertura_comercial', 'Ola, {nome}. Aqui e do comercial. Estamos entrando em contato para conversar sobre sua solicitacao.'), -('abertura_confirmacao_dados', 'Ola, {nome}. Precisamos confirmar alguns dados para seguir com seu atendimento.'), -('abertura_contato_agendado', 'Ola, {nome}. Este contato foi combinado anteriormente e estamos disponiveis para seguir.'), -('abertura_pos_atendimento', 'Ola, {nome}. Estamos fazendo um acompanhamento sobre seu atendimento recente.'), -('abertura_aviso_importante', 'Ola, {nome}. Temos uma informacao importante para compartilhar com voce.'), -('abertura_contato_inicial', 'Ola, {nome}. Vamos iniciar seu atendimento por este canal.') -ON CONFLICT (name) DO UPDATE SET - content = EXCLUDED.content, - updated_at = CURRENT_TIMESTAMP; diff --git a/database/migrations/014_whatsapp_template_workflow.sql b/database/migrations/012_whatsapp_template_workflow.sql similarity index 100% rename from database/migrations/014_whatsapp_template_workflow.sql rename to database/migrations/012_whatsapp_template_workflow.sql diff --git a/database/migrations/015_agent_presence_pause.sql b/database/migrations/013_agent_presence_pause.sql similarity index 100% rename from database/migrations/015_agent_presence_pause.sql rename to database/migrations/013_agent_presence_pause.sql diff --git a/database/migrations/016_hr_decision_tree_keywords.sql b/database/migrations/014_hr_decision_tree_keywords.sql similarity index 100% rename from database/migrations/016_hr_decision_tree_keywords.sql rename to database/migrations/014_hr_decision_tree_keywords.sql diff --git a/database/migrations/017_configurable_triage_flow.sql b/database/migrations/015_configurable_triage_flow.sql similarity index 94% rename from database/migrations/017_configurable_triage_flow.sql rename to database/migrations/015_configurable_triage_flow.sql index 6f974fb..04cc0c1 100644 --- a/database/migrations/017_configurable_triage_flow.sql +++ b/database/migrations/015_configurable_triage_flow.sql @@ -1,5 +1,5 @@ -- ============================================================ --- Migration 017: Fluxo configuravel de triagem do Agente Virtual Sothis +-- Migration 015: Fluxo configuravel de triagem do Agente Virtual Sothis -- Tabelas: -- bot_triage_flows -- bot_triage_audiences @@ -29,7 +29,8 @@ CREATE TABLE IF NOT EXISTS bot_triage_audiences ( sort_order INTEGER NOT NULL DEFAULT 1, active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + UNIQUE (flow_id, label) ); CREATE TABLE IF NOT EXISTS bot_triage_intents ( @@ -41,7 +42,8 @@ CREATE TABLE IF NOT EXISTS bot_triage_intents ( sort_order INTEGER NOT NULL DEFAULT 1, active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + UNIQUE (audience_id, label) ); ALTER TABLE whatsapp_chat_atribuicoes @@ -114,7 +116,7 @@ JOIN ( ('Sou ex-colaborador', 'ex colaborador, ex-colaborador, rescisao, fgts, informe de rendimentos, desligamento', 2), ('Sou candidato a uma vaga', 'candidato, vaga, curriculo, processo seletivo, entrevista, candidatura', 3) ) AS seed(label, keywords, sort_order) ON TRUE -ON CONFLICT DO NOTHING; +ON CONFLICT (flow_id, label) DO NOTHING; WITH audiences AS ( SELECT bta.id, bta.label @@ -142,4 +144,4 @@ SELECT audiences.id, seed.label, areas.id, seed.keywords, seed.sort_order, TRUE, FROM seed INNER JOIN audiences ON audiences.label = seed.audience_label INNER JOIN areas ON areas.nome = seed.area_nome -ON CONFLICT DO NOTHING; +ON CONFLICT (audience_id, label) DO NOTHING; diff --git a/database/migrations/018_triage_resolution_step.sql b/database/migrations/016_triage_resolution_step.sql similarity index 100% rename from database/migrations/018_triage_resolution_step.sql rename to database/migrations/016_triage_resolution_step.sql diff --git a/database/migrations/019_bot_flow_builder.sql b/database/migrations/017_bot_flow_builder.sql similarity index 100% rename from database/migrations/019_bot_flow_builder.sql rename to database/migrations/017_bot_flow_builder.sql diff --git a/database/migrations/020_bot_flow_close_node_and_area_delete.sql b/database/migrations/018_bot_flow_close_node.sql similarity index 100% rename from database/migrations/020_bot_flow_close_node_and_area_delete.sql rename to database/migrations/018_bot_flow_close_node.sql diff --git a/database/migrations/021_admin_audit_ai_contents.sql b/database/migrations/019_admin_audit_ai_contents.sql similarity index 100% rename from database/migrations/021_admin_audit_ai_contents.sql rename to database/migrations/019_admin_audit_ai_contents.sql diff --git a/database/migrations/022_whatsapp_template_category.sql b/database/migrations/020_whatsapp_template_category.sql similarity index 100% rename from database/migrations/022_whatsapp_template_category.sql rename to database/migrations/020_whatsapp_template_category.sql diff --git a/database/migrations/023_agenda_contact_channels.sql b/database/migrations/021_agenda_contact_channels.sql similarity index 100% rename from database/migrations/023_agenda_contact_channels.sql rename to database/migrations/021_agenda_contact_channels.sql diff --git a/database/migrations/025_whatsapp_config.sql b/database/migrations/022_whatsapp_config.sql similarity index 100% rename from database/migrations/025_whatsapp_config.sql rename to database/migrations/022_whatsapp_config.sql diff --git a/database/migrations/026_whatsapp_templates_hsm.sql b/database/migrations/023_whatsapp_templates_hsm.sql similarity index 100% rename from database/migrations/026_whatsapp_templates_hsm.sql rename to database/migrations/023_whatsapp_templates_hsm.sql diff --git a/database/migrations/027_mensagens_media_columns.sql b/database/migrations/024_mensagens_media_columns.sql similarity index 100% rename from database/migrations/027_mensagens_media_columns.sql rename to database/migrations/024_mensagens_media_columns.sql diff --git a/database/migrations/028_mensagens_media_filename.sql b/database/migrations/025_mensagens_media_filename.sql similarity index 100% rename from database/migrations/028_mensagens_media_filename.sql rename to database/migrations/025_mensagens_media_filename.sql diff --git a/database/migrations/029_remove_fake_templates.sql b/database/migrations/026_remove_fake_templates.sql similarity index 100% rename from database/migrations/029_remove_fake_templates.sql rename to database/migrations/026_remove_fake_templates.sql diff --git a/database/migrations/030_remove_opening_templates.sql b/database/migrations/030_remove_opening_templates.sql deleted file mode 100644 index 841606c..0000000 --- a/database/migrations/030_remove_opening_templates.sql +++ /dev/null @@ -1,18 +0,0 @@ --- Migration 030: Remove templates de abertura sem vinculo com a Meta --- A migration 011 re-insere esses templates em todo deploy via ON CONFLICT DO UPDATE. --- Este arquivo garante que sejam removidos caso nao estejam vinculados a Meta. - -DELETE FROM whatsapp_templates -WHERE name IN ( - 'abertura_atendimento_padrao', - 'abertura_retorno_contato', - 'abertura_suporte', - 'abertura_financeiro', - 'abertura_comercial', - 'abertura_confirmacao_dados', - 'abertura_contato_agendado', - 'abertura_pos_atendimento', - 'abertura_aviso_importante', - 'abertura_contato_inicial' -) -AND meta_template_name IS NULL; diff --git a/database/migrations/003_demo_access.sql b/database/seeds/001_demo_access.sql similarity index 100% rename from database/migrations/003_demo_access.sql rename to database/seeds/001_demo_access.sql