# Obras Paralisadas — Gaps e Dúvidas

> Módulo **existente apenas na v5**. Nenhum dos artefatos abaixo existe na
> v6.

---

## 1. Bugs e erros conhecidos na v5

| # | Severidade | Descrição | Evidência |
|---|---|---|---|
| B01 | Alta | As rotas de escrita (`store`, `update`, `destroy`, `destroy-arquivo`) **não declaram** `middleware('check.logged')`. A proteção depende exclusivamente da herança de `Prefecture\Controller`, que aplica `check.route.permission` no construtor. Remover ou trocar a classe base abriria criação/edição/exclusão **sem autenticação**. | `v5/routes/basepro.php:520-523` vs. `v5/app/Http/Controllers/Prefecture/Controller.php:22` |
| B02 | Média | Em `store()` e `update()`, o `catch (\Exception $e)` faz `flash($e->getMessage())->error()` e o fluxo **continua** para `flash('Ocorreu um erro...')->error()`, sobrescrevendo a mensagem real. O operador nunca sabe a causa. | `v5/app/Http/Controllers/Prefecture/ObraParalisadaController.php` |
| B03 | Média | `catch (\Exception $e)` não captura `Error`/`TypeError` do PHP 7 → HTTP 500 sem mensagem para o operador. | idem |
| B04 | Média | A exclusão de um anexo remove a entrada do JSON mas **não apaga o arquivo** do storage: o PDF continua acessível por `/storage/docs/<arquivo>`. | `ObraParalisadaController@destroyArquivo` |
| B05 | Média | Falha no `insert`/`update` após o upload deixa o arquivo órfão no disco. | `store()` e `update()` |
| B06 | Média | Renomear a `identificacao` recalcula o `slug` e **invalida a URL pública** já diffusionada (404). | hook `updating` em `v5/app/Http/Model/Prefecture/ObraParalisada.php` |
| B07 | Média | A busca pública não encontra termos compostos: `clean_slug()` remove o hífen do termo e o `translate()` converte o espaço da coluna em hífen. "obras publicas" não encontra "obras-publicas" e "obras-publicas" é apagado pelo `clean_slug`. | `Portal\ObrasParalisadasController@buildQuery` + `v5/app/Helpers/functions.php:780` |
| B08 | Média | A busca em `motivo_paralisacao` **não** remove acentos do texto procurado (`mb_strtolower` apenas), de modo que "paralisação" não encontra "paralisacao". | idem |
| B09 | Baixa | A listagem pública carrega **todos** os registros em memória a cada visita (`(clone $query)->get()`), mesmo sem pedir exportação, e injeta todos eles no HTML (`json_encode($allData)`). | `Portal\ObrasParalisadasController@index` |
| B10 | Baixa | `appends(request()->query())` preserva o parâmetro `type` na paginação; navegar para a página 2 com `type=csv` na URL baixa um arquivo em vez de renderizar. | `v5/resources/views/portal/components/obras-paralisadas/table.blade.php` |
| B11 | Baixa | O botão "Limpar campos" do filtro apenas zera o input, sem submeter o formulário — a lista continua filtrada até o usuário clicar em "Consultar". | `filtro.blade.php` de cada modelo |
| B12 | Baixa | O botão de envio da tela de **editar** usa a tradução `adminlte::adminlte.register` ("Registrar"), não "Salvar"/"Atualizar". | `v5/resources/views/prefecture/obras-paralisadas/edit.blade.php` |
| B13 | Baixa | A variável `$title` enviada à view do portal não é usada: o texto "Obras Paralisadas" está hardcoded no Blade. | `index.blade.php` de cada modelo |
| B14 | Baixa | A tabela pública gera um `<tbody>` por linha (o `<tbody>` está dentro do `@foreach`), o que é inválido semanticamente. | `v5/resources/views/portal/components/obras-paralisadas/table.blade.php` |
| B15 | Baixa | O `FileTrait::fileExistsInPath()` usa o helper `file_exist()` com caminho **relativo** (`storage/docs/...`), que não existe a partir do `public/` no servidor web → a proteção contra nome de arquivo repetido praticamente nunca atua. | `v5/app/Http/Traits/FileTrait.php:84-87` |
| B16 | Baixa | Na ficha pública, quando o anexo tem descrição, o **nome do arquivo some** da tela (a descrição o substitui). | `show.blade.php` de cada modelo |
| B17 | Baixa | A coluna `slug` é nullable e não tem índice único; um registro com `identificacao` vazia pode ficar com slug vazio e gerar a URL `/obra-paralisada`. | migration e banco |

## 2. Funcionalidades incompletas ou mortas

| # | Item | Situação |
|---|---|---|
| M01 | **Ausência de workflow** | Não há status/situação (paralisada, em andamento, concluída), data efetiva de início da paralisação, valor da obra, prazo legal, responsável jurídico ou histórico de alterações. O módulo é declarativo. |
| M02 | **Ausência de autoria** | Nenhuma coluna `created_by`/`updated_by`; `responsavel` é texto livre, não um usuário do CMS. |
| M03 | **Ausência de auditoria** | O controller **não** chama `activity()`, ao contrário de `Admin\RoleController` e `Admin\PermissionController`. Nenhuma operação fica registrada no log de atividades. |
| M04 | **Sem ordenação de anexos** | Não há reordenação (a v5 tem `ArchiveController@defaultOrder`/`putOrder`, mas apenas para a tabela `archives`, que este módulo não usa). A ordem é a de inserção. |
| M05 | **Sem visão de "voltar a:active"** | Sem restauração de registros excluídos, apesar de o `DatatableController` calcular a permissão `obra-paralisada.restore`. |
| M06 | **Sem integração com o módulo "Obras"** | Não é possível vincular uma obra paralisada a um registro de `works`; as duas coisas não compartilham identificador. |
| M07 | **Sem feed / notificação** | A publicação não gera aviso em e-mail, redes sociais ou API aberta. |
| M08 | **Sem teste automatizado na v5** | Não há suíte para este módulo. |
| M09 | **Base de dados vazia** | `SELECT count(*) FROM obras_paralisadas` retorna **0** na base `prefeituras_v5`. O código está publicado, mas o recurso nunca foi alimentado naquele ambiente. |
| M10 | **Views do portal duplicadas 6 vezes** | Manutenção exige replicar alterações em `modelo1` a `modelo6`. |
| M11 | **Layout `default` incompatível** | `portal.layouts.default` não tem `home/index` nem `obras/paralisadas`; com `layout = default` o `getTemplateActived()` faz `abort(404)` e ainda liga `pagina_em_manutencao`. |
| M12 | **JSON de anexos com formato duplo** | O código aceita o formato array-de-objetos e o formato string simples, sugerindo uma transição de formato nunca migrada. |

## 3. Riscos de dados

| # | Risco | Impacto | Mitigação |
|---|---|---|---|
| D01 | Tabela `obras_paralisadas` **não existe** na v6 | Não há dado a migrar | Recriar a tabela do zero na v7. |
| D02 | Sem `modulos` na v5 e sem recurso `obras-paralisadas` em nenhuma das versões | Não há como referenciar o módulo em menus/permissões da v7 sem criar o recurso | Criar o recurso e as permissões `index/create/edit/delete`. |
| D03 | Coluna `text` com JSON de anexos | Ilegível por indexação e sem FK | Converter para tabela de anexos ou coluna `json` com accessor. |
| D04 | `previsao_reinicio` como `varchar(255)` | Data sem tipo; comparações e ordenação por data incorretas (`2026-1-2` vs `2026-10-2`) | Converter para `date` com validação de formato. |
| D05 | Slug mutável e sem índice único | Links públicos quebram; risco (baixo) de colisão | Congelar o slug e adicionar índice único. |
| D06 | Arquivos órfãos no storage | Vazamento de documento e consumo de disco | Apagar o arquivo ao remover o anexo; job de limpeza. |
| D07 | Sem `created_by` | Impossibilidade de auditar a publicação | Adicionar autoria e log de atividades. |

## 4. Perguntas em aberto para o negócio

1. A listagem de obras paralisadas deve ser **vinculada** ao cadastro de obras
   (`works`), que existe no módulo "Obras"? Hoje são dois mundos isolados.
2. "Previsão de Reinício" é uma **data real** ou um texto livre ("2º semestre
   de 2026")? A v5 usa `input type="date"`, o que não permite texto.
3. "Responsável" é sempre uma pessoa ou pode ser uma empresa/secretaria? O
   campo é texto livre — precisa de lista de seleção?
4. A exclusão de um anexo deve remover o arquivo do storage? (Recomendação:
   sim.)
5. Faz falta um **controle de fluxo** (paralisada → em andamento → concluída)
   ou o registro apenas sai da lista pública quando a obra é concluída?
6. Deve haver **prazos de carência** (ex.: a obra só entra no portal 30 dias
   após a paralização)?
7. O módulo precisa de **relatório/indicador** (quantidade de obras paralisadas
   por secretaria, prazo médio de retomada)?
8. Quem pode publicar? A permissão atual é herdada do recurso `obras`, o que
   não diferencia obras de obras paralisadas.
9. É necessário algum **controle de acesso do cidadão** (somente officials do
   município) ou a listagem deve ser pública? Hoje é pública e irrestrita.

## 5. Mapa v5 → v6

| Camada | Artefato na v5 | Situação na v6 |
|---|---|---|
| Model | `v5/app/Http/Model/Prefecture/ObraParalisada.php` | **ausente** |
| Controller CMS | `v5/app/Http/Controllers/Prefecture/ObraParalisadaController.php` | **ausente** |
| Controller portal | `v5/app/Http/Controllers/Portal/ObrasParalisadasController.php` | **ausente** |
| Form Request | `v5/app/Http/Requests/ObraParalisadaRequest.php` | **ausente** |
| Migration | `v5/database/migrations/2026_05_26_000003_create_obras_paralisadas_table.php` | **ausente** |
| Rotas CMS | `v5/routes/basepro.php:516-523` (7 rotas `obra-paralisada.*`) | **ausentes** |
| Rota do DataTable | `v5/routes/basepro.php:474` (`datatable.obra-paralisada`) | **ausente** |
| Rotas do portal | `v5/routes/web.php:210-212` (`obras-paralisadas.index`, `obras-paralisadas.show`) | **ausentes** |
| Views CMS | `v5/resources/views/prefecture/obras-paralisadas/` (4 arquivos) | **ausentes** |
| Views do portal | 18 arquivos em `portal/layouts/modelo1..modelo6/obras/paralisadas/` | **ausentes** |
| Componente de listagem | `v5/resources/views/portal/components/obras-paralisadas/table.blade.php` | **ausente** |
| JS do DataTable | `v5/public/assets/js/custom/config/obras-paralisadas/datatable.js` | **ausente** |
| JS do PDF | `v5/public/assets/js/modulos/jspdf/gerar-pdf-obras-paralisadas.js` | **ausente** |
| Breadcrumbs | `v5/routes/breadcrumbs.php:237-246` | **ausentes** |
| Menu do CMS | `v5/app/Providers/MenuServiceProvider.php:365` | **ausente** |
| Permissão | herdada do recurso `resources.id = 13` (`obras`) | o recurso `obras` **também não existe** na v6 |
| Tabela | `obras_paralisadas` (0 linhas) | **não existe** |
| Dependência de tabela | nenhuma (`archives` não é usada) | — |

Verificação: `grep -rn "ObraParalisada\|obras_paralisadas\|obras-paralisadas\|obras-paralisada" v6/` **não retorna nenhuma ocorrência**; a listagem de tabelas do banco da v6 não contém `obras_paralisadas` nem `works`.

---

## Regressão v5 -> v6

A v6 **removeu integralmente** o módulo Obras Paralisadas. Não há uma versão
reduzida, degradada ou renomeada: cada camada da funcionalidade desapareceu.

### O que foi perdido

| Dimensão | Detalhe |
|---|---|
| **Funcionalidade** | O cidadão deixa de ter qualquer canal para saber quais obras da prefeitura estão paralisadas, por que estão e quando voltam. Não existe página de listagem, nem ficha individual, nem busca, nem exportação. |
| **Publicação de arquivos** | some a possibilidade de anexar PDFs (parecer técnico, contrato, notificação) a uma obra paralisada e de disponibilizá-los para download. |
| **Rotas (7 no CMS + 1 de DataTable + 2 no portal = 10)** | `obra-paralisada.index`, `.create`, `.edit`, `.update`, `.store`, `.destroy`, `.destroy-arquivo`, `datatable.obra-paralisada`, `obras-paralisadas.index`, `obras-paralisadas.show` — **todas ausentes** na v6. |
| **Código** | model, request, os dois controllers, a migration, 22 arquivos Blade (4 no CMS, 18 no portal), o componente de listagem, 2 arquivos JS, os 2 registros de breadcrumb e o item de menu. |
| **Permissões** | Não existe recurso `obras-paralisadas` nem na v5 nem na v6. Na v5 as permissões vinham por *alias* do recurso `obras` (`resources.id = 13`); na v6 **o próprio recurso `obras` desapareceu** da tabela `resources`, de modo que não há nem o progenitor do qual herdar. |
| **Dados** | A tabela `obras_paralisadas` não é criada na v6 (nem existe no banco da v6). Na v5 ela já estava **vazia** (0 linhas), então a perda de dados é nula — mas também significa que o módulo nunca teve conteúdo real para migrar. |
| **Integração com o módulo "Obras"** | O item de menu "Obras Paralisadas" some do submenu "Obras"; o próprio módulo "Obras" (`works`) também não existe na v6 (`grep -rln "obras" v6/app v6/resources/views v6/routes` não retorna nada, e as tabelas `works`/`work_categories`/`work_statuses`/`work_archives` não existem no banco da v6). |
| **Recurso de menu e resource** | `v6/app/Providers/MenuServiceProvider.php` (equivalente) não tem o item; a v6 usa a tabela `modulos` (criada por `v6/database/migrations/2024_11_01_150206_create_modulos_table.php`), que **não existe** na v5 — logo, a v6 não tem onde registrar este módulo sem uma nova entrada. |

### Como a v6 substituiu (ou não substituiu)

**Não substituiu.** A v6 não tem nenhum módulo equivalente para obras
paralisadas. As alternativas mais próximas — Diários Oficiais, Licitações,
Transparência Fiscal — tratam de objetos de naturezas diferentes e não
publicam o status de obras.

### Consequências práticas para a reconstrução

1. **Não há código para portar.** A v7 precisa ser construída do zero a
   partir da especificação deste dossiê, usando a v5 apenas como referência de
   comportamento observável (que, aliás, tem defeitos a corrigir — ver seção 1).
2. **Não há dado para migrar.** O `INSERT` inicial de conteúdo precisa ser
   produzido pelo negócio, ou o módulo nasce vazio — exatamente como na v5.
3. **As permissões precisam ser criadas.** O recurso `obras-paralisadas` e as
   permissões `index/create/edit/delete` não existem em nenhuma das versões.
4. **O menu precisa ser reinserido.** Na v6 o menu é estruturado por
   `modulos`/`menu_orders`/`resources.modulo_id`, estrutura que não existe na
   v5 — a reinstate exige criar o módulo no catálogo, não apenas um item de
   menu.
5. **O PDF no navegador e a exportação no servidor foram perdidos junto.**
   Nenhuma das quatro exportações (xls, csv, txt, pdf) existe na v6.
6. **O bug de rotas desprotegidas não deve ser reproduzido.** A v6 elimina
   as rotas do módulo; a v7 deve reintroduzi-las já com `auth` + `can:`
   explícitos, e não repetir o padrão de `check.logged` opcional herdado do
   controller base.

### Itens que a v6 **ganhou** (e que a v7 deve absorver)

Embora o módulo não exista na v6, a plataforma da v6 traz estruturas que a
reconstrução deve adotar:

| Item na v6 | Por que importa aqui |
|---|---|
| Tabela `modulos` (`v6/database/migrations/2024_11_01_150206_create_modulos_table.php`) com `resources.modulo_id` e `menu_orders.modulo_id` | Permite registrar "Obras Paralisadas" como módulo próprio, com permissões dedicadas — eliminando o *alias* de permissões por prefixo de slug. |
| Ausência da coluna `arquivo` JSON em favor de estrutura tabular | Orienta a decisão M2/D03: tabela de anexos dedicada. |
| Padrão de Resources/Controllers namespaces `App\Http\Controllers\{Prefecture,Portal,Admin}` | Define onde o código novo deve ficar na v7. |
