# Backlog Priorizado para a Reconstrução (v7)

> **Data:** 2026-10-21
> **Fonte:** `dossie_modules/_00_panorama/17-REGISTRO-DE-BUGS.md` (204 itens catalogados, com evidência `arquivo:linha` confirmada)
> **Objetivo:** backlog executável, ordenado por prioridade, com esforço, risco e dependências.
> **Alvo:** PHP 8.x + Laravel 11/12 + PostgreSQL.

---

## 1. Legenda

| Prioridade | Critério |
|---|---|
| **P0** | Bloqueador. Exposição de dados/injeção/autorização ausente agora, ou pré-requisito de qualquer migração de módulo de escrita. |
| **P1** | Quebra funcionalidade do CMS ou do portal em uso corrente. |
| **P2** | Dívida técnica e risco de migração: não quebra hoje, mas custa retrabalho ou perda de dado se ignorado. |
| **P3** | Qualidade de código, UX, limpeza, código morto. |

**Esforço (P/M/G em horas):** `P` = até 4 h · `M` = 4–16 h · `G` = 16–60 h · `GG` = > 60 h.
Ver §5 para a ressalva sobre a natureza das estimativas.

**Risco se não corrigido:** `Crítico` (exposição de dado ou perda) · `Alto` (funcionalidade quebrada) · `Médio` (degradação) · `Baixo` (higiene).

> **Regra de sequenciamento:** nenhum módulo de escrita é migrado para a v7 antes de o
> item P0 de autorização correspondente estar resolvido (ver Sprint 1).

---

## 2. Backlog por prioridade

### 2.1 P0 — Bloqueadores

| ID | Sev. | Esforço | Risco se não corrigido | Dependências | Módulo |
|---|---|---|---|---|---|
| BUG-SEC-001 | Crítica | M | Crítico — leitura arbitrária do banco por anônimo | — | legislacao, publicacoes, atas-e-pontos, comite-de-investimentos |
| BUG-SEC-002 | Crítica | M | Crítico — extração de CPF/nome de servidores | — | requerimento-de-diarias, legislacao, atas-e-pontos, comite-de-investimentos |
| BUG-SEC-003 | Crítica | G | Crítico — escrita do CMS por anônimo em 80 controllers | — | plataforma (todos os módulos do CMS) |
| BUG-SEC-004 | Crítica | M | Crítico — criação/alteração/exclusão sem login | BUG-SEC-003 | e-vacina, enquetes, drive, mais-conteudos |
| BUG-SEC-005 | Crítica | M | Crítico — qualquer usuário logado escreve em qualquer recurso | BUG-SEC-003 | plataforma |
| BUG-SEC-006 | Crítica | P | Crítico — credencial de serviço pago no histórico do Git | — | gemini |
| BUG-SEC-007 | Crítica | P | Crítico — consumo da cota da IA por anônimo | BUG-SEC-006 | gemini |
| BUG-SEC-008 | Crítica | M | Crítico — acervo de arquivos legível e gravável por anônimo | BUG-SEC-003 | arquivo, drive |
| BUG-SEC-009 | Crítica | M | Crítico — execução de comando com senha do usuário | — | diario-oficial |
| BUG-SEC-026 | Crítica | M | Crítico — escalada de privilégio: usuário comum cria perfil `super-admin` | BUG-SEC-005 | usuarios |
| BUG-SEC-027 | Crítica | M | Crítico — exclusão de arquivo de qualquer módulo | BUG-SEC-003 | viap, arquivo |
| BUG-SEC-017 | Alta | M | Crítico — SQL injection no portal público (v5) | — | obras |
| BUG-SEC-018 | Alta | M | Crítico — SQL injection na API Swagger | — | orgaos |
| BUG-SEC-013 | Alta | M | Alto — stack trace e credencial de banco expostos | — | plataforma (todos os repositórios) |
| BUG-SEC-015 | Alta | M | Alto — leitura de segredos por qualquer operador | — | configuracoes-da-instituicao |
| BUG-SEC-016 | Alta | G | Alto — XSS armazenado no portal público | — | multiplos |
| BUG-SEC-021 | Alta | M | Alto — upload de qualquer tipo de arquivo | — | arquivo, carta-de-servicos, agenda-de-eventos |
| BUG-DATA-001 | Crítica | M | Crítico — corrupção silenciosa de manifestações | — | ouvidoria |
| BUG-DATA-002 | Crítica | M | Crítico — exclusão do anexo errado | — | licitacoes |
| BUG-FUNC-001 | Crítica | M | Crítico — Carta de Serviços sem geração de PDF | — | carta-de-servicos |
| BUG-MIG-001 | Crítica | GG | Crítico — 8 módulos precisam ser reconstruídos do zero | — | multiplos (ver §4 do registro) |
| BUG-FUNC-055 | Alta | P | Alto — middleware quebra em PHP 8.1+ | BUG-SEC-005 | plataforma |
| BUG-FUNC-056 | Alta | P | Alto — helper inexistente no Laravel moderno | BUG-SEC-005 | plataforma |
| BUG-FUNC-057 | Alta | P | Alto — 27 funções globais ausentes em produção | — | plataforma |
| BUG-MIG-003 | Alta | P | Alto — `composer install` aborta (pacote 404) | — | plataforma |

### 2.2 P1 — Funcionalidade quebrada

| ID | Sev. | Esforço | Risco se não corrigido | Dependências | Módulo |
|---|---|---|---|---|---|
| BUG-FUNC-002 | Crítica | M | Alto — rotas de `Route::resource` respondem 500 | — | novidades, logs-do-sistema, e-vacina, menus-do-site, licitacoes, agenda-de-eventos |
| BUG-DATA-003 | Alta | M | Alto — coluna e filtro perdidos na migração | BUG-MIG-001 | licitacoes |
| BUG-DATA-004 | Alta | M | Alto — categorização do acervo sem destino de schema | BUG-MIG-001 | arquivo, drive |
| BUG-DATA-005 | Alta | M | Alto — chave privada do certificado exposta | — | diario-oficial |
| BUG-DATA-006 | Alta | M | Alto — fluxo de geração do Diário sem consumidor | — | diario-oficial |
| BUG-DATA-007 | Alta | M | Alto — resultado da enquete não confiável | — | enquetes |
| BUG-DATA-008 | Alta | M | Alto — voto duplicado infinito | BUG-DATA-007 | enquetes |
| BUG-DATA-009 | Alta | M | Alto — inconsistência entre enquete e resposta | BUG-DATA-007 | enquetes |
| BUG-DATA-010 | Alta | P | Alto — ordenação por data incorreta | — | formularios-dinamicos |
| BUG-DATA-011 | Alta | P | Alto — obrigatoriedade condicional inoperante | — | formularios-dinamicos |
| BUG-DATA-012 | Alta | P | Alto — validação de existência nunca exercitada | BUG-MIG-001 | obras |
| BUG-DATA-013 | Alta | M | Alto — filtro de notícias examina 1 item do lote | — | noticias |
| BUG-DATA-014 | Alta | M | Alto — categoria errada exibida ao cidadão | — | noticias, orgaos |
| BUG-DATA-015 | Alta | P | Alto — duplicação silenciosa de registro | BUG-DATA-012 | obras |
| BUG-FUNC-013 | Alta | M | Alto — 500 em 5 módulos para slug inexistente | — | acesso-rapido, agenda-de-eventos, comite-de-investimentos, atas-e-pontos, publicacoes |
| BUG-FUNC-014 | Alta | M | Alto — rascunho publicado por engano | — | publicacoes, atas-e-pontos, comite-de-investimentos, glossario |
| BUG-FUNC-015 | Alta | M | Alto — rota de detalhe serve conteúdo de outro módulo | — | atas-e-pontos, comite-de-investimentos |
| BUG-FUNC-016 | Alta | M | Alto — links gerados apontam para o contexto errado | — | paginas-estaticas, transparencia-fiscal, a-instituicao |
| BUG-FUNC-017 | Alta | P | Alto — 500 em rota do portal | — | a-instituicao |
| BUG-FUNC-018 | Alta | P | Alto — URL errada divulgada ao público | — | a-instituicao |
| BUG-FUNC-019 | Alta | M | Alto — portal inteiro cai em manutenção sem aviso | — | plataforma |
| BUG-FUNC-020 | Alta | M | Alto — operador recebe confirmação sem gravar | — | agenda-de-eventos |
| BUG-FUNC-021 | Alta | P | Alto — 500 na listagem pública de eventos | — | agenda-de-eventos |
| BUG-FUNC-022 | Alta | P | Alto — 3º super banner sobrescreve o 2º | — | banners |
| BUG-FUNC-023 | Alta | P | Alto — arquivo gravado e lido em caminhos diferentes | — | banners |
| BUG-FUNC-024 | Alta | P | Alto — erro fatal no update | — | e-vacina |
| BUG-FUNC-025 | Alta | P | Alto — exclusão em lote reporta sucesso sem apagar | — | feriados-municipais |
| BUG-FUNC-026 | Alta | P | Alto — objeto `null` devolvido ao chamador | — | enquetes |
| BUG-FUNC-027 | Alta | P | Alto — 500 ao excluir id inválido | BUG-MIG-001 | obras |
| BUG-FUNC-028 | Alta | P | Alto — exclusão sem justificativa | BUG-MIG-001 | obras |
| BUG-FUNC-029 | Alta | P | Alto — 500 em `/cms/licitacao/{id}` | — | licitacoes |
| BUG-FUNC-030 | Alta | P | Alto — filtro exibido e ignorado | — | licitacoes |
| BUG-FUNC-031 | Alta | M | Alto — rota principal do módulo retorna 500 | — | licitacoes-antigas |
| BUG-FUNC-032 | Alta | P | Alto — proteção anti-spam inativa | — | ouvidoria |
| BUG-FUNC-033 | Alta | P | Alto — manifestação gravada na modality errada | — | ouvidoria |
| BUG-FUNC-034 | Alta | M | Alto — dados pessoais acessíveis por chute de protocolo | — | ouvidoria |
| BUG-FUNC-035 | Alta | P | Alto — HTML de outro módulo na resposta AJAX | — | comite-de-investimentos |
| BUG-FUNC-036 | Alta | P | Alto — 500 para slug inexistente | BUG-FUNC-013 | publicacoes |
| BUG-FUNC-037 | Alta | P | Alto — filtros da API descartados | — | orgaos |
| BUG-FUNC-038 | Alta | P | Alto — view devolve linhas erradas | — | atas-e-pontos-de-frequencia |
| BUG-FUNC-039 | Alta | M | Alto — escrita irrestrita no manual | — | manual-do-sistema |
| BUG-FUNC-040 | Alta | P | Crítico — menu do portal alterável por anônimo | BUG-SEC-003 | menus-do-site |
| BUG-FUNC-041 | Alta | M | Alto — 500 no glossário em 2 templates | — | glossario |
| BUG-FUNC-042 | Alta | M | Alto — módulo inoperante sem subcategorias com pai 1 | — | noticias |
| BUG-FUNC-043 | Alta | P | Alto — conteúdo desativado publicado | — | perguntas-frequentes |
| BUG-FUNC-044 | Alta | P | Alto — pauta não publicada aparece | — | pauta-do-dia |
| BUG-FUNC-045 | Alta | M | Alto — aplicação não sobe sem `config.json` | — | configuracoes-da-instituicao |
| BUG-FUNC-046 | Alta | G | Alto — dois módulos sobre a mesma tela | — | configuracoes-da-instituicao, outras-configuracoes |
| BUG-FUNC-047 | Alta | P | Alto — sidebar do CMS sem menu | — | plataforma (CMS) |
| BUG-FUNC-048 | Alta | P | Alto — relação invertida no menu | — | menus-do-site |
| BUG-FUNC-049 | Alta | P | Alto — soft delete inoperante em itens de menu | — | menus-do-site |
| BUG-FUNC-050 | Alta | M | Alto — módulo desabilitado por slug duplicado | — | logs-do-sistema, diario-oficial |
| BUG-FUNC-051 | Alta | P | Alto — módulo não encontrado por slug | — | destaques |
| BUG-FUNC-052 | Alta | M | Alto — módulos inacessíveis pelo menu | — | destaques, lgpd, comite-de-investimentos |
| BUG-FUNC-053 | Alta | P | Alto — status só muda após `cache:clear` | — | plataforma (CMS) |
| BUG-FUNC-054 | Alta | P | Alto — campo `key` não mass-assignable | — | tema e cores / layouts |
| BUG-FUNC-058 | Alta | P | Médio — policy placeholder | — | plataforma |
| BUG-FUNC-059 | Alta | P | Alto — exceção anexada à resposta | BUG-SEC-013 | plataforma |
| BUG-FUNC-060 | Alta | P | Alto — POST sem CSRF desloga o operador | — | plataforma |
| BUG-FUNC-061 | Alta | P | Alto — módulo inacessível sem seeder opcional | — | manual-do-sistema |
| BUG-FUNC-062 | Alta | P | Alto — módulo só operável por `super-admin` | — | novidades |
| BUG-FUNC-063 | Alta | P | Médio — data inválida vira data de hoje | — | novidades |
| BUG-FUNC-064 | Alta | M | Alto — ordenação inoperante no CMS | — | redes-sociais |
| BUG-FUNC-065 | Alta | P | Alto — módulo de logs inalcançável pelo menu | BUG-FUNC-050 | logs-do-sistema |
| BUG-FUNC-066 | Alta | P | Alto — 6 rotas respondem 500 | — | logs-do-sistema |
| BUG-FUNC-067 | Alta | P | Crítico — escrita de categorias sem login | BUG-SEC-003 | mais-conteudos |
| BUG-FUNC-068 | Alta | P | Alto — exclusão em lote apaga a tabela errada | — | newsletters |
| BUG-FUNC-069 | Alta | P | Alto — 500 em `/cms/novidades/{id}` | BUG-FUNC-002 | novidades |
| BUG-FUNC-070 | Alta | P | Alto — segredos no log de atividades | BUG-SEC-011 | configuracoes-da-instituicao |
| BUG-FUNC-071 | Alta | P | Alto — JS travado em "enviando" | — | agenda-de-eventos |
| BUG-FUNC-072 | Alta | P | Alto — ação sem rota | — | configuracoes-da-instituicao |
| BUG-FUNC-098 | Média | P | Alto — `dd()` em produção | BUG-SEC-013 | multiplos |
| BUG-FUNC-099 | Média | P | Médio — erros engolidos sem registro | — | multiplos |
| BUG-SEC-011 | Alta | P | Alto — credencial em log e query string | BUG-SEC-006 | gemini, configuracoes-da-instituicao |
| BUG-SEC-012 | Alta | P | Alto — stack trace ao cliente | BUG-SEC-013 | gemini, plataforma |
| BUG-SEC-014 | Alta | P | Alto — erro interno na tela do operador | — | estagiarios, configuracoes-da-instituicao |
| BUG-SEC-019 | Alta | M | Alto — dado de saúde em log e planilha | — | fila-espera-sus |
| BUG-SEC-020 | Alta | M | Alto — `..` no nome do arquivo | BUG-SEC-021 | arquivo, drive |
| BUG-PERF-001 | Alta | G | Alto — portal cai por volume de dados | BUG-MIG-001 | multiplos |
| BUG-PERF-002 | Alta | M | Alto — risco de indisponibilidade do portal de legislação | — | legislacao |
| BUG-PERF-003 | Alta | M | Médio — 4+ queries por submit de configuração | — | configuracoes-da-instituicao |
| BUG-PERF-004 | Alta | M | Alto — 5 queries por página e erro fatal sem `cor_1` | — | plataforma (portal) |
| BUG-UX-001 | Alta | G | Alto — editor de layout só funciona em 1 de 6 modelos | — | temas-e-cores / layouts |
| BUG-UX-002 | Alta | P | Alto — 500 na home do portal | — | avisos |
| BUG-UX-003 | Alta | P | Alto — menu leva o cidadão à página errada | — | acesso-rapido |
| BUG-UX-004 | Alta | P | Alto — botões visíveis só para `super-admin` | — | redes-sociais |
| BUG-DATA-021 | Alta | P | Alto — `InformationsRequest::answers()` aponta para coluna inexistente (`answ | — | transparencia-fiscal |
| BUG-DATA-022 | Alta | P | Alto — `amount` nunca preenchida e `description` nunca persistida — colunas ó | — | viap |
| BUG-FUNC-101 | Alta | P | Alto — `RoleController@update` zera as permissões do perfil ao salvar sem mar | — | usuarios |
| BUG-FUNC-102 | Alta | M | Alto — Resposta do e-SIC injetada no HTML sem escape — XSS armazenado | — | transparencia-fiscal |
| BUG-FUNC-103 | Alta | P | Alto — `TransparencyController@show` acessa `$transparencia->title` sem prote | — | transparencia-fiscal |
| BUG-FUNC-104 | Alta | P | Alto — 9 rotas declaradas com apenas 3 nomes distintos (4 e 5 duplicações) | — | transparente-fiscal |
| BUG-FUNC-105 | Alta | P | Alto — `down()` da migration derruba a tabela errada (`tv_camara` vs `tv_cama | — | tv-camara |
| BUG-FUNC-106 | Alta | M | Alto — Botão de exclusão em lote usa slug inexistente `tv-camaras.delete` | — | tv-camara |
| BUG-FUNC-107 | Alta | P | Alto — `sync()` de mandatos insere no pivot sem `role` — coluna `NOT NULL` | — | vereadores |
| BUG-FUNC-108 | Alta | P | Alto — `update` não valida com `CityCouncilorRequest` | — | vereadores |
| BUG-FUNC-109 | Alta | M | Alto — Botão de excluir vereador controlado por `agenda.delete` (permissão de | — | vereadores |
| BUG-FUNC-110 | Alta | P | Alto — Regra de unicidade da atualização aponta para tabela/coluna erradas | — | unidade-gestora |
| BUG-FUNC-111 | Alta | P | Alto — ID cru do YouTube gravado como `/YbJOTdZBX1g` — o player não funciona | — | transmissoes |
| BUG-FUNC-112 | Alta | P | Alto — Toggle de status não desativa as demais transmissões (`order` = NULL) | — | transmissoes |
| BUG-FUNC-113 | Alta | M | Alto — Exclusão em lote não funciona — o JS envia `toDelete`, o controller lê | — | terceirizados |
| BUG-FUNC-114 | Alta | P | Alto — 404 na página pública quando o layout ativo não é `modelo1..modelo6` | — | terceiros |
| BUG-FUNC-115 | Alta | P | Alto — `->first()->value` sem guarda em views e controller — falha fatal no p | — | temas-e-cores |
| BUG-FUNC-116 | Alta | P | Alto — `layout` só é validado quando é o primeiro campo enviado no POST | — | temas-e-cores |

### 2.3 P2 — Dívida técnica e risco de migração

| ID | Sev. | Esforço | Risco se não corrigido | Dependências | Módulo |
|---|---|---|---|---|---|
| BUG-MIG-004 | Alta | M | Alto — SQL não portável e sem prepared statement | — | licitacoes, propostas |
| BUG-MIG-005 | Alta | M | Alto — ordenação frágil e específica do PostgreSQL | — | licitacoes |
| BUG-MIG-006 | Alta | M | Alto — views listam outro módulo se o id mudar | — | multiplos (75 views SQL) |
| BUG-MIG-007 | Alta | M | Alto — coluna reservada exige aspas em todo SQL | — | multiplos |
| BUG-SEC-010 | Alta | P | Alto — proteção de SQL frágil e inconsistente | BUG-SEC-001, BUG-SEC-002 | multiplos |
| BUG-SEC-022 | Média | P | Médio — *prompt injection* na rota pública | BUG-SEC-007 | gemini |
| BUG-SEC-023 | Média | P | Médio — enumeração de colunas por endpoint público | BUG-SEC-008 | arquivo, drive |
| BUG-SEC-024 | Média | P | Médio — consentimento não auditável (LGPD art. 8) | — | lgpd |
| BUG-SEC-025 | Média | P | Médio — PDF sem `nosniff`/`Content-Disposition` | — | carta-de-servicos |
| BUG-DATA-016 | Média | P | Médio — chaves duplicadas gravam só a primeira | — | configuracoes-da-instituicao |
| BUG-DATA-017 | Média | M | Médio — slug ambíguo quebra links públicos | — | multiplos |
| BUG-DATA-018 | Média | M | Médio — vínculo institucional sempre vazio | — | a-instituicao |
| BUG-DATA-019 | Média | P | Médio — exclusão em cascata apaga perguntas | — | formularios-dinamicos |
| BUG-DATA-020 | Média | P | Médio — configuração órfã sem vínculo | — | configuracoes-da-instituicao |
| BUG-FUNC-073 | Média | M | Médio — campos não validados em 4 módulos | — | glossario, atas-e-pontos, comite-de-investimentos |
| BUG-FUNC-074 | Média | P | Médio — `status`/`order` gravados sem validação | — | acesso-rapido, redes-sociais |
| BUG-FUNC-075 | Média | P | Médio — categoria sem nome | — | agenda-de-eventos |
| BUG-FUNC-076 | Média | P | Médio — chave gravada na categoria errada | — | configuracoes-da-instituicao |
| BUG-FUNC-077 | Média | P | Baixo — `echo` antes do redirect | — | configuracoes-da-instituicao |
| BUG-FUNC-078 | Média | P | Médio — permissão assimétrica leitura/escrita | — | configuracoes-da-instituicao, lgpd |
| BUG-FUNC-079 | Média | P | Médio — `$modulos` ausente fora do dashboard | BUG-FUNC-047 | configuracoes-da-instituicao, outras-configuracoes |
| BUG-FUNC-080 | Média | P | Baixo — composer órfão | — | configuracoes-da-instituicao |
| BUG-FUNC-081 | Média | P | Médio — `value` da configuração indexado por `row_number()` | — | configuracoes-da-instituicao |
| BUG-FUNC-082 | Média | P | Médio — ação sem rota | BUG-FUNC-072 | configuracoes-da-instituicao |
| BUG-FUNC-083 | Média | P | Médio — `limit` inerte | — | noticias |
| BUG-FUNC-084 | Média | P | Médio — `limit` aplicado ao sub-select | — | noticias |
| BUG-FUNC-085 | Média | P | Médio — modalidade nunca casa | BUG-FUNC-033 | ouvidoria |
| BUG-FUNC-086 | Média | P | Médio — validação divergente do formulário | — | ouvidoria |
| BUG-FUNC-087 | Média | P | Médio — verbetes com inicial minúscula inalcançáveis | — | glossario |
| BUG-FUNC-088 | Média | P | Médio — verbete desativado publicado | BUG-FUNC-014 | glossario |
| BUG-FUNC-089 | Média | P | Baixo — letra da URL perdida | — | glossario |
| BUG-FUNC-090 | Média | P | Médio — permissões inexistentes | — | licitacoes |
| BUG-FUNC-091 | Média | P | Médio — PDF com conteúdo de outro módulo | — | licitacoes |
| BUG-FUNC-092 | Média | P | Baixo — 200 em vez de 404 | — | licitacoes-antigas |
| BUG-FUNC-093 | Média | P | Médio — 200 com página de erro | — | paginas-estaticas |
| BUG-FUNC-094 | Média | P | Médio — vínculo notícia-órgão bloqueado | BUG-FUNC-052 | orgaos |
| BUG-FUNC-095 | Média | M | Médio — modelo de Órgão não existe | — | orgaos |
| BUG-FUNC-117 | Média | P | Médio — Listagem pública do VIAP vazia quando não há filtros | — | viap |
| BUG-FUNC-118 | Média | P | Médio — `cor_cms` não é validada contra a lista de skins | — | temas-e-cores |
| BUG-FUNC-119 | Média | M | Médio — Rotas do modelo 5 sem permissão de recurso mapeada | — | temas-e-cores |
| BUG-FUNC-120 | Média | P | Médio — Upload de `background` ignora o redimensionamento | — | temas-e-cores |
| BUG-UX-010 | Média | P | Médio — Checkboxes de `background` renderizados dentro do bloco condicional de | — | temas-e-cores |
| BUG-FUNC-096 | Média | P | Médio — ação sem rota | BUG-FUNC-072 | configuracoes-da-instituicao |
| BUG-FUNC-097 | Média | P | Médio — dois namespaces no mesmo diretório | — | plataforma |
| BUG-FUNC-100 | Média | P | Baixo — placeholder do skeleton | — | plataforma |
| BUG-PERF-005 | Média | M | Médio — 5000 linhas sem paginação | — | logs-do-sistema |
| BUG-PERF-006 | Média | M | Médio — 50 requisições `HEAD` por rolagem | — | arquivo, drive |
| BUG-PERF-007 | Média | P | Baixo — query inerte por requisição | — | comite-de-investimentos |
| BUG-PERF-008 | Média | P | Baixo — custo fixo por requisição | — | plataforma (portal) |
| BUG-PERF-009 | Média | P | Baixo — query por renderização | — | banners |
| BUG-PERF-010 | Média | P | Baixo — N+1 na reordenação | — | plataforma |
| BUG-PERF-011 | Média | P | Baixo — 2 queries por visita | — | noticias |
| BUG-PERF-012 | Média | M | Médio — função SQL impede índice | — | multiplos |
| BUG-MIG-008 | Média | M | Médio — base migrada sem seed fica incoerente | — | a-instituicao |
| BUG-MIG-009 | Média | P | Baixo — view órfã no banco | — | a-instituicao |
| BUG-MIG-010 | Média | M | Médio — slugs duplicados em 4 tabelas | — | multiplos |
| BUG-MIG-011 | Média | P | Baixo — `down()` derruba view inexistente | — | carta-de-servicos |
| BUG-MIG-012 | Média | P | Médio — duplicatas de slug permitidas | BUG-FUNC-050 | plataforma (CMS) |
| BUG-MIG-013 | Média | P | Médio — coluna `"order"` | BUG-MIG-007 | multiplos |
| BUG-MIG-014 | Média | P | Baixo — colunas mortas desde 2018 | — | arquivo, drive |

### 2.4 P3 — Qualidade, UX e limpeza

| ID | Sev. | Esforço | Risco se não corrigido | Dependências | Módulo |
|---|---|---|---|---|---|
| BUG-UX-005 | Média | P | Baixo — limite do formulário ≠ limite do backend | — | banners, avisos, comite-de-investimentos |
| BUG-UX-006 | Média | P | Baixo — link morto no rodapé | — | multiplos |
| BUG-UX-007 | Média | P | Baixo — CSS inexistente | — | carta-de-servicos |
| BUG-UX-008 | Média | P | Baixo — 404 de CSS por página | — | lgpd |
| BUG-UX-009 | Média | M | Médio — correção manual de slug a cada menu novo | — | plataforma (CMS) |

> **Cobertura:** BUG-FUNC-003 a BUG-FUNC-012 (os 8 módulos removidos na v6) estão
> rastreados no backlog pelo par **BUG-MIG-001** (P0) e pelo Sprint 5, que os trata
> como um único programa de reconstrução. Cada ID aparece em exatamente uma
> prioridade no backlog.

---

## 3. Sequenciamento sugerido (sprints)

### Sprint 0 — Contenção imediata (1–2 dias, sem mudança de código)

| Ação | Itens |
|---|---|
| Rotacionar a chave da API Gemini e remover o literal dos seeders | BUG-SEC-006, BUG-SEC-011 |
| Colocar as rotas de escrita vulneráveis atrás de autenticação por configuração de proxy/WAF, como contenção | BUG-SEC-004, BUG-SEC-008, BUG-FUNC-067 |
| Confirmar se o PostgreSQL de produção usa o superusuário `postgres` e, se sim, criar role de privilégio mínimo | BUG-SEC-001, BUG-SEC-002, BUG-SEC-017 |

### Sprint 1 — Autorização e sanitização de entrada (1 sprint, ~3 semanas)

**Objetivo:** fechar toda a superfície de escrita e de leitura aninhada antes de migrar qualquer módulo.

| Ordem | Item | Esforço |
|---|---|---|
| 1 | BUG-SEC-003 — middleware de autorização no grupo de rotas do CMS | G |
| 2 | BUG-SEC-004 — `check.logged` + Policy em todas as rotas de escrita | M |
| 3 | BUG-SEC-005 — corrigir o `array_where` do `CheckRoutePermission` | M |
| 4 | BUG-SEC-008, BUG-FUNC-067 — fechar Drive, galeria e `categoria-conteudo` | M |
| 5 | BUG-SEC-007, BUG-SEC-022 — fechar a rota pública do Gemini | P |
| 6 | BUG-SEC-001, BUG-SEC-002, BUG-SEC-010, BUG-SEC-017, BUG-SEC-018 — binding em todo SQL com input do usuário | G |
| 7 | BUG-SEC-009 — `escapeshellarg` / extensão OpenSSL | M |
| 8 | BUG-SEC-013, BUG-SEC-014, BUG-FUNC-059, BUG-FUNC-060, BUG-FUNC-098 — tratamento de erro | M |
| 9 | BUG-SEC-015, BUG-FUNC-070 — filtragem de segredos no datatable e no log de atividades | M |

> **Regra dura:** nenhum item de escrita de um módulo entra no Sprint 3+
> sem que o módulo correspondente tenha passado pelo teste de superfície
> (todas as rotas de escrita exigem 401/403 sem sessão).

### Sprint 2 — Integridade de dados (1 sprint, ~2 semanas)

| Ordem | Item | Esforço |
|---|---|---|
| 1 | BUG-DATA-001 — `OmbudsmanRequest@update` por id | M |
| 2 | BUG-DATA-002 — exclusão de anexo pelo `archive_id` | M |
| 3 | BUG-DATA-007, BUG-DATA-008, BUG-DATA-009 — integridade do voto | M |
| 4 | BUG-DATA-005, BUG-DATA-006 — certificado e fluxo de geração do Diário | M |
| 5 | BUG-FUNC-025, BUG-FUNC-026, BUG-FUNC-039 — `destroyAll`, repositório e validação | M |
| 6 | BUG-DATA-010, BUG-DATA-011, BUG-DATA-012, BUG-DATA-013, BUG-DATA-014, BUG-DATA-015 — campos, slugs e scopes | M |

### Sprint 3 — Correção funcional e rotas quebradas (2 sprints, ~5 semanas)

| Ordem | Item | Esforço |
|---|---|---|
| 1 | BUG-FUNC-002, BUG-FUNC-069, BUG-FUNC-066, BUG-FUNC-029 — rotas que respondem 500 | M |
| 2 | BUG-FUNC-013, BUG-FUNC-036, BUG-FUNC-041 — slug inexistente e templates faltantes | M |
| 3 | BUG-FUNC-014, BUG-FUNC-015, BUG-FUNC-043, BUG-FUNC-044 — filtro de publicação | M |
| 4 | BUG-FUNC-016, BUG-FUNC-017, BUG-FUNC-018 — nomes de rota | M |
| 5 | BUG-FUNC-001 — `ServiceLetterPdfService` | M |
| 6 | BUG-FUNC-020 a BUG-FUNC-024, BUG-FUNC-035, BUG-FUNC-037, BUG-FUNC-038 — falhas de módulo | G |
| 7 | BUG-FUNC-019 — validação do campo `layout` | M |
| 8 | BUG-FUNC-047 a BUG-FUNC-054, BUG-FUNC-065, BUG-FUNC-079 — registry de módulos e menus | M |

### Sprint 4 — Performance e dívida estrutural (2 sprints, ~5 semanas)

| Ordem | Item | Esforço |
|---|---|---|
| 1 | BUG-PERF-001, BUG-PERF-002 — paginação server-side | G |
| 2 | BUG-PERF-003, BUG-PERF-004, BUG-PERF-012 — N+1 e queries por renderização | M |
| 3 | BUG-MIG-004, BUG-MIG-005, BUG-MIG-006, BUG-MIG-007 — SQL portável, views e colunas reservadas | G |
| 4 | BUG-FUNC-045, BUG-FUNC-046, BUG-FUNC-057, BUG-FUNC-058, BUG-FUNC-100 — bootstrap e configuração | M |
| 5 | BUG-MIG-008 a BUG-MIG-014 — consistência de seeds, slugs e colunas mortas | M |

### Sprint 5 — Reconstrução dos 8 módulos removidos (paralelo, ~8 sprints)

Cada módulo é reconstruído a partir do dossiê da v5, que é a única especificação
funcional existente. Detalhamento por módulo em §4.

| Ordem | Módulo | Esforço | Dependências |
|---|---|---|---|
| 1 | **Relatório Estatístico da Ouvidoria** (BUG-FUNC-010) | G | BUG-DATA-001, BUG-DATA-005 |
| 2 | **Obras** (BUG-FUNC-003) | GG | BUG-SEC-017, BUG-DATA-012, BUG-DATA-015 |
| 3 | **Obras Paralisadas** (BUG-FUNC-005) | G | BUG-FUNC-003 |
| 4 | **Fila de espera SUS** (BUG-FUNC-007) | G | BUG-SEC-019 |
| 5 | **Concursos PSS** (BUG-FUNC-004) | G | BUG-PERF-001 |
| 6 | **Licitantes Sancionados** (BUG-FUNC-008) | M | BUG-DATA-003 |
| 7 | **Terceirizados** (BUG-FUNC-009) | M | — |
| 8 | **Estagiários** (BUG-FUNC-006) | M | — |
| — | **Gemini — geração de conteúdo** (BUG-FUNC-011) | M | decisão de produto + BUG-SEC-006/007 |

### Sprint 6 — Qualidade e limpeza (contínuo)

Todos os itens P3, mais: `BUG-FUNC-073` a `BUG-FUNC-097` (validação e views),
`BUG-PERF-005` a `BUG-PERF-011`, `BUG-UX-001` a `BUG-UX-009`.

---
---

A **estimativa total por módulo** está em
**`18b-ESTIMATIVAS-POR-MODULO.md`**.
