# Acesso Rápido — Gaps, Bugs e Dividas

## 1. Bugs confirmados no código

| # | Bug | Evidência | Severidade |
|---|---|---|---|
| B1 | **Erro fatal (500) em slug inexistente.** O controller usa `$contents->id` antes de verificar se `$contents` é nulo. | `v6/app/Http/Controllers/Portal/QuickAccessController.php:47-53` | Alta |
| B2 | A view `admin.errors.conteudo-nao-encontrado` é **inalcançável** nesse fluxo (o `return` de erro vem depois do acesso a `null`). | mesmo arquivo, linha 54-56 | Média |
| B3 | **`Route::any` em rotas de leitura** — POST/PUT/DELETE executam a mesma ação e incrementam `static_pages.clicks`. | `v6/routes/web.php:90,94` | Média |
| B4 | **Layout `newsbit` hardcoded** para a tela de solicitação de informação, divergindo do layout ativo. | `v6/app/Http/Controllers/Portal/QuickAccessController.php:63` | Média |
| B5 | **Views ausentes em `modelo3`/`modelo4`**: `solicitar-informacao.blade.php`, `solicitacao-form.blade.php` e `files-list.blade.php` não existem nesses layouts. | `v6/resources/views/portal/layouts/modelo3/informacoes-instituicao/acesso-rapido/` e `v6/resources/views/portal/layouts/modelo4/informacoes-instituicao/acesso-rapido/` | Alta (quebra a rota) |
| B6 | **`modelo5` não inclui a view** `portal.layouts.modelo5.home.news.sidebar.acesso-rapido` em lugar nenhum; o bloco depende do "modelo personalizável", registrado com `status = 0`. | `v6/database/migrations/2026_05_19_104500_sync_acesso_rapido_modelo_5.php:36-44` | Média |
| B7 | **`struct_views()` chamada com 4 argumentos** numa função que aceita 2. | `v6/app/Http/Controllers/Prefecture/DatatableController.php:237` vs `:504` | Baixa (código morto) |
| B8 | **Slug duplicado em `static_pages`**: duas linhas com `manual-de-navegacao` (ids 6 e 8). A `id 6` é sempre a retornada por `->first()` e tem `clicks` nulo, enquanto a `id 8` é a que acumula cliques. | consulta em `prefeituras_v5`; `v6/app/Http/Traits/GetInformationsPrefectureTrait.php:60-63` | Média (dado) |
| B9 | **`status` e `order` não são validados** pelo `ContentRequest`; um POST sem `status` grava `null` e o item **desaparece do portal** sem aviso. | `v6/app/Http/Requests/ContentRequest.php:193-202` | Média |
| B10 | **Regra inválida** `"isBlank" => ""` no `ContentRequest` (string vazia não é uma regra). | mesmo arquivo, linha 199 | Baixa |
| B11 | **Seed não idempotente** — `AcessoRapidoSeeder` usa `insert`/`insertGetId`; rodar duas vezes duplica categoria, contents e links. | `v6/database/seeds/AcessoRapidoSeeder.php` | Média |
| B12 | **View composer global**: `$acessos` é calculado em **todas** as requisições do portal. | `v6/app/Providers/ConfigHeaderServiceProvider.php:86` | Baixa (performance) |
| B13 | **`contents.text` renderizado com `{!! !!}`** — HTML cru do Summernote sem sanitização. | Blades do portal (ex.: `perguntas-frequentes.blade.php`) | Média (XSS) |
| B14 | **Links relativos no JS do CMS** (`'editar/acesso-rapido/' + data.id`) — funcionam apenas porque a listagem está em `/cms/conteudos/acesso-rapido`. | `v6/public/assets/js/custom/contents/acesso-rapido/datatable.js` | Baixa |
| B15 | **`newsbit` não possui `home/index`**, logo não pode ser layout ativo (`getTemplateActived()` aborta 404). | `v6/resources/views/portal/layouts/newsbit/` | Baixa |
| B16 | **Divergência de destino do atalho "Ouvidoria"**: o seed aponta para `/pagina/contato`, mas a rota `/acesso-rapido/ouvidoria` redireciona para o e-SIC. | `v6/database/seeds/AcessoRapidoSeeder.php` vs `QuickAccessController.php:31-33` | Baixa (comportamento) |
| B17 | **Rota de reordenação compartilhada e mal nomeada** (`ajust.banners`) — reordena qualquer `contents`. | `v6/routes/basepro.php:137` | Baixa |
| B18 | **Destinos trocados no menu "Acesso Rápido"** (`menus.id = 3`): "Manual de Navegação" aponta para a página estática 5 ("Relatório Estatístico"), "Solicitar Informação" para a 2 ("Ouvidoria") e "Acompanhe sua solicitação" para a 3 ("Solicitar Informação"). | `v6/database/seeds/MenuItemsTableSeeder.php:1045-1077` + `v6/app/Http/Presenters/MenuItemPresenter.php:15-19` | Alta |
| B19 | **`$menuRapido` injetado e não usado** em `Portal\PortalController` (propriedade atribuída, nunca lida). | `v6/app/Http/Controllers/Portal/PortalController.php:45,48,52` | Baixa (código morto) |
| B20 | **Duas estruturas homônimas e independentes** chamadas "acesso rápido" no portal: o menu de atalhos (`$menuRapido`, `menu_items` do menu 3) e os cards da home (`$acessos`, `contents` da categoria `acesso-rapido`). | `v6/app/Providers/MenuServiceProvider.php:438` e `v6/app/Providers/ConfigHeaderServiceProvider.php:86` | Média (confusão de escopo) |
| B21 | **Slugs duplicados em `static_pages`** (item B8) agravados por B18: o `static_pages_id = 4` ("acompanhe-sua-solicitacao") tem tratamento especial no presenter (`url($slug)` sem o prefixo `acesso-rapido/`), mas **nenhum item do menu** o referencia. | `v6/app/Http/Presenters/MenuItemPresenter.php:16-18` | Média |

## 2. Funcionalidades incompletas ou mortas

| Item | Situação | Observação |
|---|---|---|
| `v5/database/seeds/MenuAcessoRapidoSeeder.php` | **Classe morta na v5** (arquivo inteiro comentado) e **removido na v6**. | Ver seção 4. |
| `v6/resources/views/portal/layouts/modelo5/home/news/sidebar/acesso-rapido.blade.php` | View **órfã**: o composer injeta `$acessos` nela, mas nenhum Blade a inclui. | O bloco do modelo5 depende do "modelo personalizável" (`layouts.key = 'acesso-rapido'`, `status = 0`). |
| Estrutura A no modelo5 | **Não existe** barra "Acesso Rápido" no modelo5 (ao contrário de modelo1/2/6). | O modelo5 não renderiza `$menuRapido` em lugar nenhum, embora o composer o injete em `portal.layouts.modelo5.*`. |
| `contents.slug` dos atalhos | Sempre `null` — o módulo não usa slug por item. | Não é "morto", mas é campo não utilizado pelo módulo. |
| Permissões `acesso-rapido.inactive` / `.show` | Declaradas no seed de papéis (`v6/database/seeds/RolesTableSeeder.php:110`) mas sem uso no código do módulo. | Ruído herdado do modelo genérico de permissões. |
| `acesso_rapido` no papel `administrador` | Todas as flags `acesso-rapido.*` são `false` no seed do papel `administrador`. | O módulo fica restrito ao `super-admin` em instalações com o seed padrão. |
| `link` no `form.blade.php` do CMS | Campo `link` é `required` no `ContentRequest`, mas o `form` usa `$content->linksUnique['link']` — se o `content` não tiver `linksUnique`, o Blade lança erro de índice. | Verificar em criação de item sem link prévio. |

## 3. Itens da v5 que foram removidos na v6

| Item v5 | Situação na v6 | Impacto |
|---|---|---|
| `v5/database/seeds/MenuAcessoRapidoSeeder.php` | **Arquivo removido.** | Nenhum: o arquivo já estava 100% comentado (classe morta) na v5. |
| Inserção de `resources` dentro do `AcessoRapidoSeeder` | **Removida.** | Nenhum: a v6 popula `resources` via `v6/database/seeds/ResourcesTableSeeder.php:603-609`, com `modulo_id = 49`. |

### 3.1 Itens da v5 que **continuam** na v6

- As 3 migrations da view SQL `acesso_rapido` — **byte-idênticas** entre `v5/` e `v6/`.
- `v5/database/seeds/AcessoRapidoSeeder.php` — igual, exceto o bloco de `resources`.
- As rotas `/acesso-rapido/{slug}` e `/acessos-rapido/{slug}` — **mesmas URIs e mesmos nomes**.
- `v6/database/migrations/2023_04_11_101345_create_view_to_unidade_gestora.php` — idêntica (ver `../unidade-gestora/`).

## 4. Mapa v5 -> v6

| Item | v5 | v6 | Observação |
|---|---|---|---|
| Controller do portal | `v5/app/Http/Controllers/Portal/QuickAccessController.php`, método `getIndex($slug1)` | `v6/app/Http/Controllers/Portal/QuickAccessController.php`, método `index($slug1)` | Renomeado; rotas apontam para `index` na v6. |
| Diretório das views do portal | `informacoes-prefeitura/acesso-rapido/` | `informacoes-instituicao/acesso-rapido/` | Renomeação global do portal. |
| View do layout `newsbit` | `portal.layouts.newsbit.informacoes-prefeitura.acesso-rapido.solicitar-informacao` | `portal.layouts.newsbit.informacoes-instituicao.acesso-rapido.solicitar-informacao` | Acompanha a renomeação. |
| Fallback de conteúdo vazio | `if (!$contents) return view("admin.errors.conteudo-nao-encontrado");` | `if (!count($contents)) return $this->getIndexStatic($slug1);` | Mudança de comportamento: passa a servir página estática. |
| Redirect de "ouvidoria" | inexistente | `redirect()->to(url('/acessos-rapido/solicitar-informacao'))` | Novo. |
| Prefixo das views | concatenado a cada `view('portal.layouts.'.$this->getTemplateActived().'.informacoes-prefeitura.acesso-rapido.'.$slug1)` | propriedade `$this->view` montada no construtor | Refatoração interna. |
| Rotas do portal | `v5/routes/web.php:80-86` | `v6/routes/web.php:89-95` | Mesmas URIs/nomes; linhas deslocadas. |
| Rotas do CMS | `v5/routes/basepro.php:139,167,415,441` | `v6/routes/basepro.php:150,181,407,430` | Mesmas URIs/nomes. |
| Migrations da view | `v5/database/migrations/2023_04_10_153741_create_view_to_acesso_rapido.php`, `v5/database/migrations/2023_06_15_101623_update_view_acesso_rapido.php`, `v5/database/migrations/2024_01_08_103853_update_view_acesso_rapido_2.php` | `v6/database/migrations/2023_04_10_153741_create_view_to_acesso_rapido.php`, `v6/database/migrations/2023_06_15_101623_update_view_acesso_rapido.php`, `v6/database/migrations/2024_01_08_103853_update_view_acesso_rapido_2.php` | Byte-idênticas. |
| Seed | `v5/database/seeds/AcessoRapidoSeeder.php` (insere `resources`) | `v6/database/seeds/AcessoRapidoSeeder.php` (sem `resources`) | Bloco de `resources` removido. |
| Seed de menu | `v5/database/seeds/MenuAcessoRapidoSeeder.php` (100% comentado) | **removido** | Código morto. |
| Registro em `modulos` | não existia a tabela `modulos` na v5 | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` (id 49) | Novo registro de módulo. |
| `resources` | sem `modulo_id` | `v6/database/seeds/ResourcesTableSeeder.php:603` com `modulo_id = 49` | Novo vínculo recurso -> módulo. |

### 4.1 Verificação do `MenuAcessoRapidoSeeder`

Comandos executados:

```bash
ls v6/database/seeds/ | grep -i "acesso"
# AcessoRapidoSeeder.php          (MenuAcessoRapidoSeeder.php NÃO existe na v6)

grep -rn "MenuAcessoRapido" v6/ v5/
# v5/database/seeds/MenuAcessoRapidoSeeder.php:6://class MenuAcessoRapidoSeeder extends Seeder
```

Conteúdo integral do arquivo da v5 (`v5/database/seeds/MenuAcessoRapidoSeeder.php`):
**todas as 90 linhas estão comentadas** com `//` — a classe `MenuAcessoRapidoSeeder`
nunca foi executável. O que ele faria (comentado): criar um `menus` com
`slug = 'acesso-rapido'`, criar 5 `menu_items` (Perguntas Frequentes, Manual de
Navegação, Solicitar Informação, Acompanhe sua Solicitação, Transparência Fiscal)
e um `links` "Convênios" com `link = '#'`.

Conclusão: **a remoção na v6 não perdeu funcionalidade**; o seed já era inoperante
na v5. O equivalente funcional existe em dois lugares:

- `v6/database/seeds/MenusTableSeeder.php:27-32` cria o `menus` com
  `slug = 'acesso-rapido'` (id 3 na base);
- `v6/database/seeds/MenuItemsTableSeeder.php:1033-1089` cria os **mesmos 5
  `menu_items`** (com `name` + `second_name`, `icon`, `type` e `order`), com os
  `static_pages_id` trocados (bug B18).

E o `AcessoRapidoSeeder` cuida da outra metade (categoria + `contents` + `links`).

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

| Risco | Detalhe | Mitigação |
|---|---|---|
| Slug duplicado | `static_pages` tem 2 linhas com `manual-de-navegacao` | Definir a linha canônica (id 8, que tem `clicks`) e migrar `archives`/`links` antes de apagar a id 6. |
| `links` 1-N na prática | O model assume `hasOne`, mas o schema permite N links por `contents_id` | Definir a política (mais recente) e impor `UNIQUE (contents_id)` na tabela nova. |
| `contents` compartilhado | A categoria `acesso-rapido` (id 45) é genérica; a de perguntas frequentes é a id 12 | Backfill com filtro por `category_contents.slug`, nunca por id fixo. |
| `contents.order` reutilizado | `order` é usado por vários módulos de `contents` | Ao extrair, copiar o valor para `position` e zerar o `order` legado apenas se a categoria for migrada por completo. |
| `modulos.status` cacheado | `Cache::rememberForever('modulos')` | Invalidado por `Cache::pull('modulos')` no `ModulosController@update` — OK. |
| `service_letters.menu_acesso_rapido` | Coluna com valores `'cidadao'`/outros, **não** relacionada ao slug do módulo | Não migrar; é classificação do tipo de atendimento, não do módulo. |

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

1. O atalho "Ouvidoria" deve levar ao **e-SIC** (`/acessos-rapido/solicitar-informacao`),
   à página de contato (`/pagina/contato`, como está no seed) ou à Ouvidoria
   propriamente dita (`/ouvidoria`)? Hoje há dois destinos conflitantes.
2. O prefixo plural `acessos-rapido` deve ser mantido? Ele existe só por causa do
   fallback histórico de páginas estáticas.
3. As páginas "Solicitar Informação" e "Acompanhe sua Solicitação" devem ser
   gerenciadas como **conteúdo** (hoje são `static_pages` com arquivos) ou como
   módulos próprios (e-SIC e Ouvidoria já são módulos)?
4. O bloco da home deve aparecer em todos os layouts? Hoje o modelo5 depende do
   "modelo personalizável" e está desativado (`status = 0`).
5. Qual o limite de 25/50 caracteres para título e descrição? Éherança do formulário
   genérico ou decisão de design do card?
6. O módulo deve ter uma URL de listagem própria no CMS (`/cms/acesso-rapido`) em
   vez do genérico `/cms/conteudos/acesso-rapido`?

## 7. Dívidas técnicas resumidas

| Dívida | Esforço | Prioridade |
|---|---|---|
| Corrigir o bug B1 (checar `$contents` antes de usar) | pequeno | alta |
| Restringir as rotas a `GET` | pequeno | média |
| Unificar as telas em componentes Blade (eliminar 5-7 cópias por layout) | grande | média |
| Mover a tela do CMS para um CRUD próprio (hoje depende de `contents`) | médio | média |
| Tornar o `AcessoRapidoSeeder` idempotente | pequeno | média |
| Unificar `slug` duplicado em `static_pages` | pequeno | média |
| Habilitar `acesso-rapido.*` no papel `administrador` (ou justificar) | pequeno | média |
| Sanitizar `contents.text` / migrar para texto puro | médio | média |
| Eliminar o view composer global | médio | baixa |
| Migrar para tabela `quick_links` dedicada | médio | média (preparatório para a v7) |
