# Telefones Úteis — Modelagem de Dados

## 1. Tabelas envolvidas

### 1.1 `contents` (armazenamento real)

| Coluna | Tipo | Null | Default | Observação |
|---|---|---|---|---|
| `id` | serial | não | — | PK |
| `title` | varchar(191) | não | — | Nome do órgão/serviço |
| `text` | text | sim | — | **Número do telefone** (campo `text` do formulário) |
| `linha_fina` | varchar(300) | sim | — | Não usado neste módulo (coluna adicionada em `v6/database/migrations/2026_06_25_000001_add_linha_fina_to_contents_table.php`) |
| `slug` | varchar(191) | sim | — | Gerado a partir do título em `ContentController@store` |
| `clicks` | int | sim | — | Contador de cliques, não usado aqui |
| `status` | bool | sim | — | Existe, mas o portal **não** filtra por ele |
| `category_contents_id` | int | não | — | FK -> `category_contents.id` (30 = telefones-uteis) |
| `highlights` | bool | sim | — | — |
| `galery` | bool | sim | — | — |
| `publication_date` | timestamp | sim | — | — |
| `order` | int | sim | — | — |
| `created_at` / `updated_at` / `deleted_at` | timestamp | sim | — | `deleted_at` habilita `SoftDeletes` |

A tabela é criada por `v6/database/migrations/2018_04_02_180433_create_contents_table.php`; a coluna
`category_contents_id` é declarada como `integer('category_contents_id')->unsigned()` com FK para
`category_contents` nessa mesma migration.

### 1.2 `category_contents` (classificação)

| Coluna | Tipo | Observação |
|---|---|---|
| `id` | serial | `30` para `telefones-uteis` |
| `name` | varchar(191) | “Telefones Úteis” |
| `slug` | varchar(191) | `telefones-uteis` (chave usada por todo o código) |
| `status_create` | bool | `1` no seed (indica categoria que aceita criação via menu) |
| `category_contents_id` | int | auto-FK; `NULL` para categorias de topo |
| `status` | bool | default `true` |

Migration: `v6/database/migrations/2018_04_01_180916_create_category_contents_table.php`.
Seed: `v6/database/seeds/CategoryContentTableSeeder.php` (`updateOrCreate(['slug' => 'telefones-uteis'], ['name' => 'Telefones Úteis', 'status_create' => 1])`).

## 2. View SQL `telefones_uteis`

Criada em `v6/database/migrations/2023_03_16_093714_create_view_to_telefones_uteis.php`:

```sql
CREATE OR REPLACE VIEW telefones_uteis
as select
    row_number() OVER (ORDER BY c.created_at desc) as value,
    c.title as titulo,
    c.id as id
FROM contents c
    JOIN category_contents cc ON cc.id = c.category_contents_id
WHERE c.deleted_at IS NULL AND cc.slug = 'telefones-uteis'
ORDER BY c.created_at DESC;
```

| Coluna da view | Origem | Uso |
|---|---|---|
| `value` | `row_number()` | número sequencial exibido na coluna ID do DataTable |
| `titulo` | `contents.title` | coluna Título |
| `id` | `contents.id` | chave das ações de editar/excluir |

Observações: a view **não** expõe `text` (o telefone), **não** expõe `status` e ordena por
`created_at DESC` (o mais novo primeiro). É usada apenas por
`DatatableController@get_telefones_uteis` (`DB::table('telefones_uteis')`).

## 3. Tabelas `phones` e `phones_type` — relação real com este módulo

**Não há relação.** Estas tabelas existem no mesmo projeto, mas servem ao fluxo de pedidos de
informação (LAI), não ao módulo Telefones Úteis.

| Tabela | Colunas | Origem | Consumidor real |
|---|---|---|---|
| `phones_type` | `id`, `name`, `description`, `timestamps`, `deleted_at` | `v6/database/migrations/2018_03_16_194526_create_phones_type_table.php` | `App\Admin\PhoneType` |
| `phones` | `id`, `phones_type_id` (FK), `persons_id` (FK), `phone_number`, `timestamps`, `deleted_at` | `v6/database/migrations/2018_03_16_194527_create_phones_table.php` | `App\Admin\Phone` |

Quem usa `phones` de fato:

- `v6/app/Http/Controllers/Portal/InformationController.php:101-104` e `:309-312`:
  `Phone::create($phone + ['persons_id' => $personId])` — telefone do cidadão que preencheu um formulário de solicitação.
- `v6/database/seeds/LaiCaturiteSeeder.php:315-355` — seeds do fluxo LAI.
- `v6/database/seeds/PhonesTypeTableSeeder.php` — tipos “Residencial” e “Comercial”.
- `v6/database/seeds/PhonesTableSeeder.php` — um telefone de exemplo apontando para `persons_id = 1`.

Modelos (namespace `App\Admin`, arquivos em `v6/app/Http/Model/Admin/`):

```php
class Phone extends Model
{
    protected $table = 'phones';

    protected $fillable = [
        'phones_type_id',
        'persons_id',
        'area_code',
        'phone_number',
    ];
```

```php
class PhoneType extends Model
{
    protected $table = 'phones_type';

    protected $fillable = [
        'name',
        'description',
    ];
```

Defeitos observáveis desses modelos (relevantes para a v7):

| Problema | Evidência |
|---|---|
| `area_code` está no `$fillable` mas a coluna foi comentada na migration (`//$table->integer('area_code');`) | `v6/database/migrations/2018_03_16_194527_create_phones_table.php:20` |
| `PhoneType::phones()` não tem `return`, logo a relação retorna `null` | `v6/app/Http/Model/Admin/PhoneType.php:25` |
| `phones_type_id` é nullable na migration mas a FK é declarada `->nullable(false)` | `v6/database/migrations/2018_03_16_194527_create_phones_table.php:26-30` |
| `phones_type` tem `SoftDeletes` mas `Phone` não referencia o trait, então registros apagados de tipo continuam visíveis | `v6/app/Http/Model/Admin/PhoneType.php` vs `v6/app/Http/Model/Admin/Phone.php` |

Estado atual no banco (`prefeituras_v5`, container `v6_6f22e1bd-postgres-1`):

| Consulta | Resultado |
|---|---|
| `select count(*) from telefones_uteis` | 0 |
| `select count(*) from rede_social` | 0 |
| `select count(*) from phones` | 0 |
| `select * from phones_type` | 2 linhas (Residencial, Comercial) |

## 4. Relacionamentos Eloquent

| Relação | Definição | Uso |
|---|---|---|
| `Content::categoryContents()` | `belongsTo(CategoryContent::class, 'category_contents_id', 'id')` | Filtro do portal e da view |
| `Content::archives()` | `hasMany(Archive::class, 'contents_id')` | Não usado neste módulo |
| `Content::linksUnique()` | `hasOne(Link::class, 'contents_id', 'id')` | Não usado neste módulo (o telefone é texto, não link) |

Trecho real (`v6/app/Http/Model/Prefecture/Content.php`):

```php
public function categoryContents()
{
    return $this->belongsTo(CategoryContent::class, 'category_contents_id', 'id');
}
```

## 5. Consultas que o módulo executa

| Contexto | Consulta | Arquivo |
|---|---|---|
| Portal | `Content::whereHas('categoryContents', fn => slug = 'telefones-uteis')->get()` | `v6/app/Http/Traits/GetInformationsPrefectureTrait.php:28-33` |
| CMS DataTable | `DB::table('telefones_uteis')->get()` | `v6/app/Http/Controllers/Prefecture/DatatableController.php:122-126` |
| CMS criação | `Content::create($contentData)` com `category_contents_id` do formulário | `v6/app/Http/Controllers/Prefecture/ContentController.php:693` |
| CMS permissões | `has_access('telefones-uteis.edit')` etc. | `v6/app/Library/Helper/appHelpers.php:22` |

## 6. Migrations e seeds do módulo

| Arquivo | Papel |
|---|---|
| `v6/database/migrations/2018_04_01_180916_create_category_contents_table.php` | tabela `category_contents` |
| `v6/database/migrations/2018_04_02_180433_create_contents_table.php` | tabela `contents` |
| `v6/database/migrations/2023_03_16_093714_create_view_to_telefones_uteis.php` | view `telefones_uteis` |
| `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` | registro do módulo no CMS (`modulos`) |
| `v6/database/seeds/CategoryContentTableSeeder.php` | categoria `telefones-uteis` |
| `v6/database/seeds/ResourcesTableSeeder.php` | resource/permissões `telefones-uteis` |
| `v6/database/seeds/MenuOrderSeeder.php` | ordem do item no menu |
| `v6/database/seeds/PhonesTypeTableSeeder.php` | tipos de telefone (LAI) |
| `v6/database/seeds/PhonesTableSeeder.php` | telefone de exemplo (LAI) |
