# Migrations — SGG

Este documento explica como o banco evolui entre blocos sem precisar
reimportar tudo nem perder dados.

## Conceito

Há **dois caminhos** para chegar ao banco atualizado:

1. **Instalação nova** → use o `database.sql`. Ele já contém o esquema
   completo e atualizado (estado consolidado), incluindo tudo o que as
   migrations abaixo aplicam. Quem instala do zero **não precisa** rodar
   migrations.

2. **Atualização de uma instalação existente** → rode os arquivos da pasta
   `migrations/` que ainda não foram aplicados, na ordem numérica. Eles
   alteram o banco já existente preservando os dados.

> Regra de ouro: o `database.sql` é sempre o "estado final". As migrations
> são o "caminho incremental" para quem já tinha uma versão anterior.

## Como aplicar as migrations (cPanel / phpMyAdmin)

1. Faça **backup** do banco antes (veja `BACKUP.md`).
2. Abra o phpMyAdmin e selecione o banco do sistema.
3. Aba **Importar** → selecione o primeiro arquivo de migration ainda não
   aplicado (ex.: `migrations/001_bloco2_ajustes.sql`) → **Executar**.
4. Repita para os arquivos seguintes, em ordem (`002_...`, `003_...`).
5. Confira se não houve erro. Pronto.

### Por linha de comando (se tiver acesso SSH)

```bash
mysql -u USUARIO -p NOME_DO_BANCO < migrations/001_bloco2_ajustes.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/002_bloco2_seeds.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/003_bloco3_midia.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/004_bloco6_agenda.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/005_bloco7_agenda_resultado.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/006_bloco7_coords_seed.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/007_bloco8_documents_public.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/008_fase10_hardening.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/009_hotfix101_neighborhoods.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/010_carga_bairros_uberlandia.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/011_bloco11_profile.sql
mysql -u USUARIO -p NOME_DO_BANCO < migrations/012_geo_agenda_events.sql
```

## Migrations existentes

| Arquivo                       | Bloco | O que faz                                                                 | Idempotente? |
|-------------------------------|-------|---------------------------------------------------------------------------|--------------|
| `001_bloco2_ajustes.sql`      | 2     | Adiciona em `citizens`: `nickname`, `is_community_leader`, `source_id` (FK). Adiciona em `users`: `region_id` (FK). Cria tabela `user_neighborhoods` (bairros atendidos). Garante índices únicos em `regions` e `departments`. | Sim¹         |
| `002_bloco2_seeds.sql`        | 2     | Popula regiões e bairros de Uberlândia, secretarias de exemplo, vínculo categoria→secretaria e a setting `city_name`. | Sim²         |
| `003_bloco3_midia.sql`        | 3     | Mídia: adiciona `region_id` em `media_files`; cria `media_tags`, `media_file_tags` (tags N:N) e `media_share_queue` (fila WhatsApp, sem envio). | Sim¹         |
| `004_bloco6_agenda.sql`       | 6     | Agenda: adiciona `status` e `region_id` em `agenda_events` e amplia o ENUM `type` (audiência, compromisso interno/externo). Nenhuma tabela nova. | Sim¹         |
| `005_bloco7_agenda_resultado.sql` | 7 | Agenda: adiciona `resultado` e `encaminhamentos` (TEXT) em `agenda_events`. Nenhuma tabela nova. | Sim¹ |
| `006_bloco7_coords_seed.sql`  | 7     | Seed de coordenadas aproximadas dos bairros de Uberlândia (dado de referência, para o mapa). Idempotente. | Sim |
| `007_bloco8_documents_public.sql` | 8 | Transparência: adiciona `is_public` e `published_at` em `documents` (publicação intencional). Nenhuma tabela nova. | Sim¹ |
| `008_fase10_hardening.sql`    | 10    | Hardening: `must_change_password` e `password_changed_at` em `users`; índice `idx_demands_created`. Marca o admin para trocar a senha. Nenhuma tabela nova. | Sim¹ |
| `009_hotfix101_neighborhoods.sql` | 10.1 | Saneia bairros: normaliza UTF8, funde duplicados (remapeia 10 tabelas), unicidade por (tenant,name), remove índice antigo. Nenhuma tabela nova. | Sim |
| `010_carga_bairros_uberlandia.sql` | — | Carga oficial dos 100 bairros de Uberlândia via UPSERT (NÃO apaga, NÃO reinicia AUTO_INCREMENT). Renomeia/funde "Roosevelt"→"Presidente Roosevelt" e acentuações, preservando vínculos. Adiciona coluna region_name. Faça BACKUP antes. | Sim |
| `011_bloco11_profile.sql` | 11 | Perfil: adiciona `avatar_path VARCHAR(255) NULL` e `preferences_json TEXT NULL` à tabela `users`. Idempotente via `IF NOT EXISTS`. | Sim |
| `012_geo_agenda_events.sql` | Geo Territorial | Coordenadas: adiciona `latitude DECIMAL(10,8) NULL` e `longitude DECIMAL(11,8) NULL` à tabela `agenda_events`, mais índice `idx_agenda_geo`. Idempotente via `IF NOT EXISTS`. | Sim |
| `013_geo_media_files.sql`       | Adiciona `latitude` e `longitude` à tabela `media_files`. INFORMATION_SCHEMA-safe. |
| `014_cep_address_fields.sql`    | Adiciona campos de endereço estruturado (CEP, número, cidade, estado) em `demands`, `technical_visits` e `agenda_events`. |

¹ A 001 só adiciona colunas/índices/FKs que ainda não existam (usa
  verificações em `information_schema`). Rodar mais de uma vez **não causa
  erro** e não duplica nada.

² A 002 usa `INSERT IGNORE` e `ON DUPLICATE KEY`, apoiada nos índices únicos
  criados pela 001. Pode ser repetida sem duplicar dados.

> Ambas as migrations do Bloco 2 foram testadas rodando **três vezes
> seguidas** sobre uma base do Bloco 1, sem erros e sem duplicação.

## Convenções para novas migrations (blocos futuros)

- Nome: `NNN_descricao.sql` com número sequencial de 3 dígitos.
- Uma migration por mudança lógica de schema; não misture blocos diferentes.
- Sempre que possível, escreva seeds idempotentes (`INSERT IGNORE` /
  `ON DUPLICATE KEY UPDATE`).
- Toda migration nova também deve ser refletida no `database.sql`
  (estado consolidado), para manter os dois caminhos equivalentes.
- Comente no topo do arquivo a que bloco pertence e o que faz.

## Como saber em que estado meu banco está?

Confira a presença das mudanças. Exemplos:

```sql
-- a 001 foi aplicada? (deve retornar a coluna)
SHOW COLUMNS FROM citizens LIKE 'nickname';
SHOW TABLES LIKE 'user_neighborhoods';

-- a 002 foi aplicada? (deve haver bairros)
SELECT COUNT(*) FROM neighborhoods;
```

Em blocos futuros poderá ser criada uma tabela `schema_migrations` para
registrar automaticamente o que já rodou; por ora o controle é manual e
simples, adequado ao tamanho do projeto.

---

## Bloco 13 — 015, 016, 017 (Governança Administrativa)

- **015_admin_status_tables.sql** — cria `demand_statuses`, `demand_priorities`,
  `visit_statuses`, `task_statuses`, `task_priorities` (slug estável = valor ENUM
  antigo) e faz o seed. Idempotente.
- **016_admin_status_fks.sql** — converte `demands.status/priority`,
  `technical_visits.status`, `tasks.status/priority` de ENUM para VARCHAR(30)
  preservando os valores; adiciona índices. **Não** altera `sla_status`.
  Idempotente (procedure detecta se ainda é ENUM).
- **017_settings_manage_seed.sql** — garante a permissão `settings.manage` e a
  liga ao papel admin. Idempotente.

Ordem em banco existente: aplicar 015 → 016 → 017. Em instalação nova, o
`database.sql` já inclui as três (idempotentes).

---

## Bloco 14 — 018 (Inteligência do Gabinete)

- **018_goals.sql** — cria a tabela `goals` (metas mensais: demands_resolved,
  visits_done, tasks_done). UNIQUE por (tenant_id, metric, period_month,
  period_year). Idempotente. Em instalação nova, o `database.sql` já a inclui.

---

## Hotfix — 019 (Padronização do título das mídias de demanda)

- **019_media_demand_title_protocol.sql** — atualiza (dados, não estrutura) o
  `title` das mídias existentes com `demand_id`, prefixando o protocolo no
  formato `PROTOCOLO — TÍTULO`. Idempotente (só atualiza quando o título ainda
  não começa com o protocolo). Fallback: título da demanda e, na falta dele,
  nome original do arquivo. Não toca em `original_name`, arquivos físicos,
  coordenadas ou descrição. Respeita o limite VARCHAR(200) via LEFT().
  Opcional: só aplicar se desejado padronizar o histórico (Opção B).

---

## Bloco — Registro de Evolução da Demanda — 020 (estágio da mídia)

- **020_media_demand_stage.sql** — adiciona a coluna `demand_stage VARCHAR(20)
  NOT NULL DEFAULT 'initial'` a `media_files` e o índice composto
  `idx_media_demand_stage (demand_id, demand_stage)`. Classifica cada mídia
  vinculada a uma demanda em `initial` (situação inicial — inclui todas as
  mídias antigas, migradas por backfill), `progress` (reservado) ou `final`
  (situação final). **VARCHAR e não ENUM**, por compatibilidade MySQL 5.7/8.0+
  e MariaDB 10.3+ e para permitir novos estágios sem ALTER de tipo; o conjunto
  lógico é garantido na camada PHP (`MediaFile`). Idempotente (guarda por
  INFORMATION_SCHEMA para coluna e índice; backfill só toca mídias vinculadas
  a demanda sem estágio válido). Em instalação nova, o `database.sql` já inclui
  a coluna e o índice. Não cria tabela nova; não altera outras colunas.

---

## Bloco 15 — 021 (Central de Comunicação e Marketing)

- **021_communication.sql** — cria a estrutura própria e desacoplada da
  comunicação: `communication_items` (UNIQUE por `demand_id` — nunca duplica),
  `communication_statuses` (10 status configuráveis), `communication_status_history`,
  `communication_checklists`, `communication_publications`, `communication_assignments`,
  e 6 permissões próprias (`communication.view/create/update/assign/publish/archive`)
  ligadas a admin/chefe_gabinete/marketing/equipe_rua/vereador. VARCHAR (não ENUM)
  para status. Idempotente (CREATE TABLE IF NOT EXISTS + inserts guardados por
  NOT EXISTS / ON DUPLICATE KEY). Em instalação nova, `database.sql` já inclui
  todas as tabelas, o seed de status e as permissões. Não usa a tabela `demands`
  para dados de comunicação; bairro/região/solicitante/secretaria vêm por JOIN.

---

## Bloco 16 — Consolidação / Auditoria Geral (sem novas migrations)

Auditoria completa da plataforma rumo à v1.0. **Nenhuma migration nova** e
nenhuma alteração de schema — as melhorias foram apenas de código (segurança,
auditoria e performance). Confirmado o fluxo de instalação:

    Banco vazio → database.sql → migrations 001..021 → sistema funcional (59 tabelas)

Idempotência de todas as 21 migrations reconfirmada (rodadas 2× sem divergência).
