# Menus do Site — Inventario de Migrations

> Lista exaustiva das migrations da v6 que afetam `menus`, `menu_items`,
> `menu_orders` ou a view `menus_site`, com o que cada uma altera.
>
> (Migrations de `v5` citadas apenas quando foram renomeadas ou removidas na
> portagem — ver `08-GAPS-E-DIVIDAS.md` §5.5.)

---

## 1. `menus` — criacao

**Arquivo:** `v6/database/migrations/2018_04_09_194517_create_menus_table.php`
**Data:** 2018-04-09 19:45:17

```php
Schema::create('menus', function (Blueprint $table) {
    $table->engine = 'InnoDB';
    $table->increments('id');
    $table->string('name');
    $table->string('slug');
    $table->boolean('status_create')->nullable();
    $table->timestamps();
    $table->softDeletes();
});
```

| Coluna | Tipo | Null |
|---|---|---|
| `id` | `increments` (serial) | nao |
| `name` | `string` | nao |
| `slug` | `string` | nao |
| `status_create` | `boolean` | sim |
| `created_at` / `updated_at` | `timestamps` | sim |
| `deleted_at` | `softDeletes` | sim |

Observacoes:

- O `$table->engine = 'InnoDB'` e um vestigio de MySQL: o banco e PostgreSQL
  (o engine e ignorado).
- `slug` **nao** tem indice unico.
- `down()` faz `Schema::dropIfExists('menus')`.

---

## 2. `menu_items` — criacao

**Arquivo:** `v6/database/migrations/2018_04_09_194931_create_menu_items_table.php`
**Data:** 2018-04-09 19:49:31

Cria a tabela e, em um segundo `Schema::table`, as 6 chaves estrangeiras:

```php
$table->integer('menus_id')->unsigned();
$table->integer('menus_items_id')->nullable()->unsigned();
$table->integer('type')->nullable()->unsigned();
$table->integer('links_id')->unsigned()->nullable();
$table->integer('static_pages_id')->unsigned()->nullable();
$table->integer('category_contents_id')->unsigned()->nullable();
$table->integer('contents_id')->nullable();
$table->boolean('status_create')->nullable();
$table->boolean('isBlank')->nullable();
```

| FK | Coluna | Referencia | `nullable` |
|---|---|---|---|
| 1 | `menus_id` | `menus.id` | `true` (declarado, mas a coluna e `NOT NULL`) |
| 2 | `menus_items_id` | `menu_items.id` (auto-referencia) | `true` |
| 3 | `links_id` | `links.id` | `true` |
| 4 | `static_pages_id` | `static_pages.id` | `true` |
| 5 | `category_contents_id` | `category_contents.id` | `true` |
| 6 | `contents_id` | `contents.id` | (coluna ja nullable) |

Observacoes:

- `menus_id` e `NOT NULL` no banco, embora a FK seja declarada `nullable(true)`.
- `order` e `integer NOT NULL` **sem default** — origem da fragilidade com o
  `MenuItemRequest` que remove `order` do request.
- `deleted_at` e criado por `softDeletes()`, mas o model **nao** usa
  `SoftDeletes` (comentado em `v6/app/Http/Model/Prefecture/MenuItem.php:18`).

---

## 3. `menu_items` — colunas `icon` e `second_name`

**Arquivo:** `v6/database/migrations/2021_02_05_170740_add_icon_to_menu_items_table.php`
**Data:** 2021-02-05 17:07:40

```php
Schema::table('menu_items', function (Blueprint $table) {
    $table->string('icon')->after('order')->nullable();
    $table->string('second_name')->after('name')->nullable();
});
```

- `after()` e uma diretiva do MySQL; no PostgreSQL e ignorada (a ordem fisica das
  colunas difere do esquema original).
- `down()` remove as duas colunas.

---

## 4. `menu_orders` — criacao

**Arquivo:** `v6/database/migrations/2022_04_08_101047_create_menu_order_table.php`
**Data:** 2022-04-08 10:10:47

```php
Schema::create('menu_orders', function (Blueprint $table) {
    $table->increments('id');
    $table->string('slug')->nullable();
    $table->integer('clicks');
    $table->timestamps();
    $table->softDeletes();
});
```

Observacoes:

- `clicks` e `NOT NULL` **sem default** — o `MenuOrderSeeder` sempre informa
  `clicks => 0`.
- `slug` e nullable e **nao** tem indice unico (a tabela tem 45 linhas com
  slugs unicos no banco da v6, mas nada garante isso).

---

## 5. View `menus_site`

**Arquivo:** `v6/database/migrations/2023_04_13_151009_create_view_to_menus.php`
**Data:** 2023-04-13 15:10:09

```php
DB::statement("
CREATE OR REPLACE VIEW menus_site
AS SELECT row_number() OVER (ORDER BY (m.status_create is true) DESC) AS value,
    m.id,
    m.name,
    m.slug
   FROM menus m
  WHERE m.deleted_at IS NULL
  ORDER BY (m.status_create is true) DESC;
");
```

| Aspecto | Detalhe |
|---|---|
| Funcao | Numerar e ordenar os menus para o DataTable do CMS |
| Colunas expostas | `value` (row_number), `id`, `name`, `slug` |
| Filtro | `deleted_at IS NULL` |
| Ordem | `status_create IS TRUE DESC` (menus "criados" primeiro) |
| `down()` | `Drop view if exists public.menus_site` (DDL case-insensitive) |
| Consumidor | `v6/app/Http/Controllers/Prefecture/DatatableController.php:349-353` |

---

## 6. Insercao de `menu_orders` (dados)

### 6.1 Formulario dinamico e questionarios

**Arquivo:**
`v6/database/migrations/2024_04_02_000718_add_questionnaires_to_menu_order_and_resource_tables.php`
**Data:** 2024-04-02 00:07:18

Insere em `menu_orders`: `slug = 'formulario-dinamico'`, `clicks = 0`.
Insere em `resources`: `formulario-dinamico` ("Formularios Dinamicos") e
`questionarios` ("Questionarios").
O `down()` remove os tres registros.

### 6.2 Questionarios preenchidos

**Arquivo:**
`v6/database/migrations/2024_04_11_163017_add_filled_questionnaires_to_menu_order_and_resource_tables.php`
**Data:** 2024-04-11 16:30:17

Insere em `resources`: `questionarios-preenchidos` ("Questionarios Preenchidos").
Nao toca em `menu_orders` (apesar do nome da migration).

### 6.3 Newsletter

**Arquivo:**
`v6/database/migrations/2024_10_30_161709_inserting_menu_orders_newsletter.php`
**Data:** 2024-10-30 16:17:09

Insere em `menu_orders`: `slug = 'newsletter'`, `clicks = 0`.

> **Risco de dados**: essas migrations fazem `insert` **sem** `updateOrCreate` e
> **sem** `modulo_id`. Rodando duas vezes em bases diferentes, ha linhas
> duplicadas. A migration de 2026-09-01 corrige o `modulo_id` das linhas orfas,
> mas nao remove duplicidades.

---

## 7. `menu_orders.modulo_id`

**Arquivo:** `v6/database/migrations/2024_11_04_094157_add_modulo_id_to_menu_order_table.php`
**Data:** 2024-11-04 09:41:57

```php
Schema::table('menu_orders', function (Blueprint $table) {
    $table->unsignedInteger('modulo_id')->nullable();
    $table->foreign('modulo_id')
        ->nullable(true)
        ->references('id')
        ->on('modulos');
});
```

- Torna possivel ligar a linha de `menu_orders` ao modulo correspondente na
  tabela `modulos` (criada em
  `v6/database/migrations/2024_11_01_150206_create_modulos_table.php`).
- Sem essa coluna, o `MenuServiceProvider` nao consegue checar
  `$menu->modulo->status` e o modulo **nao aparece** no menu lateral do CMS.
- `down()` remove a FK (`menu_orders_modulo_id_foreign`) e a coluna.

---

## 8. `menu_items.is_active`

**Arquivo:** `v6/database/migrations/2025_06_04_160404_add_is_active_to_menus_table.php`
**Data:** 2025-06-04 16:04:04

```php
Schema::table('menu_items', function (Blueprint $table) {
    if (!Schema::hasColumn('menu_items', 'is_active')) {
        $table->boolean('is_active')->default(true)->after('status_create');
    }
});
```

| Aspecto | Detalhe |
|---|---|
| Nome enganoso | A migration se chama `add_is_active_to_**menus**_table`, mas altera **`menu_items`** |
| Efeito | `is_active boolean NOT NULL DEFAULT true` |
| Guard | `Schema::hasColumn` torna a migration idempotente |
| `after()` | Diretiva MySQL, ignorada no PostgreSQL |
| `down()` | `dropColumn('is_active')` — **nao** tem guarda; rodar o `down` duas vezes falha |

Consumidores:

- `v6/app/Providers/MenuServiceProvider.php:454-457` (menu de acesso rapido);
- `v6/resources/views/portal/layouts/modelo1/layout/nav.blade.php:116` e
  equivalentes (menu principal);
- `v6/app/Http/Controllers/Prefecture/MenuItemController.php:319-325` (toggle);
- `v6/resources/views/prefecture/menus-itens/show.blade.php` (interruptor).

> O `menus` (tabela de agrupadores) **nao** tem `is_active` — apenas
> `menu_items` tem.

---

## 9. `menu_items.is_mega_menu`

**Arquivo:** `v6/database/migrations/2026_06_02_120000_add_is_mega_menu_to_menu_items_table.php`
**Data:** 2026-06-02 12:00:00

```php
Schema::table('menu_items', function (Blueprint $table) {
    $table->boolean('is_mega_menu')->nullable()->default(false)->after('link');
});
```

| Aspecto | Detalhe |
|---|---|
| Efeito | `is_mega_menu boolean NULL DEFAULT false` |
| `after('link')` | A coluna `link` **nao existe** na v6 — a diretiva e ignorada no PostgreSQL |
| Nullable | Sim (diferente de `is_active`, que e `NOT NULL`) |
| `down()` | `dropColumn('is_mega_menu')` |

Consumidores: `v6/resources/views/prefecture/menus-itens/form.blade.php:146-147`
(checkbox), `v6/resources/views/prefecture/menus-itens/show.blade.php:196-199`
(badge), `v6/resources/views/portal/layouts/modelo1/layout/nav.blade.php:117-133`
e `v6/resources/views/portal/layouts/modelo5/layout/header/nav-header/menu-principal.blade.php:36-60`
(render do mega menu).

---

## 10. Correcao de `menu_orders.modulo_id` nulos

**Arquivo:** `v6/database/migrations/2026_09_01_100000_fix_menu_orders_missing_modulo_id.php`
**Data:** 2026-09-01 10:00:00

```php
public function up()
{
    $orfaos = DB::table('menu_orders')->whereNull('modulo_id')->get();

    foreach ($orfaos as $menuOrder) {
        $modulo = DB::table('modulos')->where('slug', $menuOrder->slug)->first();

        if ($modulo) {
            DB::table('menu_orders')
                ->where('id', $menuOrder->id)
                ->update(['modulo_id' => $modulo->id]);
        }
    }
}
```

| Aspecto | Detalhe |
|---|---|
| Problema corrigido | `menu_orders` com `modulo_id` nulo nao aparecia no menu lateral do CMS (o `MenuServiceProvider` exige `isset($menu->modulo->status)`) |
| Estrategia | Casar por **`slug`** do modulo, e nao por id fixo — os ids de `modulos` variam entre instalacoes |
| Idempotente | Sim: so atualiza linhas com `modulo_id` nulo |
| Nao reversivel | O `down()` esta vazio, com justificativa em comentario: "nao ha valor original conhecido para restaurar" |
| Limitacao | Linhas cujo slug nao casa com nenhum modulo continuam orfas (nao ha log nem alerta) |

Estado atual na base v6: nenhuma linha com `modulo_id` nulo.

---

## 11. Migrations relacionadas, fora do escopo direto

| Migration | Relacao |
|---|---|
| `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` | Cria `modulos` (destino da FK de `menu_orders.modulo_id`) |
| `v6/database/migrations/2024_11_05_104026_add_modulo_id_to_resources_table.php` | `resources.modulo_id` — o par `resources` + `menu_orders` e que define a presenca do modulo no CMS |
| `v6/database/migrations/2024_04_02_003245_create_view_listagem_questionarios.php` | Cria a view `listagem_questionarios` (usa `menu_orders` na origem) |
| `v6/database/migrations/2026_01_20_160719_create_service_letters_table.php` | Insere linhas em `menu_orders` para os modulos de carta de servicos |

---

## 12. Migrations da v5 que NAO foram portadas

| Migration v5 | Efeito | Situacao na v6 |
|---|---|---|
| `v5/database/migrations/2023_02_13_141452_create_item_menu_order.php` | Insere `menu_orders.slug = 'certificado'` | **Nao portada** — a linha existe no banco (`menu_orders.id = 26`, `modulo_id = 16`), mas nao ha migration que a crie |
| `v5/database/migrations/2023_06_29_143227_add_itens_to_menu.php` | Insere `menu_orders.slug = 'revisoes-cliente'` + `resources` | **Nao portada** |
| `v5/database/migrations/2026_05_26_113000_insert_terceirizados_into_menu_and_resources.php` | Insere entradas de "terceirizados" | **Nao portada** |
| `v5/database/migrations/2026_05_26_200002_insert_estagiario_menu_and_resource.php` | Insere "estagiario" | **Nao portada** |
| `v5/database/migrations/2026_05_27_000002_insert_concurso_pss_menu_and_resource.php` | Insere "concurso pss" | **Nao portada** |
| `v5/database/migrations/2025_06_02_114951_add_is_active_to_menus_table.php` | Adiciona `menu_items.is_active` | Renomeada para `2025_06_04_160404_add_is_active_to_menus_table.php` (conteudo identico) |

> **Impacto:** em uma instalacao nova da v6 (migrations do zero), as linhas de
> `menu_orders` para `certificado`, `revisoes-cliente`, "terceirizados",
> "estagiario" e "concurso pss" **nao serao criadas**. Os modulos correspondentes
> simplesmente nao aparecerao no menu lateral do CMS. Alem disso, a migration de
> 2026-09-01 (que preenche `modulo_id` por slug) so alcanca as linhas existentes.

---

## 13. Checklist de validacao de schema (v7)

Ao reconstruir o schema, conferir:

- [ ] `menus.slug` com indice unico.
- [ ] `menu_items.order` com default (evita o conflito com o `FormRequest` que
      remove o campo do request).
- [ ] `menu_items.menus_items_id` com `ON DELETE SET NULL` (o legado bloqueia a
      exclusao do pai na UI, mas o banco deve ser defensivo).
- [ ] `menu_items.deleted_at` de fato utilized (`SoftDeletes` no model).
- [ ] `menu_orders.slug` com indice unico.
- [ ] `menu_orders.modulo_id` NOT NULL para as linhas de modulo (o legado aceita
      nulo, mas o nulo = modulo invisivel).
- [ ] `links` orfaos limpos antes de criar a FK `links_id`.
- [ ] View `menus_site` mantida ou substituida por `MenuResource` paginado.
- [ ] Indices `(menus_id, menus_items_id, order)` em `menu_items`.
