# Páginas Estáticas — Modelagem de Dados

## 1. Tabela `static_pages`

Criada em `v6/database/migrations/2018_03_30_195519_create_static_pages_table.php`.
Estado atual conferido com `\d static_pages` no container
`v6_6f22e1bd-postgres-1` (banco `prefeituras_v5`).

| Coluna | Tipo | Null | Default | Origem / observação |
|---|---|---|---|---|
| `id` | `integer` | não | `static_pages_id_seq` | PK |
| `key` | `varchar(191)` | sim | — | reservado; não é usado pelo código do módulo |
| `title` | `varchar(191)` | sim | — | título exibido no portal e no breadcrumb |
| `text` | `text` | sim | — | HTML (Summernote) |
| `access` | `varchar(191)` | sim | — | não referenciado no código do módulo |
| `status_create` | `boolean` | sim | — | `true` = página de sistema (protegida contra exclusão) |
| `galery` | `boolean` | sim | — | habilita a galeria de imagens |
| `slug` | `varchar(191)` | sim | — | **URL da página na raiz do domínio** |
| `clicks` | `integer` | sim | — | contador de visitas (incrementado no `staticShow`) |
| `deleted_at` | `timestamp(0)` | sim | — | `SoftDeletes` |
| `created_at` / `updated_at` | `timestamp(0)` | sim | — | — |
| `layout` | `integer` | **não** | `1` | `1` = com barra lateral, `2` = sem; `2019_08_16_120659_add_layout_static_pages_table.php` |
| `is_external` | `boolean` | **não** | `false` | `2023_09_08_093924_add_is_external_to_static_pages_table.php`; redireciona para `links.link` |

### Sobre a coluna `is_external` — divergência migration/schema

A migração que a cria é:

```php
// v6/database/migrations/2023_09_08_093924_add_is_external_to_static_pages_table.php
public function up()
{
    Schema::table('static_pages', function (Blueprint $table) {
        $table->boolean('is_external')->default(false)->after('layout');
    });
}
```

Verificações realizadas:

| Verificação | Resultado |
|---|---|
| `\d static_pages` no banco `prefeituras_v5` (container v6) | A coluna **existe**: `is_external boolean not null default false` |
| `\d static_pages` no banco `prefeituras_v5` (container v5) | A coluna **existe** com o mesmo tipo e default |
| Coluna em `StaticPage::$fillable` | Sim (`v6/app/Http/Model/Prefecture/StaticPage.php:18-28`) |
| Coluna usada na escrita | Sim — `StaticPageController::update` faz `$request->merge(['is_external' => $request->has('is_external') ? true : false])` (`v6/app/Http/Controllers/Prefecture/StaticPageController.php:290-292`) |
| Coluna usada na leitura | Sim — `PortalController::staticShow` testa `$content->is_external == true` (`v6/app/Http/Controllers/Portal/PortalController.php:289`) |
| Formulário do CMS | Sim — checkbox "Redirecionar para Link Externo" (`v6/resources/views/prefecture/static-pages/form.blade.php:73-79`) |

**Conclusão:** a coluna **existe** no schema e no banco de ambas as versões
e é efetivamente usada pelo código. As divergências reais encontradas são:

1. `->after('layout')` é um modificador **do MySQL**; no PostgreSQL ele é
   ignorado pelo Blueprint (a posição da coluna é determinada pelo
   `ALTER TABLE ... ADD COLUMN`, que a coloca ao final). O resultado
   observado no banco (`is_external` por último) confirma isso.
2. A migração declara `boolean` **nullable** (sem `->nullable(false)`), mas o
   Postgres aplicou `NOT NULL DEFAULT false` (comportamento do Laravel 5.5
   para colunas booleanas com default). Não há divergência entre o código e
   o banco.
3. `StaticPageController::store` **não** faz `merge` de `is_external`
   (ao contrário de `update`); o valor só é persistido na criação porque o
   `StaticPageRepository` passa o Request inteiro ao `updateOrCreate()` e
   `is_external` está no `$fillable`. Isso é frágil: se o `$fillable`
   mudar, a criação perde o campo.

## 2. Tabela `archives` (parcial)

| Coluna | Uso neste módulo |
|---|---|
| `static_pages_id` | FK -> `static_pages.id` |
| `contents_id` | NULL (o arquivo é da página, não de um conteúdo) |
| `name` / `path` | Galeria: `storage/statics/{slug}/galeria/{nome}`; anexos: `storage/content/paginas-estaticas/{id}/arquivos/{nome}` |
| `highlight` | NULL na galeria (`where('highlight', null)`) |
| `view_pdf` | Marca o PDF exibido inline |

## 3. Tabela `links`

| Coluna | Uso neste módulo |
|---|---|
| `static_pages_id` | FK -> `static_pages.id` |
| `link` | URL externa (quando `is_external`) ou vídeo (YouTube/Vimeo) |
| `isBlank` | Abre em nova aba |

## 4. Tabela `menu_items`

| Coluna | Uso |
|---|---|
| `static_pages_id` | FK -> `static_pages.id` (`v6/app/Http/Model/Prefecture/MenuItem.php:60`) |
| `contents_id` | Alternativa para conteúdos (`contents`) |

Ao excluir uma página estática, os `menu_items` vinculados são removidos
(`StaticPageController::destroy`).

## 5. Relacionamentos Eloquent

| Método | Modelo | Tipo | Implementação |
|---|---|---|---|
| `menusItems()` | `StaticPage` | belongsTo | `belongsTo(MenuItem::class, 'static_pages_id', 'id')` |
| `linksUnique()` | `StaticPage` | hasOne | `hasOne(Link::class, 'static_pages_id', 'id')` |
| `archives()` | `Archive` | hasMany (implícito por `static_pages_id`) | — |
| `staticPage()` | `MenuItem` | hasOne | `hasOne(StaticPage::class, 'id', 'static_pages_id')` |

> O modelo `StaticPage` tem as relações `archives()` e `links()` **comentadas**
> (`v6/app/Http/Model/Prefecture/StaticPage.php:30-38`) — não há
> `hasMany(Archive)` declarado.

## 6. View SQL `paginas_estaticas`

| Item | Valor |
|---|---|
| Arquivo atual | `v6/database/migrations/2024_10_10_120559_update_view_static_pages.php` |
| Definição no banco | `pg_get_viewdef('paginas_estaticas'::regclass, true)` |

```sql
CREATE VIEW public.paginas_estaticas AS
SELECT row_number() OVER (ORDER BY sp.created_at DESC) AS value,
    sp.title AS titulo,
    sp.slug AS slug,
    sp.id
FROM static_pages sp
WHERE sp.deleted_at IS NULL
ORDER BY sp.created_at DESC;
```

| Observação | Detalhe |
|---|---|
| Filtra soft delete | `sp.deleted_at IS NULL` |
| **Não expõe `galery`** | A versão intermediária (`2024_05_28_153428_update_view_paginas_estaticas.php`) expunha `sp.galery AS galeria`; a versão atual removeu a coluna |
| Não expõe `status_create` | A datatable do CMS não distingue páginas de sistema |
| Não expõe `layout` / `is_external` | — |

Histórico da view:

| Migration | Efeito |
|---|---|
| `2023_05_30_094155_create_view_static_pages.php` | Versão inicial: `value`, `titulo`, `id` |
| `2024_05_28_153428_update_view_paginas_estaticas.php` | Acrescenta `sp.galery AS galeria` |
| `2024_10_10_120559_update_view_static_pages.php` | Versão atual: `value`, `titulo`, `slug`, `id` (sem `galery`) |

**Consequência verificada:** o JavaScript do CMS
(`v6/public/assets/js/custom/contents/paginas-estaticas/datatable.js`) chama
`createGaleryButton(\`pagina-estatica/${data.id}/edit#galeria\`, data.galery,
data.edit)`. Como `data.galery` não existe mais na view, `createGaleryButton`
(`v6/public/assets/js/custom/utilities/table.js:310-318`) recebe `undefined`
e **desabilita o botão** (`disabled = 'true'`, `href = '#'`). O botão de
galeria da listagem de páginas estáticas está permanentemente inoperante.

## 7. Migrations

| Migration | Efeito |
|---|---|
| `v6/database/migrations/2018_03_30_195519_create_static_pages_table.php` | Cria `static_pages` |
| `v6/database/migrations/2019_08_16_120659_add_layout_static_pages_table.php` | Acrescenta `layout` (default 1) |
| `v6/database/migrations/2023_05_30_094155_create_view_static_pages.php` | Cria a view `paginas_estaticas` |
| `v6/database/migrations/2023_09_08_093924_add_is_external_to_static_pages_table.php` | Acrescenta `is_external` |
| `v6/database/migrations/2024_05_28_153428_update_view_paginas_estaticas.php` | View com `galeria` |
| `v6/database/migrations/2024_10_10_120559_update_view_static_pages.php` | View atual (sem `galeria`) |
| `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:192-196` | `modulos` `paginas-estaticas` (id 28) |

## 8. Seeds

| Seed | Efeito |
|---|---|
| `v6/database/seeds/StaticPagesTableSeeder.php` | Cria as páginas de sistema: `contato`, `ouvidoria`, `solicitar-informacao` e outras, todas com `status_create = true` |
| `v6/database/seeds/RestoreDefaultStaticPagesSeeder.php` | Restaura o texto de `solicitar-informacao` (com placeholders `xxx` do texto original) |
| `v6/database/seeds/ResourcesTableSeeder.php:270-277` | `Resource` `pagina-estatica` -> `modulo_id = 28` |
| `v6/database/seeds/ArchivesTableSeeder.php` | Anexos de demonstração |

Trecho do seed de páginas de sistema:

```php
DB::table('static_pages')->insert([
    'title' => 'Contato',
    'slug' => 'contato',
    'text' => '<p>Utilize o formulário abaixo como um canal aberto ...</p>',
    'status_create' => true,
    'created_at' => date("Y-m-d H:i:s")]);
```

## 9. Regras de integridade

| Regra | Onde | Efeito |
|---|---|---|
| FK `archives.static_pages_id` | migration 2018-04-02 | Anexo órfão é impossível |
| FK `links.static_pages_id` | migration 2018-04-02 | Idem |
| FK `menu_items.static_pages_id` | migration de `menu_items` | Idem |
| Slug único | apenas na aplicação | `StaticPageRepository` desambigua com `-<dmyHis>` |
| Slug não pode colidir com `category_contents.slug` | `StaticPageRepository::structureUpInsert` | Verificado explicitamente |
| `status_create = 1` bloqueia a exclusão | `StaticPageController::destroy` e `deleteByLote` | Páginas de sistema são preservadas |
