# Logs do Sistema — Modelagem de Dados

> Estrutura de dados da trilha de auditoria e do registro de módulos
> (onde está a duplicidade). Fonte: schema real do banco `prefeituras_v5`.

---

## 1. `activity_log` — a trilha de auditoria

Criada por `v6/database/migrations/2018_09_05_143852_create_activity_log_table.php`,
que usa `config('activitylog.table_name')` (resolvido para `activity_log`
por `v6/config/activitylog.php`).

| Coluna | Tipo | Null | Default | Observação |
|---|---|---|---|---|
| `id` | integer | não | `nextval('activity_log_id_seq')` | PK |
| `log_name` | varchar(191) | sim | — | sempre `'default'` (nenhuma gravação usa `logName()`) |
| `description` | text | **não** | — | a mensagem, ex.: `'Listou usuários'` |
| `subject_id` | integer | sim | — | id do modelo afetado |
| `subject_type` | varchar(191) | sim | — | FQCN do model, ex.: `App\Admin\User` |
| `causer_id` | integer | sim | — | id do usuário que executou |
| `causer_type` | varchar(191) | sim | — | `App\Admin\User` |
| `properties` | text | sim | — | **JSON** com as "properties" (ex.: `{"Detalhe":"..."}`) |
| `created_at` | timestamp(0) | sim | — | |
| `updated_at` | timestamp(0) | sim | — | |
| `ip_address` | varchar(191) | sim | — | adicionado por `2025_01_16_210444_add_ip_address_to_activity_log.php` |
| `browser` | varchar(191) | sim | — | idem |

Índices: `activity_log_pkey` (PK), `activity_log_log_name_index` (`log_name`).

**Observações de modelagem:**

1. Não há índice em `created_at`, que é a coluna usada para ordenar a
   listagem (`ORDER BY created_at DESC LIMIT 5000`).
2. Não há índice em `causer_id` nem em `subject_type`/`subject_id`.
3. `properties` é `text` (não `jsonb`): o `json_decode` é feito em PHP no
   `struct_logs()`, linha a linha.
4. Não há FK para `causer_id`/`subject_id` (o pacote é agnóstico).
5. A base está **vazia** (0 linhas) no ambiente analisado.

### 1.1 Origem dos dados (exemplos reais)

```json
// $request->get('name'), etc. — v6/app/Http/Controllers/Admin/UserController.php:129
{
  "Detalhe": "Foi criado um usuário: Id 12, Nome: Fulano, Perfil: [\"3\"], Criado por: Administrador"
}
```

```json
// v6/app/Http/Controllers/Admin/RoleController.php:88
{
  "Detalhe": "Foi criado uma role: Id 4, Nome: Editor, Permissoes: [\"usuario.index\"], Criado por: Administrador"
}
```

---

## 2. `modulos` — o registro de módulos (e a duplicidade)

Criada por `v6/database/migrations/2024_11_01_150206_create_modulos_table.php`.

| Coluna | Tipo | Null | Default |
|---|---|---|---|
| `id` | integer | não | seq |
| `name` | varchar(191) | não | — |
| `slug` | varchar(191) | **não** | — | **sem índice único** |
| `status` | boolean | sim | — |
| `created_at` / `updated_at` | timestamp(0) | sim | — |

### 2.1 Linhas duplicadas

| id | name | slug | status |
|---|---|---|---|
| **7** | Logs do Sistema | `logs-do-sistema` | `true` |
| **32** | Logs do Sistema | `logs-do-sistema` | `false` |

Ambas são inseridas **pela mesma migration**, em blocos separados
(`// ID 7` e `// ID 32`), com o mesmo `name` e o mesmo `slug`. A segunda
ocorre na seção "Sidebar" da migration, provavelmente por revisão de
código que reorganizou os blocos e duplicou a linha por engano.

**Não há `UNIQUE` em `modulos.slug`**, o que permitiu (e permite) novas
duplicações.

### 2.2 Resto do registro (58 linhas)

| Faixa | Slugs |
|---|---|
| 1-10 | `configuracoes-da-instituicao`, `temas-e-cores`, `lgpd`, `outras-configuracoes`, `e-vacina`, `fornecedores`, `logs-do-sistema` (7), `manual-do-sistema`, `suporte`, `novidades` |
| 11-32 | `usuarios`, `a-instituicao`, `a-cidade`, `noticias`, `publicacoes`, `diario-ofifical` (typo), `orgaos`, `secretarias`, `legislacao`, `licitacoes-antigas`, `licitacoes`, `banners`, `transparencia-fiscal`, `glossario`, `perguntas-frequentes`, `avisos`, `telefones-uteis`, `paginas-estaticas`, `redes-sociais`, `drive`, `menus-do-site`, `logs-do-sistema` (32) |
| 33-58 | `solicitacoes-lai`, `revisoes`, `servidor`, `requerimento-de-diarias`, `diario-oficial`, `enquetes`, `agenda-de-eventos`, `sessoes`, `requerimentos`, `pauta-do-dia`, `vereadores`, `transmissoes`, `tv-camara`, `atas-e-pontos-de-frequencia`, `unidades-de-atendimento`, `comite-de-investimentos`, `acesso-rapido`, `unidade-gestora`, `feriados-municipais`, `formularios-dinamicos`, `newsletters`, `mais-conteudos`, `destaques`, `ouvidoria`, `carta-de-servicos`, `viap` |

> Note a coexistência de `diario-ofifical` (id 16, typo) e `diario-oficial`
> (id 37) — outra duplicidade semântica, esta com slugs diferentes.

### 2.3 Efeito da duplicidade no código

`v6/resources/views/vendor/adminlte/page.blade.php:115-124`:

```php
@inject('modulos', 'App\Http\Model\Admin\Modulos')
@php
    $modulos = $modulos->whereIn('slug', [
        'configuracoes-da-instituicao',
        'temas-e-cores',
        'lgpd',
        'outras-configuracoes',
        'e-vacina',
        'fornecedores',
        'logs-do-sistema',
    ])->pluck('status', 'slug');
@endphp
```

`pluck('status','slug')` com chave duplicada **mantém a última ocorrência**.
Como o `whereIn` não desempata, as duas linhas entram e a **id 32
(`status = false`) sobrescreve a id 7 (`status = true`)**.

O mesmo ocorre em `v6/app/Providers/ModulosServiceProvider.php:22-24`
(`Modulos::all()->pluck('status','slug')`), que alimenta o portal público e o
dashboard.

---

## 3. `resources` — o recurso do módulo

| id | slug | name | modulo_id |
|---|---|---|---|
| 36 | `logs-do-sistema` | Logs do Sistema | **32** |

O recurso aponta para a **cópia desativada** do módulo. E a linha do
recurso é filtrada na matriz de permissões por
`$resource->modulo->status` (`v6/resources/views/admin/role/form.blade.php:43`),
logo **não aparece**.

O slug de permissão checado no menu é outro:
`has_access(['registro-de-atividades.index'])`
(`v6/resources/views/vendor/adminlte/page.blade.php:284`) — e
`registro-de-atividades` **não existe** em `resources`.

---

## 4. `update_logs` — a versão do sistema (conceito separado)

Criada por `v6/database/migrations/2023_03_22_095658_create_update_logs_table.php`.

| Coluna | Tipo | Null | Default |
|---|---|---|---|
| `id` | integer | não | seq |
| `version` | text | **não** | — |
| `date` | date | **não** | — |
| `title` | varchar(191) | sim | — |
| `message` | text | sim | — |
| `author_name` | varchar(191) | sim | — |
| `commit_id` | varchar(191) | sim | — |
| `created_at` / `updated_at` | timestamp(0) | sim | — |

Sem `deleted_at`. A migration insere a linha inicial
`version = '6.0.0'`, `date = '2025-03-05'`.

Consumidores:

| Consumidor | Uso |
|---|---|
| `v6/app/Console/Commands/UpdateVersion.php` (`update:logs`) | cria a próxima versão (incrementa o patch) |
| `v6/resources/views/vendor/adminlte/page.blade.php:418,421-423` | rodapé: `{{ $systemVersion->version }}` com link para `changelog.index` |
| `v6/app/Providers/FooterServiceProvider.php:102` | mesma informação no rodapé do **portal público** |

> O model `App\Http\Model\Prefecture\UpdateLogs` tem `description` no
> `$fillable`, mas a tabela **não tem** a coluna `description` — um
> `fill()` com esse campo causaria erro de coluna inexistente.

---

## 5. Views SQL

Nenhuma view SQL é usada por este módulo. A listagem consulta a tabela
`activity_log` diretamente via Eloquent.

---

## 6. Migrations relacionadas

| Migration | Efeito |
|---|---|
| `v6/database/migrations/2018_09_05_143852_create_activity_log_table.php` | cria `activity_log` a partir de `config('activitylog.table_name')` |
| `v6/database/migrations/2025_01_16_210444_add_ip_address_to_activity_log.php` | adiciona `ip_address` e `browser` |
| `v6/database/migrations/2023_03_22_095658_create_update_logs_table.php` | cria `update_logs` + linha inicial `6.0.0` |
| `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` | cria `modulos` e insere o slug `logs-do-sistema` **duas vezes** |
| `v6/database/migrations/2024_11_05_104026_add_modulo_id_to_resources_table.php` | `resources.modulo_id` (FK) — é por ele que o recurso 36 fica preso ao módulo 32 |

---

## 7. Seeds

**Nenhum** seed popula `activity_log`. A auditoria é gerada apenas em
tempo de execução.

Para `update_logs`: a migration inicial (não um seed).

---

## 8. Observações de modelagem para a v7

1. **`modulos.slug` deve ter `UNIQUE`.** A migration que resolver a
   duplicidade precisa escolher qual id sobrevive. Como o recurso
   `resources.id = 36` aponta para o **id 32**, e o item de menu depende do
   status, a decisão é:
   - manter o id 32 e **ativar** o status (recomendado: preserva a FK do
     recurso), **ou**
   - mover `resources.modulo_id` do 32 para o 7 e apagar o 32
     (recomendado: preserva o id "histórico" do módulo, que é o que a
     matrix e o menu já referenciam por status).
2. **Colunas explícitas em vez de `properties` em JSON.** A tela só usa
   `Detalhe`; na v7 vale a pena ter `action` (enum), `subject_type`,
   `subject_id`, `causer_id`, `description`, `context` (jsonb).
3. **Índice em `created_at`** e, se houver filtros, em
   `(causer_id, created_at)`.
4. **`update_logs` e `activity_log` devem ficar separadas** — são domínios
   diferentes (versão do software x auditoria de ações). A confusão atual
   vem de o rodapé misturar as duas.
