# Feriados Municipais — Modelagem de Dados

## 1. Objetos envolvidos

| Objeto | Tipo | Criado por |
|---|---|---|
| `feriados_municipais` | tabela | `v6/database/migrations/2023_02_02_094344_create_feriados_municipais_table.php` |
| `lista_feriados_municipais` | **view SQL** | `v6/database/migrations/2023_05_29_144236_create_view_lista_de_feriados_municipais.php` |
| `modulos` | tabela | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` (registro id 51) |
| `menu_orders` | tabela | módulo do CMS |
| `resources` | tabela | permissões do CMS |

## 2. `feriados_municipais` — schema real

Schema obtido do PostgreSQL 10 do ambiente v6
(`docker exec v6_6f22e1bd-postgres-1 psql -U postgres -d prefeituras_v5 -c "\d feriados_municipais"`):

| Coluna | Tipo | Collation | Nullable | Default |
|---|---|---|---|---|
| `id` | integer | — | **not null** | `nextval('feriados_municipais_id_seq'::regclass)` |
| `date` | date | — | **not null** | — |
| `icon` | character varying(191) | — | sim | — |
| `description` | text | — | **not null** | — |
| `created_at` | timestamp(0) without time zone | — | sim | — |
| `updated_at` | timestamp(0) without time zone | — | sim | — |
| `deleted_at` | timestamp(0) without time zone | — | sim | — |

Índices:

```
"feriados_municipais_pkey" PRIMARY KEY, btree (id)
```

Observações:

- **Não há índice** sobre `date` nem sobre `(date) WHERE deleted_at IS NULL`.
  Como o portal filtra por ano (`whereYear`), a consulta faz *seq scan*.
- **Não há restrição `UNIQUE`** que impeba dois feriados na mesma data.
- `icon` é `varchar(191)` **nullable** no banco, embora o Form Request exija
  `required` — a divergência só é visível se a validação for contornada.
- `description` é `text` e **não null** no banco; a regra do request é
  `required|max:200`, ou seja, o banco permite mais que o formulário.
- A coluna `icon` guarda o **nome da classe CSS** do ícone (ex.: `fab fa-500px`),
  não um identificador de catálogo — nada impede o cadastro de uma classe
  inexistente.

## 3. Migration que cria a tabela

`v6/database/migrations/2023_02_02_094344_create_feriados_municipais_table.php`:

```php
Schema::create('feriados_municipais', function (Blueprint $table) {
    $table->increments('id');
    $table->date('date');
    $table->string('icon')->nullable();
    $table->text('description');
    $table->timestamps();
    $table->softDeletes();
});
```

### 3.1 Diferença v5 → v6 nesta migration

A migration da v5 é **idêntica**, exceto por um bloco adicional no `up()` que
semeava o módulo no esquema antigo (`resources`, `menu_orders`, `links` e
`menu_items`):

```php
// (presente apenas na v5)
DB::table('resources')->where('slug', 'feriados-municipais')->delete();
DB::table('resources')->insert([
    'slug' => 'feriados-municipais',
    'name' => 'Feriados Municipais',
    'description' => 'Funcionalidade de feriados municipais',
    'created_at' => date("Y-m-d H:i:s")
]);

DB::table('menu_orders')->insert([
    'slug' => 'feriados-municipais',
    'clicks' => 0
]);

if(DB::table('links')->count() > 0){
    DB::table('links')->insert([
        'title' => 'Feriados Municipais',
        'alt' => 'Feriados Municipais',
        'name' => 'Feriados Municipais',
        'isBlank' => '0',
        'status_create' => '1',
        'link' => '/feriados-municipais'
    ]);

    $link_id = DB::table('links')->where('name', 'Feriados Municipais')->first();
    DB::table('menu_items')->insert([
        'name'              => 'Feriados Municipais',
        'order'             => '47',
        'menus_id'          => 1,
        'type'              => 0,
        'menus_items_id'    => 2,
        'links_id'          => $link_id->id,
        'status_create'     => 1
    ]);
}
```

Na v6 esse bloco **não existe**: o módulo passa a ser descrito pela tabela
`modulos` (id 51) e pelos registros em `resources` / `menu_orders` /
`menu_items` criados fora da migration.

**Atenção:** o `down()` da migration é o mesmo nas duas versões
(`Schema::dropIfExists('feriados_municipais')`).

## 4. Model Eloquent

`v6/app/Http/Model/Prefecture/FeriadosMunicipais.php` (idêntico na v5):

```php
namespace App\Http\Model\Prefecture;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class FeriadosMunicipais extends Model
{
    use SoftDeletes;

    protected $table = 'feriados_municipais';

    protected $fillable = [
        'date',
        'description',
        'icon',
    ];
}
```

| Aspecto | Valor | Observação |
|---|---|---|
| Namespace | `App\Http\Model\Prefecture` | O model **não** usa o prefixo `Prefecture` como namespace de classe (diferente de `Content`, que é `App\Prefecture`) |
| `$table` | `feriados_municipais` | Explícito (o plural automático já bateria, mas é explícito) |
| `$fillable` | `date`, `description`, `icon` | Exclui `status`, `_token` e `_method` enviados pela request |
| `$casts` | — | **Ausente**: `date` não é tipada; o Eloquent devolve `Carbon` para colunas `date` por padrão, mas sem cast explícito para o `format()` usado nas views |
| `$dates` | — | Ausente (obsoleto no Laravel moderno) |
| SoftDeletes | sim | `deleted_at` preenchido na exclusão |

Consequência de `$fillable` + `filter_request`: o campo `status` (adicionado
pelo `structureUpInsert`) e os metadados da request (`_token`, `_method`) são
descartados silenciosamente pelo *mass assignment*.

## 5. View SQL `lista_feriados_municipais`

### 5.1 Definição

`v6/database/migrations/2023_05_29_144236_create_view_lista_de_feriados_municipais.php`
(**idêntica** na v5):

```sql
create or REPLACE VIEW public.lista_feriados_municipais
AS SELECT row_number() OVER (ORDER BY fm.created_at DESC) AS value,
    to_char(fm.date::timestamp with time zone, 'DD/MM/YYYY'::text) AS data,
    fm.description as descricao,
    fm.id
FROM feriados_municipais fm
WHERE fm.deleted_at IS NULL
ORDER BY fm.created_at DESC;
```

### 5.2 Schema real da view

| Coluna | Tipo | Origem |
|---|---|---|
| `value` | bigint | `row_number() OVER (ORDER BY fm.created_at DESC)` |
| `data` | text | `to_char(fm.date::timestamp with time zone, 'DD/MM/YYYY')` |
| `descricao` | text | `fm.description` |
| `id` | integer | `fm.id` |

### 5.3 Como a view é consumida

Exclusivamente pelo DataTable do CMS:

```php
// v6/app/Http/Controllers/Prefecture/DatatableController.php:399-403
public function get_feriados()
{
    $feriados_municipais = DB::table("lista_feriados_municipais")->get();
    return DataTables::of($this->struct_views($feriados_municipais, 'feriados-municipais'))->make(true);
}
```

E, indiretamente, pelas colunas do JS
`v6/public/assets/js/custom/contents/feriados-municipais/datatable.js`:

| Coluna JS | Origem na view |
|---|---|
| `value` | `row_number()` |
| `data` | `data` (texto `DD/MM/YYYY`) |
| `descricao` | `descricao` |
| `id` | `id` (usado nos botões de editar/excluir) |

**A view não é usada pelo portal público** — o controller do portal consulta
`feriados_municipais` via Eloquent.

Observações técnicas:

- A view **não expõe o `icon`**: o operador não vê qual ícone está gravado na
  listagem do CMS.
- A ordenação é por `created_at DESC` (data de cadastro), **não** pela data do
  feriado — a listagem do CMS não está em ordem cronológica de feriado.
- `to_char(fm.date::timestamp with time zone)` converte `date` para timestamptz; em
  fusos negativos, `date` pode exibir o dia anterior (o `date` é convertido
  para meia-noite local e reconvertido em UTC).

## 6. Registro do módulo

| Tabela | id | slug / nome | `modulo_id` | Outros |
|---|---|---|---|---|
| `modulos` | 51 | `feriados-municipais` / "Feriados Municipais" | — | `status = false` (desativado) |
| `resources` | 70 | `feriados-municipais` / "Feriados Municipais" | 51 | — |
| `menu_orders` | 37 | `feriados-municipais` | 51 | `clicks = 64` |

A migration `v6/database/migrations/2024_11_01_150206_create_modulos_table.php`
insere o registro:

```php
// ID 51
DB::table('modulos')->insert([
    'name' => 'Feriados Municipais',
    'slug' => 'feriados-municipais',
    'status' => 0,
]);
```

O `status` é alterável em `/cms/modulos`
(`v6/app/Http/Controllers/Admin/ModulosController.php`) e controla a exibição do
item de menu no CMS.

## 7. Migrations relacionadas

| Data | Arquivo | Efeito |
|---|---|---|
| 2023-02-02 | `v6/database/migrations/2023_02_02_094344_create_feriados_municipais_table.php` | Cria `feriados_municipais` (v5: cria + semeia `resources`/`menu_orders`/`links`/`menu_items`) |
| 2023-05-29 | `v6/database/migrations/2023_05_29_144236_create_view_lista_de_feriados_municipais.php` | Cria a view `lista_feriados_municipais` |
| 2024-11-01 | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` | Registra o módulo (id 51) |

**Não há** migration posterior que altere `feriados_municipais` (nada adiciona
coluna desde fev/2023) nem seed de feriados.

## 8. Estado dos dados no ambiente de desenvolvimento

Consulta `SELECT count(*) FROM feriados_municipais` no banco `prefeituras_v5`
(v6): **0 linhas**. A tabela e a view existem, mas não há feriados cadastrados.

## 9. Diagrama de relacionamentos

```mermaid
erDiagram
    modulos ||--o{ menu_orders : "modulo_id"
    modulos ||--o{ resources : "modulo_id"
    feriados_municipais {
        int id PK
        date date "not null"
        varchar icon "nullable"
        text description "not null"
        timestamp created_at
        timestamp updated_at
        timestamp deleted_at
    }
    lista_feriados_municipais {
        bigint value "row_number"
        text data "DD/MM/YYYY"
        text descricao
        int id
    }
```

`lista_feriados_municipais` é uma **view** sobre `feriados_municipais`, não uma
tabela com FK.
