# Órgãos — Gaps, Bugs e Dívidas

> Escopo: defeitos encontrados, funcionalidades inertes ou mortas, riscos de dados, perguntas em aberto
> e o comparativo **v5 -> v6**.

---

## 1. Bugs confirmados

### B1 — Filtro da API descartado (severidade: alta)

> Detalhamento completo da superfície de dados abertos em `09-API-E-DADOS-ABERTOS.md`.

**Onde:** `v6/app/Http/Controllers/Swagger/V1/Portal/OrgaoController.php`

```php
$contents = $this->getContent();

if($title) {
    $contents->whereRaw($this->caseInsensitiveAccentFreeSearch($title, 'title'));
}

if($description) {
    $contents->whereRaw($this->caseInsensitiveAccentFreeSearch($description, 'text'));
}

$contents = $contents->get();
```

`Illuminate\Database\Eloquent\Builder::whereRaw()` **devolve uma nova instância** e não altera a original.
Como o retorno é descartado, os filtros de `titulo` e `descricao` **nunca** são aplicados. O consumidor
recebe a lista completa de órgãos (limitada apenas por `limite`).

**Impacto:** a documentação OpenAPI anuncia dois parâmetros de filtro que não funcionam.

**Correção:** reatribuir (`$contents = $contents->whereRaw(...)`) ou usar `when()`.

**Raiz:** o mesmo padrão está em `SecretariaController`, `LegislationController`, `NewController` e
`PublicationController` (todos herdados da base `Swagger\V1\Portal\Controller`) — corrigir na base resolve
os cinco de uma vez. O arquivo `v5/app/Http/Controllers/Swagger/V1/Portal/OrgaoController.php` é
**byte a byte idêntico** ao da v6 (`diff` vazio): o bug foi herdado, não introduzido.

**Agravante de segurança:** `caseInsensitiveAccentFreeSearch()`
(`v6/app/Http/Controllers/Swagger/V1/Portal/Controller.php`) concatena o termo do usuário **diretamente**
no SQL, sem binding:

```php
return "lower(
    TRANSLATE($column,'áéíóúàèìòùãõâêîôôäëïöüçÁÉÍÓÚÀÈÌÒÙÃÕÂÊÎÔÛÄËÏÖÜÇ','aeiouaeiouaoaeiooaeioucAEIOUAEIOUAOAEIOOAEIOUC')
) like '%$toLowerChars%'";
```

Hoje o efeito é limitado porque o filtro é inoperante; **ao corrigir B1, é obrigatório trocar por binding**
(`whereRaw($sql, [$termo])`).

### B2 — `modulos.status = false` impede o vínculo notícia↔órgão (severidade: alta)

**Cadeia causal completa:**

1. `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:124-129` cria o módulo `orgaos`
   (id 17) com `'status' => 0`.
2. `v6/app/Providers/ModulosServiceProvider.php` cacheia `Cache::rememberForever('modulos', fn () =>
   Modulos::all()->pluck('status', 'slug'))` e injeta `$modulos` em
   `prefecture.contents.noticias.form`.
3. `v6/resources/views/prefecture/contents/noticias/form.blade.php:76-88` só renderiza o select "Órgãos"
   se `@if(isset($modulos['orgaos']) && $modulos['orgaos'])`.
4. No banco atual, `modulos.status` de `orgaos` é **`false`** (verificado via `psql`).
5. O `ContentController::store()` grava `orgaos_id` a partir de `$request->orgaos` — mas o campo nunca é
   enviado porque o select não existe.

**Consequência verificada:** `SELECT count(orgaos_id) FROM contents` -> **0** de 184. Nenhuma notícia está
vinculada a órgão; a página do órgão exibe "Nenhuma notícia cadastrada".

**Agravantes:**

- O mesmo `modulos.status` também controla a entrada "Órgãos" no menu lateral do CMS
  (`v6/app/Providers/MenuServiceProvider.php`), então **duas features distintas** morrem por causa de uma
  única flag.
- O cache `modulos` só é invalidado por `Cache::pull('modulos')` em `ModulosController::update`
  (`v6/app/Http/Controllers/Admin/ModulosController.php`); alterações diretas no banco não têm efeito
  imediato.

### B3 — Include do `orgaosNews` do modelo1 dentro do modelo2 (severidade: média)

`v6/resources/views/portal/layouts/modelo2/informacoes-instituicao/components/components-a-prefeitura/index.blade.php:97`

```blade
@include('portal.layouts.modelo1.layout.sidebar.orgaosNews')
```

Não existe um `orgaosNews.blade.php` em `v6/resources/views/portal/layouts/modelo2/layout/sidebar/` (confirmado por
listagem do diretório). O `modelo2` renderiza o include do `modelo1`, que traz CSS próprio
(`.flex { width: 350px; height: 100px; }`, `.img { width: 110px; height: 98px; }`) e reimplementa a
estrutura da lista — divergência visual entre layouts.

**Consequência adicional:** o `ModulosServiceProvider` registra composer para
`portal.layouts.modelo2.layout.sidebar.orgaosNews` (view inexistente) — composer morto.

**Correção:** criar o arquivo do `modelo2` (ou extrair um componente único compartilhado).

### B4 — Breadcrumb do órgão aponta para a URL errada (severidade: média)

`v6/routes/breadcrumbs.php:214-221`:

```php
Breadcrumbs::register('orgaos', function ($breadcrumbs, $content) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('A Instituição', url('/#'));
    $breadcrumbs->push('Órgãos', url('/#'));
    $breadcrumbs->push($content->title, route('a-instituicao.index', $content->slug));
});
```

O último `push` usa `a-instituicao.index` (rota `/a-instituicao/{slug}`) em vez de
`a-instituicao-orgaos.index` (`/a-instituicao/orgaos/{slug}`). O breadcrumb leva a uma URL que resolve
outro conteúdo (ou 404).

### B5 — Autorização permissiva no CRUD de conteúdo (severidade: alta, herdada)

`v6/app/Http/Middleware/CheckRoutePermission.php` retorna `true` sempre que **qualquer** segmento do nome
da rota estiver em `$openRoutes` ou em `$resourceRoutes`:

```php
$resourceRoutes = [
    'edit' => 'update',
    'create' => 'store',
    'delete' => 'destroy',
];
```

Consequência para Órgãos: `POST /cms/conteudo` (`conteudo.store`), `PUT /cms/conteudo/{id}`
(`conteudo.update`) e `DELETE /cms/conteudo/{id}` (`conteudo.destroy`) são liberados para **qualquer
usuário logado**, sem `orgaos.create`/`orgaos.edit`/`orgaos.delete`. O caso especial
`if ($access == "generic.conteudo.delete") $access = "conteudo.delete";` está **depois** do `return true`
e portanto é inalcançável.

O mesmo vale para `GET /cms/datatable/orgaos` (rota `datatable.orgaos`): `'datatable'` está em
`$openRoutes`.

**Não é específico do módulo Órgãos** — afeta todos os conteúdos — mas o módulo é exposto por ele.

### B6 — Filtro de data aplicado em memória (severidade: média, funcional)

`v6/app/Http/Controllers/Portal/PrefectureController.php:73-74`:

```php
$contentNew->orgaos = $contentNew->orgaos
    ->where("publication_date", "<=", $date);
```

O filtro roda sobre a **Coleção já materializada**, não sobre a query. Com `publication_date` NULL
(todos os 3 órgãos atuais têm NULL), o `Collection::where()` compara `null <= string` e **remove** o item
— comportamento diferente do SQL, onde `NULL <= data` também é falso, mas o `NULL` seria tratado de forma
diferente por um `whereNotNull` explícito. O ponto em si: a semântica esperada (notícias com data futura
não aparecem) só funciona por acidente de comparação do PHP.

### B7 — `getContentDataWith` devolve `null` sem tratamento (severidade: média)

`PrefectureController@getIndex` (linha 41) faz `$title = $contentNew->title;` **antes** do teste
`if (empty($contentNew) and !isset($contentNew))`. Com slug inexistente, o acesso a `->title` em `null`
dispara erro em PHP 7.2 (notice) e fatal em PHP 8.

## 2. Funcionalidades inertes ou mortas

| Item | Situação | Evidência |
|---|---|---|
| Vínculo notícia↔órgão | **Inerte** | `contents.orgaos_id` 100% NULL; select escondido por `modulos.status = false` (B2) |
| Vínculo evento↔órgão | **Inerte** | `calendar_events` com `orgaos_id` não NULL: **0** |
| Galeria de órgão | **Sem dados** | `contents.galery` = false nos 3 órgãos; 0 `archives` ligados à categoria 32 |
| Imagem de destaque | **Sem dados** | 0 `archives` com `highlight = 1` na categoria 32 |
| Composer `portal.layouts.modelo2.layout.sidebar.orgaosNews` | **Morto** | view inexistente |
| `Content::eventosOrgaos()` | **Sem uso no portal** | o portal usa a query inline `where('orgaos_id', ...)`; a relação existe mas não é chamada nesse caminho |
| `ContentRequest` `case 'a-cidade'` compartilhado com `orgaos` | **Válido** | não é bug, é reutilização de regras idênticas |
| `v5` migration `2025_05_19_165859_update_orgaos_view.php` | **Não portada** | a v6 mantém o nome `a_orgaos`; a v5 usa `orgaos` |
| View `public.orgaos` | **Não existe no banco atual** | `information_schema.views` mostra apenas `a_orgaos` |
| `pub-nav.blade.php` para Órgãos | **Não existe** | ver seção 4 |

## 3. Riscos de performance (resumo operacional)

| Cenário | Problema | Ganho estimado na v7 |
|---|---|---|
| Grade do CMS | `DB::table("a_orgaos")->get()` materializa a view inteira; o Yajra fatia em memória | Paginação server-side: de O(N) para O(pageSize) |
| Lista de notícias do órgão | `hasMany` sem `limit`, filtro em memória, `@foreach` sem paginação | `paginate(10)` no SQL |
| Formulário de notícias | `getContentByCategoryWith('orgaos', ...)` sem `limit` para popular um `<select>` | `limit` ou select2 remoto |
| API sem `limite` | Retorna todos os órgãos com `with('archives')` | Default de paginação documentado |
| API | Duas queries extras de `exists()` (`directExists`, `nestedExists`) por requisição | Cache/joins |
| Página do órgão | `$news_secretary` (query inútil) é executada em toda visita | Remover do caminho do órgão |

## 4. Ausência de view `pub-nav` para o módulo

O padrão `pub-nav` (navegação de subcategoria por área, usado como cabeçalho de seção) **não existe** para
Órgãos. Ele existe apenas em:

| Área | Caminho |
|---|---|
| Publicações (layout `default`) | `v6/resources/views/portal/layouts/default/pages/elements/pub-nav.blade.php` (componente compartilhado) |
| Atas e Pontos | `v6/resources/views/portal/layouts/modelo1/atas-e-pontos/pub-nav.blade.php` (idem para modelo2..modelo6) |
| Comitê de Investimentos | `v6/resources/views/portal/layouts/modelo1/comite-de-investimentos/pub-nav.blade.php` (idem para modelo2..modelo6) |
| Publicações | `v6/resources/views/portal/layouts/modelo2/publicacoes/pub-nav.blade.php` (idem para modelo3..modelo6) |
| Requerimentos | `v6/resources/views/portal/layouts/modelo3/requerimentos/pub-nav.blade.php` (idem para modelo4) |

**Não existe** `pub-nav` para `orgaos`, `a-instituicao`, `a-cidade`, `secretarias` nem `legislacao`.

Como os órgãos chegam ao público:

| Canal | Mecanismo |
|---|---|
| Menu principal do portal | Dropdown "Órgãos" (item agrupador `menu_items.id = 16`, `type = 0`) com os órgãos como filhos (`type = 2`) |
| Link permanente no CMS | `route('a-instituicao-orgaos.index', $content->slug)` |
| Botão "Acessar órgão" na grade | `` `/a-instituicao/orgaos/${data.slug}` `` |

Não há, porém, **página de listagem de órgãos** no portal: quem não souber a URL exata precisa navegar
pelo menu. (Comparar com `legislacao`, que tem `nav.blade.php` + `recursive-list.blade.php` próprios, e com
`secretarias`, que usa menu inline.)

## 5. Mapa v5 -> v6

### 5.1 Resumo tabular

| Aspecto | `v5` | `v6` | Impacto |
|---|---|---|---|
| **View SQL (nome)** | `public.orgaos` | `public.a_orgaos` | O `DatatableController` lê nomes diferentes: `DB::table("orgaos")` (v5, linha 287) x `DB::table("a_orgaos")` (v6, linha 259). **Uma migration aplicada no banco errado quebra a grade** |
| **Filtro `cc.category_contents_id IS NULL`** | **Presente** na view `orgaos` | **Ausente** na view `a_orgaos` | Na v5, conteúdos de subcategorias de "Órgãos" **não** aparecem na grade; na v6 aparecem |
| **Migration de renomeação** | `v5/database/migrations/2025_05_19_165859_update_orgaos_view.php` (2025-05-19) — **não existe na v6** | — | Diverge o schema entre as duas versões |
| **Coluna `slug` na view** | adicionada por `v5/database/migrations/2026_03_09_000000_update_views_to_include_slug.php` (2026-03-09) | adicionada por `v6/database/migrations/2024_11_29_093120_update_view_orgaos.php` (2024-11-29) | Mesma finalidade, caminhos e datas diferentes |
| **Model de Órgão** | **inexistente** (`Organ.php` / `Orgao.php` não existem) | **inexistente** (`Organ.php` / `Orgao.php` não existem) | Órgão = `Content` da categoria 32 nas duas versões. Verificado por busca em `v5/app` e `v6/app`: só existem `OrganizersOfCompetition` (não relacionado), `OrganizationalStructureController` (página estática) e as classes de API `Orgao*` |
| **Prefixo de rota do portal** | `/a-prefeitura/orgaos/{slug}` (`a-prefeitura-orgaos.index`) | `/a-instituicao/orgaos/{slug}` (`a-instituicao-orgaos.index`) | Rebranding "A Prefeitura" -> "A Instituição". URLs antigas precisam de 301 |
| **Diretório de views do portal** | `informacoes-prefeitura/a-prefeitura/` | `informacoes-instituicao/a-instituicao/` | Mesmo rebranding |
| **Formulário do CMS** | mostra o link fixo `url('a-prefeitura/orgaos/'.$content->slug)` | mostra `url('a-instituicao/orgaos')` + campo `slug` + `route('a-instituicao-orgaos.index', ...)` | O formulário moderno exibe o prefixo e a URL final |
| **JS da grade** | monta a URL em JS com guarda `if(data.slug)` | interpola `` `/a-instituicao/orgaos/${data.slug}` `` direto | A v6 perdeu a proteção contra `slug` vazio (link `undefined`) |
| **Grade (view `index.blade.php`)** | idêntica | idêntica | — |
| **Grade (`create.blade.php`)** | idêntica | idêntica | — |
| **API (`OrgaoController`)** | idêntica (`diff` vazio) | idêntica | Bug B1 herdado |
| **API (`OrgaoResource`, `OrgaoRequest`)** | idênticas | idênticas | — |
| **`contents.orgaos_id`** | presente (nullable, FK `contents.id`) | presente (nullable, FK `contents.id`) | Mesma semântica |
| **`calendar_events.orgaos_id`** | presente | presente | — |
| **`category_contents` id 32** | `Órgãos` / `orgaos` / `category_contents_id` NULL | idêntico | Mesma chave |
| **`modulos` id 17** | — | `slug = 'orgaos'`, `status = 0` na migration | Default desligado |
| **Menu do portal** | prefixo `a-prefeitura` no `MenuItemPresenter` | prefixo `a-instituicao` | — |

### 5.2 Diff textual dos arquivos que mudaram

```diff
--- v5/database/migrations/2025_05_19_165859_update_orgaos_view.php
+++ (equivalente ausente na v6)
-        DB::statement("DROP VIEW IF EXISTS a_orgaos");
-
-        DB::statement("
-        CREATE OR REPLACE VIEW public.orgaos AS
-            SELECT row_number() OVER (ORDER BY c.created_at DESC) AS value,
-                c.title AS titulo,
-                c.id as id,
-                c.galery as galeria
-            FROM contents c
-        JOIN category_contents cc ON cc.id = c.category_contents_id
-            WHERE c.deleted_at IS NULL AND cc.slug::text = 'orgaos'::text AND cc.category_contents_id IS NULL
-        ORDER BY c.created_at DESC;
-        ");
```

```diff
--- v5/app/Http/Controllers/Prefecture/DatatableController.php:285-289
+++ v6/app/Http/Controllers/Prefecture/DatatableController.php:258-262
     public function get_orgaos()
     {
-        $orgaos = DB::table("orgaos")->get();
+        $orgaos = DB::table("a_orgaos")->get();
         return DataTables::of($this->struct_views($orgaos, 'orgaos'))->make(true);
     }
```

```diff
--- v5/app/Http/Controllers/Portal/PrefectureController.php:75-92
+++ v6/app/Http/Controllers/Portal/PrefectureController.php:71-88
     if ($category->slug == 'orgaos') {
         ...
-        return view('portal.layouts.' . $this->getTemplateActived() . '.informacoes-prefeitura.a-prefeitura.show', [
+        return view('portal.layouts.' . $this->getTemplateActived() . '.informacoes-instituicao.a-instituicao.show', [
```

```diff
--- v5/routes/web.php:69-74
+++ v6/routes/web.php:78-83
-    Route::prefix('a-prefeitura')->group(function () {
-        Route::any('/{slug}', 'Portal\PrefectureController@getIndex')->name('a-prefeitura.index');
-        Route::any('secretarias/{slug}', 'Portal\PrefectureController@getIndex')->name('a-prefeitura-secretarias.index');
-        Route::any('orgaos/{slug}', 'Portal\PrefectureController@getIndex')->name('a-prefeitura-orgaos.index');
+    Route::prefix('a-instituicao')->group(function () {
+        Route::any('/{slug}', 'Portal\PrefectureController@getIndex')->name('a-instituicao.index');
+        Route::any('secretarias/{slug}', 'Portal\PrefectureController@getIndex')->name('a-instituicao.index');
+        Route::any('orgaos/{slug}', 'Portal\PrefectureController@getIndex')->name('a-instituicao-orgaos.index');
```

### 5.3 Itens que existem na v5 e foram removidos na v6

| Item | Situação |
|---|---|
| Migration `2025_05_19_165859_update_orgaos_view.php` (renomeia a view para `orgaos` e adiciona o filtro `category_contents_id IS NULL`) | **Ausente na v6** — a v6 manteve `a_orgaos` sem o filtro |
| Migration `2026_03_09_000000_update_views_to_include_slug.php` | Ausente na v6 (a v6 tem a sua própria: `2024_11_29_093120_update_view_orgaos.php`) |
| Filtro `cc.category_contents_id IS NULL` na view de órgãos | **Removido** (na verdade, nunca existiu na v6) |
| Guarda `if(data.slug)` na construção do link no JS | **Removida** |

### 5.4 Itens que existem na v6 e não na v5

| Item | Descrição |
|---|---|
| Migration `2024_11_29_093120_update_view_orgaos.php` | Recria `a_orgaos` com `slug` |
| Formulário do CMS com campo `slug` exibido e botão "Acessar" | Substitui o link fixo da v5 |
| `MenuItemPresenter` com o caso `categoryContent->id == 32` apontando para `a-instituicao` | Na v5 o equivalente apontava para `a-prefeitura` |

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

| Risco | Descrição | Mitigação |
|---|---|---|
| R-1 | **Nome da view**: se o ambiente for migrado da v5 para a v6 (ou vice-versa) sem recriar a view, `DB::table("a_orgaos")` / `DB::table("orgaos")` falha | Recriar explicitamente a view no plano de migração; validar com `information_schema.views` |
| R-2 | **Filtro `category_contents_id IS NULL`**: se houver subcategorias de "Órgãos" criadas na v5, o conjunto exibido muda ao migrar | Inventariar `category_contents` com `category_contents_id = 32` antes de migrar e decidir o comportamento desejado |
| R-3 | **Coluna `slug` ausente** em bancos migrados da v5 sem a migration de 2026-03-09 | Verificar `\d a_orgaos` |
| R-4 | **`contents.orgaos_id` NULL** em 100% das linhas: ao ligar `modulos.status`, o operador passa a poder preencher o vínculo, mas o histórico continua sem vínculo | Definir se haverá backfill |
| R-5 | **Links do menu**: `menu_items.contents_id` aponta para `contents.id`; se o conteúdo for recriado com outro id, o menu fica quebrado | Mapeamento de ids na migração (campo `legacy_content_id`) |
| R-6 | **Sem `UNIQUE` em `contents.slug`**: a colisão é resolvida em aplicação com `max(id)+1`, que não é atômico | Índice único único no schema moderno, com tratamento de `QueryException` |
| R-7 | **Cache `modulos`**: após alterar `modulos.status`, é preciso `Cache::pull('modulos')` (ou `php artisan cache:clear`) | Incluir no runbook |
| R-8 | **Views SQL não versionadas com o código**: `a_orgaos` só muda quando uma migration roda | Recriar views no deploy da v7 ou substituí-las por queries Eloquent |

## 7. Dívidas técnicas

| Dívida | Descrição | Esforço |
|---|---|---|
| D-1 | Sem model de Órgão — tudo depende de `category_contents_id = 32` e do `slug` | Alto (reestruturação) |
| D-2 | Views Blade duplicadas em 6 modelos, com include cruzado (B3) | Médio |
| D-3 | `MenuItemPresenter` com `id` de categoria hardcoded (7, 12, 32) | Baixo (substituir por configuração) |
| D-4 | `ContentRequest` compartilhando regras entre `orgaos` e `a-cidade` | Baixo |
| D-5 | `IContentRepository` é um contrato **vazio** e `ContentRepositoryDefaultImpl` só implementa `upInsert` | Médio |
| D-6 | `Content::scopeByStatusNoticias` e `scopeByLimit` gravam estado na **sessão** dentro de um scope | Médio |
| D-7 | Nenhum teste automatizado para o módulo | Médio |
| D-8 | `getTemplateActived()` acopla o módulo à existência de `portal.layouts.<layout>.home.index` (view de outro contexto) | Baixo |
| D-9 | Slug do conteúdo ignorado no formulário (o servidor recalcula) — UX confusa | Baixo |
| D-10 | Coluna "ID" da grade mostra `row_number()` e não o `id` real | Baixo |

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

1. **Órgãos devem ter subcategorias?** A v5 filtra `category_contents_id IS NULL` na view (só a raiz);
   a v6 não filtra. Qual é o comportamento correto?
2. **A listagem pública de órgãos deve existir?** Hoje não há página de índice; só a página individual.
3. **Qual é a ordenação oficial** dos órgãos: `created_at DESC` (view SQL), `order` (campo manual do
   `contents`) ou `title`? As três coexistem e produzem listas diferentes.
4. **A galeria de órgão deve aceitar documentos** (pdf, docx) ou apenas imagens? A validação de
   `archive[]` permite 12 extensões de documento, mas a galeria do portal filtra apenas imagens.
5. **O limite de 5 eventos** na agenda do órgão é regra de negócio ou arbitrário?
6. **Deve existir um "Órgão" sem texto** (ex.: a página de "Gabinete do Prefeito" com apenas contato)?
   Hoje o conteúdo vazio exibe "CONTEÚDO NÃO ENCONTRADO".
7. **O módulo deve continuar desligado (`modulos.status = false`)?** Se a resposta for sim, o vínculo
   notícia↔órgão deve ser exposto por outra via (ex.: um formulário próprio de notícias por órgão).
8. **Quem é o "órgão" de uma notícia de outra secretaria?** Hoje `contents.secretaria` (string, por slug) e
   `contents.orgaos_id` (int, por id) coexistem em colunas diferentes da mesma tabela — dá para vincular
   uma notícia simultaneamente a uma secretaria e a um órgão. Isso é intencional?
9. **A API deve passar a filtrar de verdade?** Se sim, há impacto em consumidores que hoje dependem do
   comportamento "sem filtro" (retorno completo).
10. **O `valor`/`row_number()` da view deve ser exposto na API?** Hoje não é.

## 9. Itens verificados como ausentes (para evitar falso positivo na reconstrução)

| Item | Verificação |
|---|---|
| `Organ.php` / `Orgao.php` em `v5/app/Http/Model/Prefecture/` | Não existe |
| `Organ.php` / `Orgao.php` em `v6/app/Http/Model/Prefecture/` | Não existe |
| Tabela `orgaos` no banco | Não existe (só a view `a_orgaos`) |
| View `public.orgaos` no banco atual | Não existe |
| `pub-nav.blade.php` para a área de órgãos | Não existe em nenhum layout |
| `v6/app/Http/Model/Prefecture/OrganizersOfCompetition.php` | Existe, mas **não tem relação** com órgãos (organizadores de concurso) |
| `v6/app/Http/Controllers/Portal/OrganizationalStructureController.php` | Existe, mas resolve uma **página estática**, não o módulo Órgãos |
