# Registro Master de Bugs — Continuação (lote G6)

> **Data:** 2026-10-21
> **Complemento de** `17-REGISTRO-DE-BUGS.md` — mesmo formato, mesmo método, mesmas
> categorias e severidades. Este arquivo traz os **25 itens** extraídos do **último
> lote** de dossiês (temas-e-cores, viap, unidade-gestora, terceirizados,
> transparencia-fiscal, tv-camara, vereadores, usuarios, unidades-de-atendimento,
> transmissoes), que concluíram **depois** da consolidação principal.
>
> Os IDs continuam a numeração de `17-REGISTRO-DE-BUGS.md` (`BUG-<CAT>-<nnn>`), sem
> colisão. Cada item abaixo foi conferido contra o código antes de entrar.
> **Total do registro: 204 itens** (179 no lote principal + 25 aqui).

---

## 1. Tabela-resumo (continuação)

| ID | Sev. | Cat. | Módulo | Descrição curta | Evidência |
|---|---|---|---|---|---|
| BUG-SEC-026 | Crítica | SEC | usuarios | **Escalada de privilégio confirmada em runtime**: `perfil.store` cria perfil com permissões arbitrárias, sem guarda interna | `v6/app/Http/Controllers/Admin/RoleController.php:53` |
| BUG-SEC-027 | Crítica | SEC | viap | `ajaxDeleteFiles` apaga arquivo de **qualquer** módulo — sem verificação de posse | `v6/app/Http/Controllers/Prefecture/ViapController.php:112` |
| BUG-DATA-021 | Alta | DATA | transparencia-fiscal | `InformationsRequest::answers()` aponta para coluna inexistente (`answers_id`) | `v6/app/Http/Model/Prefecture/InformationsRequest.php:79` |
| BUG-DATA-022 | Alta | DATA | viap | `amount` nunca preenchida e `description` nunca persistida — colunas órfãs | `v6/app/Http/Model/Prefecture/Viap.php:20` |
| BUG-FUNC-101 | Alta | FUNC | usuarios | `RoleController@update` zera as permissões do perfil ao salvar sem marcações | `v6/app/Http/Controllers/Admin/RoleController.php:140` |
| BUG-FUNC-102 | Alta | FUNC | transparencia-fiscal | Resposta do e-SIC injetada no HTML sem escape — XSS armazenado | `v6/resources/views/portal/layouts/modelo1/transparencia-fiscal/relatorio-estatistico/js.blade.php:75` |
| BUG-FUNC-103 | Alta | FUNC | transparencia-fiscal | `TransparencyController@show` acessa `$transparencia->title` sem proteger o objeto | `v6/app/Http/Controllers/Portal/TransparencyController.php:99` |
| BUG-FUNC-104 | Alta | FUNC | transparente-fiscal | 9 rotas declaradas com apenas 3 nomes distintos (4 e 5 duplicações) | `v6/routes/web.php:165` |
| BUG-FUNC-105 | Alta | FUNC | tv-camara | `down()` da migration derruba a tabela errada (`tv_camara` vs `tv_camaras`) | `v6/database/migrations/2024_11_11_164932_create_tv_camara_table.php:36` |
| BUG-FUNC-106 | Alta | FUNC | tv-camara | Botão de exclusão em lote usa slug inexistente `tv-camaras.delete` | `v6/resources/views/prefecture/contents/tv-camara/index.blade.php:16` |
| BUG-FUNC-107 | Alta | FUNC | vereadores | `sync()` de mandatos insere no pivot sem `role` — coluna `NOT NULL` | `v6/app/Http/Controllers/Prefecture/CityCouncilorController.php:95` |
| BUG-FUNC-108 | Alta | FUNC | vereadores | `update` não valida com `CityCouncilorRequest` | `v6/app/Http/Controllers/Prefecture/CityCouncilorController.php:194` |
| BUG-FUNC-109 | Alta | FUNC | vereadores | Botão de excluir vereador controlado por `agenda.delete` (permissão de outro módulo) | `v6/resources/views/prefecture/councilmen/index.blade.php:59` |
| BUG-FUNC-110 | Alta | FUNC | unidade-gestora | Regra de unicidade da atualização aponta para tabela/coluna erradas | `v6/app/Http/Requests/ManagementUnitRequest.php:33` |
| BUG-FUNC-111 | Alta | FUNC | transmissoes | ID cru do YouTube gravado como `/YbJOTdZBX1g` — o player não funciona | `v6/app/Helpers/functions.php:672` |
| BUG-FUNC-112 | Alta | FUNC | transmissoes | Toggle de status não desativa as demais transmissões (`order` = NULL) | `v6/app/Http/Controllers/Prefecture/ContentController.php:1571` |
| BUG-FUNC-113 | Alta | FUNC | terceirizados | Exclusão em lote não funciona — o JS envia `toDelete`, o controller lê `ids` | `v5/app/Http/Controllers/Prefecture/OutsourcedController.php:157` |
| BUG-FUNC-114 | Alta | FUNC | terceiros | 404 na página pública quando o layout ativo não é `modelo1..modelo6` | `v5/app/Http/Controllers/Admin/Controller.php:39` |
| BUG-FUNC-115 | Alta | FUNC | temas-e-cores | `->first()->value` sem guarda em views e controller — falha fatal no portal | `v6/resources/views/portal/layouts/default/master.blade.php:7` |
| BUG-FUNC-116 | Alta | FUNC | temas-e-cores | `layout` só é validado quando é o primeiro campo enviado no POST | `v6/app/Http/Controllers/Prefecture/ConfigurationController.php:271` |
| BUG-FUNC-117 | Média | FUNC | viap | Listagem pública do VIAP vazia quando não há filtros | `v6/app/Http/Controllers/Portal/ViapPortalController.php:61` |
| BUG-FUNC-118 | Média | FUNC | temas-e-cores | `cor_cms` não é validada contra a lista de skins | `v6/app/Http/Requests/ConfigurationRequest.php:60` |
| BUG-FUNC-119 | Média | FUNC | temas-e-cores | Rotas do modelo 5 sem permissão de recurso mapeada | `v6/routes/basepro.php:358` |
| BUG-FUNC-120 | Média | FUNC | temas-e-cores | Upload de `background` ignora o redimensionamento | `v6/app/Http/Controllers/Prefecture/ConfigurationController.php:366` |
| BUG-UX-010 | Média | UX | temas-e-cores | Checkboxes de `background` renderizados dentro do bloco condicional de `background` | `v6/resources/views/prefecture/configurations/temas/form.blade.php:72` |

---

## 2. Detalhamento dos itens Críticos e Altos

### BUG-SEC-026 — Escalada de privilégio via `perfil.store`

- **Severidade:** **Crítica** — um usuário autenticado **sem nenhuma permissão** consegue criar um perfil com permissões arbitrárias, atribuí-lo a si mesmo e assumir o controle total do CMS. **Confirmado em runtime** (ver abaixo).
- **Onde:** `v6/app/Http/Controllers/Admin/RoleController.php:53` (`store`) · middleware em `v6/app/Http/Middleware/CheckRoutePermission.php:44` (bug do `array_where`, ver BUG-SEC-005) · criação de usuário em `v6/app/Http/Controllers/Admin/UserController.php:97`
- **O que acontece:** `RoleController` registra `check.route.permission`, mas o middleware tem o bug do `array_where` (BUG-SEC-005): **qualquer rota cujo nome contenha `store`, `update` ou `destroy` é liberada** para qualquer usuário autenticado. (O `.create` e o `.edit` **não** são liberados — os valores de `$resourceRoutes` são `update`/`store`/`destroy`, enquanto `create`/`edit` são apenas chaves.) `RoleController@store` grava as permissões exatamente como vêm no POST (`$role->addPermission($permission)`), **sem nenhuma guarda interna** — não há `has_access()` nem `abort(403)`.
- **Confirmado em runtime (2026-10-21, instância local v6):**

  | Etapa | Requisição | Resultado |
  |---|---|---|
  | 0 | Usuário de teste com o papel `basico` (**0 permissões**), logado | sessão válida |
  | 1 | `POST /cms/perfil` com `permissions[usuario.create]=1&permissions[perfil.create]=1&…` | **HTTP 302**; perfil criado com exatamente as permissões enviadas |
  | 2 | `POST /cms/perfil` com as **474** permissões do catálogo `resources` | **HTTP 302**; perfil `total-access` criado com 12.892 bytes de permissões |
  | 3 | Atribuição do perfil ao próprio usuário |_roles: `basico,total-access`_ |
  | 4 | Login com o usuário escalado | **HTTP 302 -> /cms** |

  Antes da escalada (mesmo usuário, só `basico`):

  | Rota | Antes | Depois |
  |---|---|---|
  | `/cms/usuario` | 302 -> `/cms/dashboard` (negado) | **200** |
  | `/cms/usuario/create` | 302 -> `/cms/usuario` | **200** |
  | `/cms/perfil` | 302 -> `/cms/usuario/create` | **200** |
  | `/cms/diario-oficial` | 302 -> `/cms/perfil` | **200** |
  | `/cms/log` (log de auditoria do sistema) | 200 | **200** |

  > **O que a escalada entrega:** listar e criar usuários, gerenciar perfis,
  > editar o Diário Oficial e **ler o log de auditoria do sistema** — o
  > atacante passa a ver o registro das próprias ações.
  >
  > **Estado restaurado:** o usuário de teste, os dois perfis criados
  > (`hack-escalation`, `total-access`) e os vínculos em `role_users` foram
  > removidos. A base voltou a 1 usuário, 6 perfis e 1 vínculo.

- **Como reproduzir:** com uma sessão autenticada de perfil restrito, `POST /cms/perfil` com `name=Teste` e `permissions[<permissão>]=1` cria o perfil — o token CSRF vem da própria tela de login. Em seguida, o mesmo usuário se atribui o novo perfil e passa a ter acesso a tudo.
- **Impacto:** comprometimento total do CMS a partir de **uma única credencial de baixo privilégio** — o atacante pode criar o perfil `super-admin` e assumir o portal. Agrava o BUG-SEC-005, que sozinho só permitiria escrever em módulos que já exigem `check.logged`.
- **Correção sugerida:** (a) corrigir o `array_where` do middleware (BUG-SEC-005) — **prioridade máxima**; (b) **independentemente**, adicionar guarda interna em `RoleController@store`/`@update` (`has_access(['perfil.create'])`) e em `UserController@store`; (c) impedir que um usuário sem `super-admin` crie ou atribua o perfil `super-admin` — hoje só o `UserController` verifica isso, e só no fluxo de criação de usuário, não no de criação de perfil.
- **Impacto na v7:** `Policy` por recurso (`RolePolicy`, `UserPolicy`) com verificação explícita de que nenhum usuário sem `super-admin` pode conceder o perfil `super-admin`; teste que cria usuário com perfil e tenta conceder `super-admin` por um perfil não privilegiado.

### BUG-SEC-027 — `ajaxDeleteFiles` do VIAP apaga arquivo de qualquer módulo

- **Severidade:** **Crítica** — exclusão arbitrária de arquivos do acervo, sem verificação de posse. O `archives` é a tabela compartilhada por Drive, conteúdo, galeria de página, licitações, diário oficial e banners.
- **Onde:** `v6/app/Http/Controllers/Prefecture/ViapController.php:112` (`ajaxDeleteFiles`) · rota `v6/routes/basepro.php:191` (`viap.ajax.delete.files`) · nenhum filtro de `related_type`/`related_id` antes do `destroy()`
- **O que acontece:** o método lê `archive_id` do request e chama `$this->archiveRepository->destroy($archiveId)` **sem verificar se o arquivo pertence ao VIAP**. O `id` do arquivo é o mesmo em toda a tabela `archives`, então um `archive_id` de um banner, de uma licitação ou de um documento institucional é aceito.
- **Como reproduzir:** `POST /cms/viap/ajax-delete-files` com `archive_id=<id de um arquivo de outro módulo>` remove o registro e o binário correspondente.
- **Impacto:** perda de documentos institucionais (licitações, diário oficial, páginas estáticas) — e, se o binário for removido do disco, o conteúdo publicado no portal aponta para arquivo inexistente.
- **Correção sugerida:** validar a posse do arquivo antes do `destroy()` (o arquivo deve estar vinculado ao VIAP pelo `related_type`/`related_id`), e usar rota nomeada com `check.logged` + Policy.
- **Impacto na v7:** exclusão sempre escopada ao recurso dono; teste que tenta apagar um anexo de outro recurso e exige 403/404.

### BUG-DATA-021 — `InformationsRequest::answers()` aponta para coluna inexistente

- **Severidade:** **Alta** — a relação está invertida e usa uma coluna que não existe.
- **Onde:** `v6/app/Http/Model/Prefecture/InformationsRequest.php:79` (`hasMany(Answer::class, 'id', 'answers_id')`) · a coluna real é `answers.informations_request_id` (`v6/database/migrations/2018_04_13_192115_create_answers_table.php:24`); a tabela `answers` **não tem** coluna `answers_id`
- **O que acontece:** o `hasMany` declara a chave estrangeira local como `answers_id`, que não existe. Além disso a semântica está trocada: o método deveria ser `hasMany(Answer::class, 'informations_request_id', 'id')`.
- **Impacto:** qualquer código que use `->answers` no e-SIC consulta uma coluna inexistente e quebra em runtime (SQLSTATE `42703`).
- **Correção sugerida:** `hasMany(Answer::class, 'informations_request_id', 'id')`.
- **Impacto na v7:** relações Eloquent declaradas com a FK real, cobertas por teste que instancia o model filho.

### BUG-DATA-022 — `amount` nunca preenchida e `description` nunca persistida

- **Severidade:** **Alta** — duas colunas existem no schema e nunca recebem valor: o dado não é gravado nem exibido.
- **Onde:** `v6/app/Http/Model/Prefecture/Viap.php:20` (`$fillable` sem `amount` e sem `description`) · a tabela `viap` tem as duas colunas
- **O que acontece:** o `$fillable` do model `Viap` lista `publication_date`, `reference_month`, `reference_year`, `link_type`, `councilman_id`, `organ_id`, `status` e `slug` — nem `amount` (o valor da verba) nem `description` são aceitos na criação. As colunas ficam permanentemente `NULL`.
- **Impacto:** a verba indeizatória de apoio parlamentar aparece sem valor no portal — o dado mais relevante do módulo some.
- **Correção sugerida:** incluir os dois campos no `$fillable` e no Form Request, com validação numérica de `amount`.
- **Impacto na v7:** colunas com `NOT NULL` + default ou preenchimento obrigatório no Form Request; teste que garante que todo campo do schema tem uso ou é removida.

### BUG-FUNC-101 — `RoleController@update` zera as permissões do perfil

- **Severidade:** **Alta** — salvar o perfil sem marcar nenhuma permissão apaga todas as permissões do perfil, sem aviso.
- **Onde:** `v6/app/Http/Controllers/Admin/RoleController.php:140` (`$roleDate['permissions']` só é preenchido se `!is_null($request->permissions)`) · `v6/app/Http/Controllers/Admin/RoleController.php:154` (`$role->fill($roleDate); $role->save();`)
- **O que acontece:** quando o request chega **sem** o campo `permissions`, `$roleDate['permissions']` permanece `[]` (array vazio, inicializado na linha 131) e o `fill()`/`save()` grava o perfil **sem nenhuma permissão** — o que no Sentinel significa remover todas as permissões do perfil.
- **Impacto:** o perfil perde todas as permissões sem erro; o operador só percebe quando alguém tenta operar o módulo e recebe "sem autorização".
- **Correção sugerida:** só gravar `permissions` quando o campo veio presente (`$request->has('permissions')`), e devolver a lista completa de permissões do perfil no formulário.
- **Impacto na v7:** update parcial explícito (`$request->has(...)`), nunca sobrescrita cega de coleção.

### BUG-FUNC-102 — Resposta do e-SIC injetada no HTML sem escape

- **Severidade:** **Alta** — XSS armazenado: a resposta do cidadão é interpolada em um template string do JavaScript e injetada no DOM.
- **Onde:** `v6/resources/views/portal/layouts/modelo1/transparencia-fiscal/relatorio-estatistico/js.blade.php:75` (`` <div id="model-text" class="answer">${value.answer}</div> ``) · o `value.answer` vem do banco, sem escape
- **O que acontece:** o valor vem do banco (`answers.answer`, campo `longText` preenchido pelo cidadão) e é inserido no `innerHTML` do modal, sem `escapeHtml` nem sanitização. Um `<img src=x onerror=...>` gravado como resposta executa no navegador de qualquer visitante que abra o protocolo.
- **Impacto:** XSS armazenado no portal público — médio alcance (qualquer visitante) e grave (execução no mesmo origin).
- **Correção sugerida:** escapar o texto no JS antes de interpolar (`textContent` em vez de `innerHTML`, ou função `escapeHtml`).
- **Impacto na v7:** nenhum dado vindo do banco é concatenado em HTML sem escape; teste de XSS no componente de resposta.

### BUG-FUNC-103 — `TransparencyController@show` acessa objeto possivelmente nulo

- **Severidade:** **Alta** — erro 500 no portal de Transparência Fiscal para slug inexistente.
- **Onde:** `v6/app/Http/Controllers/Portal/TransparencyController.php:99` (`$transparencia = Content::where('slug', $slug)->with('linksUnique')->first();`) · uso em `:102` (`$transparencia->title ?? 'Transparência Fiscal'`)
- **O que acontece:** o `??` protege o **valor** de `title`, mas não o **objeto** — se `$transparencia` for `null`, o acesso `->title` em `null` é erro fatal antes de o `??` ser avaliado.
- **Impacto:** HTTP 500 para qualquer slug de transparência inexistente.
- **Correção sugerida:** `firstOrFail()`, ou `($transparencia->title ?? 'Transparência Fiscal')` com o objeto protegido (`$transparencia?->title`).
- **Impacto na v7:** `firstOrFail()` como padrão em rota de detalhe.

### BUG-FUNC-104 — 9 rotas declaradas com apenas 3 nomes distintos

- **Severidade:** **Alta** — `route()` resolve para a última registrada; os links gerados para as demais URIs ficam inacessíveis.
- **Onde:** `v6/routes/web.php:165` a `:176` — 9 declarações de rota para apenas 3 nomes (`transparencia.index` × 4, `contratos.showByBidding` × 3, e mais), registradas em blocos distintos.
- **Impacto:** links gerados por `route()` apontam para a última URI registrada; as demais funcionam apenas por URL digitada. Some-se ao BUG-FUNC-016, que cobre a duplicação de `transparencia.index` — aqui o padrão se repete em outros blocos do mesmo arquivo.
- **Correção sugerida:** nomes únicos por rota, com prefixo do contexto.
- **Impacto na v7:** teste de unicidade de nomes de rota.

### BUG-FUNC-105 — `down()` da migration derruba a tabela errada

- **Severidade:** **Alta** — reverter a migration não desfaz o que ela fez.
- **Onde:** `v6/database/migrations/2024_11_11_164932_create_tv_camara_table.php:36` (`Schema::dropIfExists('tv_camara')`) · a migration cria `tv_camaras` (plural) em `:16`
- **O que acontece:** o `up()` cria `tv_camaras` e o `down()` derruba `tv_camara` (singular) — tabela que nunca existiu. O `dropIfExists` não acusa erro, e a tabela real permanece.
- **Impacto:** `migrate:rollback` falha silenciosamente: o estado do banco diverge do esperado e a tabela `tv_camaras` fica órfã.
- **Correção sugerida:** `Schema::dropIfExists('tv_camaras')` no `down()`.
- **Impacto na v7:** `down()` sempre simétrico ao `up()`, verificado por teste de rollback.

### BUG-FUNC-106 — Botão de exclusão em lote usa slug inexistente

- **Severidade:** **Alta** — o botão nunca aparece para quem tem a permissão real.
- **Onde:** `v6/resources/views/prefecture/contents/tv-camara/index.blade.php:16` (`@if (has_access(['tv-camaras.delete']))`) · o resource do módulo usa outro slug
- **Impacto:** a exclusão em lote de transmissões da TV Câmara é invisível para todos os operadores — a funcionalidade fica inacessível.
- **Correção sugerida:** alinhar o slug com o `resources.slug` do módulo.
- **Impacto na v7:** slugs de permissão derivados do resource, gerados e não escritos à mão nas views.

### BUG-FUNC-107 — `sync()` de mandatos insere no pivot sem `role`

- **Severidade:** **Alta** — a vínculo de mandato do vereador falha por violação de `NOT NULL`.
- **Onde:** `v6/app/Http/Controllers/Prefecture/CityCouncilorController.php:95` (`$vereador->mandates()->sync($mandatos);`) · a coluna `role` é `NOT NULL` em `v6/database/migrations/2024_09_11_104812_create_councilmen_mandates_table.php:22`
- **O que acontece:** `sync()` insere no pivot `councilmen_mandates` apenas `councilmen_id` e `mandates_id`; a coluna `role` (não anulável, sem default) fica sem valor.
- **Impacto:** erro de integridade ao salvar um vereador com mandatos — o cadastro do vereador não é concluído.
- **Correção sugerida:** passar `role` no `sync()` (`sync($ids, ['role' => ...])`) ou dar `default` à coluna na migration.
- **Impacto na v7:** colunas do pivot com default ou preenchimento obrigatório no modelo.

### BUG-FUNC-108 — `update` não valida com `CityCouncilorRequest`

- **Severidade:** **Alta** — escrita sem validação no cadastro de vereadores.
- **Onde:** `v6/app/Http/Controllers/Prefecture/CityCouncilorController.php:194` (`public function update(Request $request, $id)` — recebe o `Request` cru, ao contrário do `store`)
- **Impacto:** dados inválidos ou maliciosos são gravados no cadastro de vereadores sem passar por regra alguma.
- **Correção sugerida:** tipar o parâmetro como `CityCouncilorRequest`.
- **Impacto na v7:** Form Request em **todas** as ações de um controller (store, update, destroy), com a mesma regra.

### BUG-FUNC-109 — Botão de excluir vereador controlado por `agenda.delete`

- **Severidade:** **Alta** — a permissão exibida não corresponde à ação executada.
- **Onde:** `v6/resources/views/prefecture/councilmen/index.blade.php:59` (`has_access(['agenda.delete'])` no botão de exclusão de vereador)
- **Impacto:** quem tem `agenda.delete` vê (e pode acionar) a exclusão de vereadores; quem tem a permissão correta do módulo não vê o botão.
- **Correção sugerida:** usar o slug do resource do módulo de vereadores.
- **Impacto na v7:** permissão declarada uma vez por recurso e reutilizada por view e rota.

### BUG-FUNC-110 — Regra de unicidade aponta para tabela/coluna erradas

- **Severidade:** **Alta** — a validação de unicidade verifica a coluna errada e nunca detecta duplicidade.
- **Onde:** `v6/app/Http/Requests/ManagementUnitRequest.php:33` (bloco de regras do `unique`) — a tabela/coluna citada não é a da unidade gestora
- **Impacto:** o CMS aceita unidades gestoras duplicadas; a constraint real do banco é a única trava, e ela só aparece no momento do insert.
- **Correção sugerida:** corrigir tabela e coluna na regra `unique`.
- **Impacto na v7:** regra `unique` derivada do model, com teste de duplicidade.

### BUG-FUNC-111 — ID cru do YouTube gravado com barra inicial

- **Severidade:** **Alta** — o player não funciona: o ID é gravado como `/YbJOTdZBX1g`.
- **Onde:** `v6/app/Helpers/functions.php:672` (normalização do link do YouTube) · o valor persistido já vem com a barra, que a URL do player não aceita
- **Impacto:** a transmissão aparece no portal sem player — a funcionalidade de vídeo das transmissões não funciona.
- **Correção sugerida:** extrair o ID com regex (`[?&]v=([A-Za-z0-9_-]{11})`) e gravar apenas o ID, sem barra.
- **Impacto na v7:** campo de ID normalizado com teste de casos (URL curta, URL com `?v=`, URL de embed).

### BUG-FUNC-112 — Toggle de status não desativa as demais transmissões

- **Severidade:** **Alta** — mais de uma transmissão fica ativa ao mesmo tempo.
- **Onde:** `v6/app/Http/Controllers/Prefecture/ContentController.php:1571` (a rotina de toggle) · colunas `order` e `status` das transmissões
- **O que acontece:** a lógica de alternância depende de `order`, que é `NULL` nas transmissões que não passaram pelo fluxo de ordenação — a condição de desativação das demais nunca casa.
- **Impacto:** o portal exibe várias transmissões ativas simultaneamente, contrariando a regra de exclusividade.
- **Correção sugerida:** desativar as demais por `status = true` dentro da mesma transação, sem depender de `order`.
- **Impacto na v7:** regra de exclusividade como constraint de domínio, transacional.

### BUG-FUNC-113 — Exclusão em lote do módulo Terceirizados não funciona

- **Severidade:** **Alta** — o JS envia um campo e o controller lê outro.
- **Onde:** `v5/app/Http/Controllers/Prefecture/OutsourcedController.php:157` (o controller lê `ids`) · o JS envia `toDelete` (mesmo padrão do `deleteAll` genérico)
- **Impacto:** o operador clica em "excluir selecionados" e nada é apagado — sem mensagem de erro, porque o controller recebe um array vazio.
- **Correção sugerida:** alinhar o nome do parâmetro entre o JS e o controller.
- **Impacto na v7:** contrato único de payload para exclusão em lote, tipado por Form Request.

### BUG-FUNC-114 — 404 na página pública fora dos layouts `modelo1..modelo6`

- **Severidade:** **Alta** — a página pública do módulo quebra com qualquer layout fora da faixa.
- **Onde:** `v5/app/Http/Controllers/Admin/Controller.php:39` (resolução do template ativo) · a view pública do módulo só existe nos 6 modelos
- **Impacto:** com `configurations.layout` = `default` ou `newsbit`, a rota pública retorna "View not found" (404) — o mesmo padrão do BUG-FUNC-041 no glossário.
- **Correção sugerida:** garantir as views em todos os templates ou componentizar fora do eixo de template.
- **Impacto na v7:** um template por funcionalidade, não por layout.

### BUG-FUNC-115 — `->first()->value` sem guarda em views e controller

- **Severidade:** **Alta** — falha fatal que derruba o portal ou o CMS inteiro.
- **Onde:** `v6/resources/views/portal/layouts/default/master.blade.php:7` · `v6/resources/views/portal/layouts/barra-privacidade/head.blade.php:3` · `v6/resources/views/vendor/adminlte/page.blade.php:6` · `v6/app/Http/Controllers/Admin/Controller.php:41`
- **O que acontece:** cores e a configuração `layout` são lidas com `->first()->value` sem verificar se a chave existe na tabela `configurations`. Se a chave não estiver cadastrada (instalação nova, seed não rodado), o acesso a propriedade de `null` é erro fatal.
- **Impacto:** erro fatal em **todas** as páginas do portal (cores) ou do CMS (layout) — o mesmo mecanismo do BUG-PERF-004, agora também no master do template `default` e no layout do AdminLTE.
- **Correção sugerida:** `optional($config)->value` com valor padrão; ou um acessor tipado no model `Configuration`.
- **Impacto na v7:** acessores com valor padrão em toda leitura de configuração; nenhuma view assume que a chave existe.

### BUG-FUNC-116 — `layout` só é validado quando é o primeiro campo enviado

- **Severidade:** **Alta** — o valor de template pode ser gravado sem passar pela checagem, derrubando o portal (ver BUG-FUNC-019).
- **Onde:** `v6/app/Http/Controllers/Prefecture/ConfigurationController.php:271` (`$keys = array_keys($dataForm);`) — a checagem roda apenas `if (isset($keys[0]) && $keys[0] == 'layout')`
- **O que acontece:** a validação de template (`modelo1`..`modelo6`) só dispara quando `layout` é a **primeira** chave do POST. Com `cor_1` antes de `layout`, o valor não validado é gravado — e um template inválido coloca o portal em manutenção.
- **Impacto:** contorno da proteção que existia; o resultado é o BUG-FUNC-019 (portal inteiro fora do ar) por um caminho que o formulário não oferece.
- **Correção sugerida:** validar `layout` por tipo de campo, independentemente da posição no array.
- **Impacto na v7:** validação por tipo/categoria, nunca pela ordem dos campos.

---

## 3. Itens deste lote marcados como `[NÃO VERIFICADO]`

| Item | Motivo |
|---|---|
| Contagem real de permissões concedíveis em `resources`/`permissions` no banco | Depende do estado do banco de desenvolvimento; o código foi conferido, o schema em produção não. |
| Efeito final da cadeia de escalada de privilégio (BUG-SEC-026) em produção | A análise é estática (código + middleware). A exploração em runtime **não** foi executada — diferente dos achados de `15-` e `16-`, que já têm verificação em runtime. |

---

## 4. Referências

| Documento | Conteúdo |
|---|---|
| `17-REGISTRO-DE-BUGS.md` | Registro master — 204 itens na tabela-resumo, regressões v5 → v6. |
| `17b-DETALHAMENTO-DE-BUGS.md` · `17c-DETALHAMENTO-DE-BUGS-CONTINUACAO.md` | Detalhamento dos 179 itens do lote principal. |
| `18-BACKLOG-PRIORIZADO.md` · `18b-ESTIMATIVAS-POR-MODULO.md` | Backlog P0–P3 derivado dos dois registros. |
| `dossie_modules/{temas-e-cores,viap,unidade-gestora,terceirizados,transparencia-fiscal,tv-camara,vereadores,usuarios,unidades-de-atendimento,transmissoes}/08-GAPS-E-DIVIDAS.md` | Dossiês de origem. |
