# Unidade Gestora — Gaps, Bugs e Dividas

## 1. Bugs confirmados no código

| # | Bug | Evidência | Severidade |
|---|---|---|---|
| U1 | **Regra de unicidade da atualização aponta para a tabela/coluna erradas**: `unique:persons,cpf,{id}` em vez de `unique:management_units,name|code,{id}`. | `v6/app/Http/Requests/ManagementUnitRequest.php:33-34` | **Alta** |
| U2 | **`menuClicks('licitacao')` nas telas do módulo**: o contador de acessos de "Licitações" é incrementado e não existe `menu_orders` com slug `unidade-gestora`. | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php:63` (`index`), `:73` (`create`) | Média |
| U3 | **Grafia incorreta no log de atividade**: "Exclusão de uniade gestora". | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php:36` | Baixa |
| U4 | **View `show.blade.php` órfã** que usa `$functionality->name/description/created_at` — variáveis que o controller nunca envia. | `v6/resources/views/prefecture/management-units/show.blade.php` | Média |
| U5 | **`update()` não trata id inexistente**: `ManagementUnit::find($id)` devolve `null` e `->update()` estoura. | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php:117-121` | Média |
| U6 | **`destroy()` não trata id inexistente** (mesmo problema). | mesmo controller, linhas 141-145 | Média |
| U7 | **`implode(",", $request->toDelete)`** com `toDelete` ausente ou não-array gera `TypeError`, que **não** é capturado por `catch (Exception)` no PHP 7.2. | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php:35` | Média |
| U8 | **Autorização permissiva**: `create`, `store`, `edit`, `update` e `destroy` ficam abertas para **qualquer** usuário autenticado, porque `in_array($value, $resourceRoutes)` compara com os *valores* (`store`, `update`, `destroy`) do array de mapeamento. | `v6/app/Http/Middleware/CheckRoutePermission.php:44-52, 83-95` | **Alta** |
| U9 | **Rota `unidade-gestora.show` gerada sem método correspondente** no controller -> erro ao acessar `GET /cms/unidade-gestora/{id}`. | `v6/routes/basepro.php:181` + controller | Média |
| U10 | **`Form::open` do cadastro aponta para `unidade-gestora.index`**; funciona só porque `POST /cms/unidade-gestora` é a rota `store`. | `v6/resources/views/prefecture/management-units/create.blade.php:12` | Média |
| U11 | **Atributo `maxlength` não é emitido no HTML**: o form passa `maxlenght` e o componente `components.inputs.input` lê `maxlen`. | `v6/resources/views/prefecture/management-units/form.blade.php` vs `v6/resources/views/components/inputs/input.blade.php:47` | Baixa |
| U12 | **Relacionamentos Eloquent invertidos**: `ManagementUnit::biddings()` é `belongsTo` (1:1) e `Bidding::managementUnits()` é `hasOne` (1:1) — o correto é `hasMany`/`belongsTo`. | `v6/app/Http/Model/Prefecture/ManagementUnit.php:26-29`; `v6/app/Http/Model/Prefecture/Bidding.php:111-115` | Média |
| U13 | **Seed apaga fisicamente a tabela** (`DB::table('management_units')->delete()`), ignorando `SoftDeletes` e quebrando a FK de `biddings` se houver licitações. | `v6/database/seeds/ManagementUnitTableSeeder.php:12` | Média |
| U14 | **`->nullable(true)` na FK de `biddings` é no-op** no Laravel 5.5 (`Grammar::compileForeign` nunca lê o atributo `nullable`), deixando `management_units_id` `NOT NULL` apesar da intenção da migration. | `v6/database/migrations/2018_04_02_181804_create_biddings_table.php:36-38`; `v6/vendor/laravel/framework/src/Illuminate/Database/Schema/Grammars/Grammar.php:57-88` | Baixa |
| U15 | **`structureUpInsert()` retorna `[]`**: migrar `store`/`update` para `upInsert()` criaria registros sem `name`/`code`. | `v6/app/Repositories/Eloquent/Prefecture/ManagementUnit/ManagementUnitRepositoryDefaultImpl.php:22-25` | Média |
| U16 | **`IManagementUnitRepository` é uma interface vazia** — não declara nenhum método; a camada de repositórios é apenas decorativa. | `v6/app/Repositories/Contracts/IManagementUnitRepository.php` | Baixa |
| U17 | **Coluna `code` sem índice unique no banco** — a unicidade existe só na aplicação (e é quebrada na atualização, bug U1). | dump de `management_units` | Média |
| U18 | **Respostas de exclusão com formatos diferentes**: individual devolve `{"success": "Unidade Gestora deletada com sucesso."}` / `{"erro": "Ocorreu um erro ao tentar salvar no banco de dados."}`; em lote devolve `true` / `false` (JSON cru). O JS testa `response.success` em ambos, o que nunca é verdadeiro no fluxo em lote. | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php:143-152`; `v6/app/Repositories/Repository.php:99-110`; `v6/public/assets/js/custom/utilities/deleteAll.js` | Média |
| U19 | **Namespace do model desalinhado da pasta**: `namespace App\Prefecture;` em `app/Http/Model/Prefecture/ManagementUnit.php`. Funciona só por causa do autoload por classmap. | `v6/app/Http/Model/Prefecture/ManagementUnit.php:3`; `v6/composer.json:53-57` | Baixa |
| U20 | **Módulo desabilitado no menu do CMS** (`modulos.status = false`), embora a tela exista e o papel `administrador` tenha as permissões. A matriz de permissões do editor de perfis **não exibe** o recurso. | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:322-327`; banco; `v6/resources/views/admin/role/form.blade.php:45` | Média |
| U21 | **`$table->engine = 'InnoDB'`** numa migration de banco PostgreSQL. | `v6/database/migrations/2018_04_02_181802_create_management_units_table.php:17` | Baixa |

## 2. Funcionalidades incompletas ou mortas

| Item | Situação | Observação |
|---|---|---|
| `prefecture/management-units/show.blade.php` | **Órfã** e com variável inexistente (`$functionality`). | Copiada de um módulo de "Funcionalidade". Deveria ser removida ou reescrita. |
| Rota `unidade-gestora.show` | Gerada pelo `Route::resource`, sem método no controller. | Resolver criando o método ou removendo a rota. |
| Permissões `unidade-gestora.inactive`, `.inactivate`, `.restore`, `.show` | Declaradas no seed de papéis e no `struct_views`, mas sem uso real no módulo (não há "ativar/inativar" para unidades). | Ruído do modelo genérico de permissões. |
| `menu_orders` com slug `unidade-gestora` | **Não existe** a linha. | Consequência do bug U2: o módulo não tem contagem de acessos própria. |
| Coluna `code` na listagem do CMS | Não é exposta pela view SQL `unidade_gestora`. | O operador não vê o código sem abrir a edição. |
| `IManagementUnitRepository` | Interface sem métodos; só `getModel()` (herdado) e `destroyAll()` (herdado) são usados. | Poderia ser removida ou ampliada com contratos reais. |
| `structureUpInsert()` | Retorna `[]`. | Nunca é exercitado (o controller usa `ManagementUnit::create/update`). |
| Seed `ManagementUnitTableSeeder` | Não é idempotente no sentido seguro: apaga tudo fisicamente a cada execução. | Ver bug U13. |

## 3. Itens removidos na v6 (em relação à v5)

**Nenhum.** Todos os arquivos do módulo são byte-idênticos entre `v5/` e `v6/`.
As diferenças são de **ambiente**, não de código:

| Item | v5 | v6 |
|---|---|---|
| Tabela `modulos` | inexistente | criada por `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` (registro `id = 50`, `status = 0`) |
| `resources.modulo_id` | coluna inexistente | `v6/database/seeds/ResourcesTableSeeder.php:171-177` vincula o recurso ao módulo 50 |
| `menu_orders` | tabela inexistente | existe (45 linhas), mas **sem** linha para `unidade-gestora` |
| Permissões do papel `administrador` | — | `v6/database/seeds/RolesTableSeeder.php:62` |

## 4. Mapa v5 -> v6

| Item | v5 | v6 | Observação |
|---|---|---|---|
| Controller | `v5/app/Http/Controllers/Prefecture/ManagementUnitController.php` | `v6/app/Http/Controllers/Prefecture/ManagementUnitController.php` | **byte-idêntico** |
| Model | `v5/app/Http/Model/Prefecture/ManagementUnit.php` (`namespace App\Prefecture;`) | `v6/app/Http/Model/Prefecture/ManagementUnit.php` (`namespace App\Prefecture;`) | **byte-idêntico** — o namespace **não** mudou |
| Form Request | `v5/app/Http/Requests/ManagementUnitRequest.php` | `v6/app/Http/Requests/ManagementUnitRequest.php` | **byte-idêntico** (bug U1 nas duas) |
| Contrato do repository | `v5/app/Repositories/Contracts/IManagementUnitRepository.php` | `v6/app/Repositories/Contracts/IManagementUnitRepository.php` | **byte-idêntico** (interface vazia) |
| Implementação do repository | `v5/app/Repositories/Eloquent/Prefecture/ManagementUnit/ManagementUnitRepositoryDefaultImpl.php` | `v6/app/Repositories/Eloquent/Prefecture/ManagementUnit/ManagementUnitRepositoryDefaultImpl.php` | **byte-idêntico** |
| Migration da tabela | `v5/database/migrations/2018_04_02_181802_create_management_units_table.php` | `v6/database/migrations/2018_04_02_181802_create_management_units_table.php` | **byte-idêntica** |
| Migration da view SQL | `v5/database/migrations/2023_04_11_101345_create_view_to_unidade_gestora.php` | `v6/database/migrations/2023_04_11_101345_create_view_to_unidade_gestora.php` | **byte-idêntica** |
| Seed | `v5/database/seeds/ManagementUnitTableSeeder.php` | `v6/database/seeds/ManagementUnitTableSeeder.php` | **byte-idêntico** |
| Views do CMS | `v5/resources/views/prefecture/management-units/{index,create,edit,form,show}.blade.php` | `v6/resources/views/prefecture/management-units/{index,create,edit,form,show}.blade.php` | **byte-idênticas** (5 arquivos) |
| Rota do resource | `v5/routes/basepro.php:167` | `v6/routes/basepro.php:181` | Mesma URI (`unidade-gestora`), mesmos nomes de rota |
| Rota de exclusão em lote | `v5/routes/basepro.php:139` | `v6/routes/basepro.php:150` | Mesma URI e nome (`ajax.management-unit.deleteByLote`) |
| Rota do DataTable | `v5/routes/basepro.php:415` | `v6/routes/basepro.php:407` | Mesma URI (`/cms/datatable/unidade-gestora`) |
| Registro em `modulos` | — | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:322-327` | Novo |

> **Sobre o namespace:** a comparação entre `v5/app/Http/Model/Prefecture/` e
> `v6/app/Http/Model/Prefecture/` mostra que **o namespace `App\Prefecture` é o
> mesmo nos dois arquivos** (e idêntico ao de `Bidding`, `Content`,
> `CategoryContent`, etc.). O desalinhamento entre pasta e namespace é
> intencional no legado e resolvido pelo autoload por classmap
> (`v6/composer.json:53-57`). **Nada foi movido na v6.**

## 5. Riscos de dados (migração de schema)

| Risco | Detalhe | Mitigação |
|---|---|---|
| Duplicados de `name`/`code` | O bug U1 permite gravá-los; o banco não tem índice unique. | Rodar as queries de diagnóstico antes de criar o índice unique na v7. |
| FK `biddings.management_units_id` `NOT NULL` sem `ON DELETE` | Exclusão física da unidade com licitações é bloqueada pelo banco. | Manter soft delete; documentar que a exclusão é lógica. |
| Seed destrutivo | `ManagementUnitTableSeeder` faz `delete()` físico. | Não executar em produção; migrar para `updateOrCreate`. |
| `code` como texto livre | Sem padronização, valores divergentes entre municípios. | Migrar para tipo numérico ou tabela de referência só após mapear os valores em uso. |
| Coluna homônima em outro domínio | `emendas_parlamentares.unidade_gestora_id` -> `emendas_parlamentares_categories`. | Não unificar sem decisão do negócio. |
| View SQL `unidade_gestora` | Depende de `row_number()` e de `deleted_at IS NULL`; não expõe `code`. | Substituir por query Eloquent paginada na v7. |
| `modulos.status = false` | O módulo some da navegação e da matriz de permissões. | Definir se a v7 habilita o módulo por padrão. |

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

1. O `code` da unidade gestora tem significado padronizado (código do órgão na
   estrutura municipal) ou é apenas um rótulo interno? Precisa virar número?
2. O que acontece com as licitações quando uma unidade é excluída? O legado
   mantém a FK e apaga logicamente — a prefeitura aceita exibir o nome de uma
   unidade "excluída" nas licitações antigas?
3. O módulo deve voltar a ser habilitado (`modulos.status = true`)? Hoje está
   desabilitado desde a criação do registro do módulo.
4. O módulo deve ter uma tela de detalhe (`show`)? O `Route::resource` já
   reserva a rota, mas não há implementação.
5. A listagem deve mostrar o `code`? Hoje só o nome aparece, o que dificulta
   distinguir unidades com nomes parecidos.
6. O "Unidades Gestoras" deve ter relação com a taxonomia de unidades das Emendas
   Parlamentares (`emendas_parlamentares_categories`)? Hoje são domínios
   separados com o mesmo nome.

## 7. Dívidas técnicas resumidas

| Dívida | Esforço | Prioridade |
|---|---|---|
| Corrigir a regra de unicidade da atualização (bug U1) | pequeno | **alta** |
| Fechar a brecha de autorização `create/edit/delete` (bug U8) | médio | **alta** |
| Tratar id inexistente em `update`/`destroy` (bugs U5/U6) | pequeno | alta |
| Validar `toDelete` antes do `implode` (bug U7) | pequeno | alta |
| Corrigir `menuClicks('licitacao')` -> `unidade-gestora` + criar a linha em `menu_orders` | pequeno | média |
| Corrigir as relações Eloquent (`hasMany`/`belongsTo`) | pequeno | média |
| Adicionar índice unique parcial (name, code) após sanear duplicados | médio | média |
| Remover `show.blade.php` ou implementar `show` | pequeno | média |
| Corrigir o `Form::open` do cadastro (bug U10) | pequeno | média |
| Emitir `maxlength` no formulário (bug U11) | pequeno | média |
| Tornar o seed seguro (sem `delete()` físico) | pequeno | média |
| Preencher `IManagementUnitRepository` ou remover a interface | pequeno | baixa |
| Unificar o formato das respostas de exclusão (bug U18) | pequeno | baixa |
| Exibir `code` na listagem | pequeno | baixa |
| Trocar a view SQL por query Eloquent paginada | médio | média (pré-requisito da v7) |
