# ESTRUTURA_DIARIO_ATUAL.md

> Mapeamento completo do módulo **Diário Oficial** na versão atual do projeto (branch `v6-develop`,
> origin `prefeituras_v5`). A pasta `diario-oficial-reimplementacao/` contém a cópia 1:1 da versão
> antiga (v5) usada como referência; as diferenças são destacadas na seção final.
>
> Objetivo: documentar a estrutura atual — arquivos, serviços, controles, blades, JS, CSS, views,
> sistema de certificado digital, visualização, importação de PDF, FTP e tudo mais relacionado.

---

## 1. Visão geral

O Diário Oficial é um módulo do CMS (Prefeitura) que:

1. Cadastra **edições** (`diarios`) com matérias organizadas em **áreas** e **subáreas**
   (`diario_has_areas`, `diario_areas`, `diario_sub_areas`).
2. Gera um **PDF final assinado digitalmente** (TCPDF + FPDI) a partir do conteúdo das matérias.
3. Permite **anexar arquivos PDF** como matéria (`type=file`, `file_in`, `path`).
4. Publica o PDF no **portal público** com um visualizador, busca, navegação entre edições,
   **auditoria pública (LGPD)** e **workflow de publicação com segregação de funções (4 olhos)**.
5. Usa um **certificado digital A1 (PFX)** para assinar o PDF via OpenSSL.

Arquitetura: Laravel 5.5-style (repositórios Eloquent + contracts, controllers gordos, blades do CMS
admin + portal). Banco **PostgreSQL** (views SQL `diario_oficial` etc.). Autenticação **Sentinel**.

---

## 2. Árvore de arquivos (versão atual v6)

```
app/
  Console/Kernel.php                         (shared, agendamento)
  Enum/Prefecture/DiarioOficial/             (NÃO EXISTE MAIS — ver Diffs)
  Http/
    Components/Prefecture/Contents/Preview/DiarioOficialComponent.php
    Controllers/
      Admin/Controller.php                    (base admin)
      Portal/DiarioController.php             (visualizador público)
      Prefecture/Controller.php               (base prefeitura)
      Prefecture/DatatableController.php      (DataTables compartilhado: get_diario_oficial, get_areas_diario, get_sub_areas_diario)
      Prefecture/DiarioController.php         (CMS principal — 612 linhas)
      Prefecture/DiarioAreaController.php
      Prefecture/DiarioSubAreaController.php
      Prefecture/DiarioCertificadosController.php
    Model/Prefecture/
      Archive.php, Configuration.php          (compartilhados)
      Diario.php, DiarioArea.php, DiarioSubArea.php,
      DiarioHasAreas.php, DiarioConfig.php, DiarioCerticado.php   ( typo mantido: "Certicado" )
    Presenters/DiarioPresenter.php, DefaultPresenter.php
    Requests/
      CertificadoRequest.php, DiarioAreasRequest.php, DiarioOficialRequest.php
      DiarioOficial/SaveAreaRequest.php, SaveConfigRequest.php, SortRequest.php
      (DiarioAdendo/ NÃO EXISTE MAIS — ver Diffs)
    Resources/DiarioOficial/
      GetDiarioResource.php, ListAreaContentResource.php, ListAreasAndSubareasResource.php
    Traits/AppTrait.php, FileTrait.php (+ GetInformationsPrefectureTrait, NewsTrait, UploadFile)
    Rules/                                   (SelectRule, ConditionalRequiredSlug — compartilhados)
  Providers/
    ConfigHeaderServiceProvider.php, MenuServiceProvider.php, RepositoryServiceProvider.php (+ News*)
  Repositories/
    Repository.php                           (base)
    Contracts/IDiarioAreaRepository.php, IDiarioConfigRepository.php, IDiarioSubAreaRepository.php
    Eloquent/Prefecture/
      DiarioConfig/DiarioConfigRepository.php
      DiarioOficial/
        DiarioOficialRepository.php          (geração de PDF — 537 linhas)
        Area/AreaRepository.php
        DiarioArea/DiarioAreaRepository.php
        DiarioSubArea/DiarioSubAreaRepository.php
  Services/
    FPdfService.php                          (extends Fpdi — cabeçalho/rodapé/colunas/assinar)
    Pdf/PdfConverter.php                     (PDF -> imagens JPEG via Imagick)

resources/views/
  prefeitura/contents/diario-oficial/        (CMS)
    index, create, form, loading
    components/cover-image.blade.php  [NOVO], image.blade.php, pdf-file-upload.blade.php
    configuracoes/create, configuracoes/form
    diario-areas/{create,form,index}
    diario-subareas/{create,form,index}
    modal/areas/{index,modal}
    pdf/{index,style,summernote}
  prefeitura/contents/certificado/{create,form,index}
  prefeitura/contents/components/preview/diario-oficial/{index,style,summernote}
  portal/layouts/diario-oficial/
    index.blade.php, show-pdf.blade.php, auditoria.blade.php [NOVO]

public/assets/
  css/portal/diario-oficial-viewer.css
  images/diario-oficial/*.png
  js/custom/contents/diario-oficial/{index,datatable,generation-status [NOVO],cover-image [NOVO],config,areas,areas-diario/index,diario_portal}.js
  js/custom/contents/areas-do-diario/datatable.js
  js/custom/contents/sub-areas-diario/datatable.js
  js/custom/portal/diario-oficial/viewer.js
  js/custom/utilities/helpers/preview-diario.js (+ deleteAll, functions, table, summernote, cropper, sortable)
  js/modulos/cropper-min.js, sortableJs-min.js
  plugins/summernote/*
  img/diario-oficial(diario).png, diario-oficial(oficial).png

database/
  migrations/  (ver seção 10)
  seeds/      (ver seção 11)

routes/
  basepro.php     (rotas CMS/admin do diário)
  web.php         (rotas portal do diário)
  breadcrumbs.php (trilha "Diário Oficial")
  prefeitura.php, api.php, service_letter.php, console.php, channels.php (não contêm diário)
```

---

## 3. Models (`app/Http/Model/Prefecture/`)

| Model | Tabela | Papel |
|-------|--------|-------|
| `Diario.php` | `diarios` | Edição. Constantes `WORKFLOW_RASCUNHO=1`, `WORKFLOW_EM_REVISAO=2`, `WORKFLOW_PUBLICADO=3`. Relações: `certificado`, `complemento` (self), `diario_areas`, `areas`/`subAreas` (hasManyThrough), `cover_image` (Archive). Fillable inclui `status_workflow`, `*_by_user_id`, `published_at`, `line_style`, `line_color`, `cover_image_id`, campos de geração (`generation_*`). `app/Http/Model/Prefecture/Diario.php:11` |
| `DiarioArea.php` | `diario_areas` | Área temática (16 linhas, só `name`). |
| `DiarioSubArea.php` | `diario_sub_areas` | Subárea (16 linhas). |
| `DiarioHasAreas.php` | `diario_has_areas` | Matéria (ligação edição↔área). Campos-chave: `titulo`, `conteudo`, `type` (`text`/`file`), `file_in` (bool), `path` (PDF anexo), `position`, `id_area`, `id_subarea`, `number_column`, `adendo_id`. `app/Http/Model/Prefecture/DiarioHasAreas.php:41` |
| `DiarioConfig.php` | `diario_configs` | Config global (logo_position, header_img, certificado_padrao, ativos, lei). 26 linhas. |
| `DiarioCerticado.php` | `diario_certificados` | Certificado digital A1. Campos: `name`, `path` (CRT), `cert`, `pkey` (armazenados no banco). **Atenção**: nome de classe com typo ("Certicado") mantido do original. 19 linhas. |
| `Archive.php`, `Configuration.php` | `archives`, `configurations` | Compartilhados (capa, header, configs do site). |

---

## 4. Repositories (`app/Repositories/`)

- `Repository.php` — base (`upInsert`, `destroyAll`, `filter_request`, etc.).
- `DiarioOficialRepository.php` — **coração da geração** (`generatePDF`, `generatePdfFile`,
  `printAnexoMateria`, `gridBoxesForColumns`, `getPdfPath`, `getPublicAuditTrail`). `app/Repositories/Eloquent/Prefecture/DiarioOficial/DiarioOficialRepository.php:24`
- `AreaRepository`, `DiarioAreaRepository`, `DiarioSubAreaRepository`, `DiarioConfigRepository` — CRUD das respectivas entidades.
- Contracts: `IDiarioAreaRepository`, `IDiarioSubAreaRepository`, `IDiarioConfigRepository` (bind no `RepositoryServiceProvider`).

---

## 5. Services (geração de PDF)

### `app/Services/FPdfService.php` (extends `setasign\Fpdi\Tcpdf\Fpdi`)
Renderizador do PDF final. Responsabilidades:
- `Header()` — desenha logotipo (3 posições: `center`/`left`/`right`), QR code, lei validadora,
  CNPJ, numeração de página e **aplica a assinatura digital** via
  `$this->setSignature($certificate, $key, '', '', 2, $info)` (linha 193).
- `Footer()` — "DOCUMENTO ASSINADO DIGITALMENTE POR … VERIFIQUE EM https://validar.iti.gov.br/".
- `addCoverPage()` — página de capa (imagem A4 cheia) `:64`.
- `PrintChapter` / `ChapterHeader` / `ChapterBody` / `ChapterTitle` — composição em colunas (1/2/3).
- `contentPageNumber()` — numeração que desconta a capa `:82`.
- `convertPdfToImages(...)` — delega ao `PdfConverter` (anexos) `:16`.
- Propriedades: `certificate`, `coverImagePath`, `lineStyle`, `lineColor`, `columnsNumber`, `logoPosition`, `progressCallback`, etc.

### `app/Services/Pdf/PdfConverter.php`
Converte **PDFs externos anexados** em imagens JPEG (DPI 100, largura 700px, qualidade 80) via **Imagick**.
- `convertPdfToImages($pdfPath, $outputDir, $diarioId, $materiaId, $progressCallback)` — por página,
  com resiliência (falha numa página não derruba as demais) `:36`.
- `countPages()` — FPDI (rápido) com fallback Imagick `:141`.
- Usa `storage/app/public/{outputDir}` e reporta progresso ao controller/repository.

> **Diff vs antigo**: os sub-serviços `CoverHandler`, `HeaderRenderer`, `ImageProcessor`,
> `LayoutManager` (que existiam na v5) **foram removidos**; restaram apenas `FPdfService` +
> `PdfConverter`.

---

## 6. Controllers

### CMS — `app/Http/Controllers/Prefecture/DiarioController.php` (612 linhas)
Fluxo principal de administração:
- `index/create/store/edit/update` — CRUD da edição. Em `store`/`update` define
  `status_workflow = RASCUNHO` e dispara `dispatchGeneration()` (marca `generation_status=pending`).
- `dispatchGeneration($id)` `:228` — marca PDF como pendente (geração assíncrona, não síncrona).
- `generationStatus($id)` `:246` — endpoint de **polling** do progresso (badge na listagem/edição).
  Se `processing` há >10 min, marca `failed`.
- `publish($id)` `:307` — **publicação com 4 olhos**: só se `EM_REVISAO`; o criador/editador
  **não** pode publicar (`created_by_user_id`/`updated_by_user_id` == usuário atual → 403).
- `toogle_status` `:345` — ativa/desativa respeitando `diario_oficial_segregacao_funcoes`.
- `refresh_PDF` `:501` / `refresh_PDF_preview` `:512` — geração efetiva (`generatePdfFile`),
  atualiza `generation_status` (processing→completed/failed) e `generation_progress`.
- `sort` `:577` — reordena matérias (Sortable) e reagenda geração.
- `attachCoverImage` `:197` / `delete_cover_image` `:279` — upload/remoção da imagem de capa (Archive).
- `get_configuration` / `update_configuration` / `delete_header_img` — configs + imagem de cabeçalho.
- `dados_diario` `:567` — API (`GetDiarioResource`).
- `loading` `:608` — tela de loading do preview.

### CMS — `DiarioAreaController`, `DiarioSubAreaController`, `DiarioCertificadosController`
- `DiarioCertificadosController` (112 linhas): `store` faz upload do **PFX**, executa
  `shell_exec("openssl pkcs12 -in … -out …crt -nodes -passin pass:$password")`, parseia o CRT com
  `openssl_x509_read`/`openssl_pkcs12_read` e grava `cert`+`pkey` no banco. `app/Http/Controllers/Prefecture/DiarioCertificadosController.php:53`
  (⚠️ `shell_exec` com senha na linha de comando — risco de segurança).

### Portal — `app/Http/Controllers/Portal/DiarioController.php` (179 linhas)
Visualizador público:
- `index` — listagem paginada.
- `showPDF($id)` `:43` — serve `show-pdf.blade.php`; se o PDF não existe, marca `pending` e a view
  faz polling.
- `search` `:89` — busca por matéria/edição/autor/lei (ILIKE).
- `fileInfo($id)` `:120` — tamanho e nº de páginas do PDF (regex `/\/Page\W/`).
- `auditoria($id)` `:138` — **[NOVO]** timeline pública LGPD via `getPublicAuditTrail`.
- `filtroGET` `:152` — filtro por data/termo.

---

## 7. Certificado digital (sistema A1)

- **Cadastro**: `DiarioCertificadosController@store` recebe `.pfx` + senha; extrai CRT/PKEY com
  OpenSSL (`shell_exec` + `openssl_*`), salva `cert`/`pkey` em `diario_certificados` e o arquivo em
  `storage/app/public/diario-oficial/certificado/{id}`.
- **Uso na assinatura**: `DiarioOficialRepository::generatePdfFile` lê `certificado_padrao`
  (config) ou `id_certificado` (edição) e monta o array `$certificate` (`cert`+`pkey`).
  `FPdfService::Header()` aplica `$this->setSignature(...)` (TCPDF) — assinatura digital do PDF.
- `certReturn()` (repository e component) extrai `CN` (nome + CNPJ) do certificado para o rodapé.
- Views: `resources/views/prefecture/contents/certificado/{create,form,index}`.

---

## 8. Visualização (portal)

- `portal/layouts/diario-oficial/index.blade.php` — listagem com filtros; JS `diario_portal.js`.
- `portal/layouts/diario-oficial/show-pdf.blade.php` — `<embed>` do PDF + sidebar (busca, file-info,
  edição anterior/próxima, link de auditoria). CSS `diario-oficial-viewer.css`. JS `viewer.js`
  (polling de 5s enquanto pendente).
- `portal/layouts/diario-oficial/auditoria.blade.php` — **[NOVO]** timeline de eventos (ActivityLog)
  com mascaramento de nomes (LGPD), sem CPF/IP.
- CMS preview: `components/preview/diario-oficial/*` + `preview-diario.js` (iframe →
  `refresh-diario-preview/{id}` → `/cms/diario-oficial/{id}`).

---

## 9. Importação de PDF (anexos de matéria) — "file_in"

Implementado em `DiarioOficialRepository::printAnexoMateria` (`:282`):
- Uma matéria com `type='file'` e `path` preenchido é um PDF anexo.
- `file_in = true` → o PDF é convertido em **imagens JPEG** (`PdfConverter`) e embutido dentro do
  layout de colunas do diário (grade 1-up ou 2x2 "4-up" via `gridBoxesForColumns`).
- `file_in = false` → as páginas do PDF anexo são **importadas como páginas inteiras** (`importPage`
  do FPDI) no layout de colunas.
- Upload no CMS: `components/pdf-file-upload.blade.php` + `modal/areas/modal.blade.php`
  (matéria do tipo "Arquivo (PDF)").
- Colunas `type`, `file_in`, `path` adicionadas em `2026_09_04_150000_add_file_attachment_to_diario_has_areas_table.php`.

---

## 10. FTP

**Não existe implementação de FTP no código atual.**
- Busca por "ftp" em `app/` → só falso positivo em `AppTrait::lpad` (zsh/string "lpad").
- Busca em `config/` → apenas comentário padrão do Laravel em `config/filesystems.php`
  (`"Supported Drivers: local, ftp, s3, rackspace"`).
- Busca nos JS do módulo → nenhum match; não há cliente FTP, upload externo ou `shell_exec` no frontend.
- A publicação funciona por **HTTP**: o portal serve o PDF de `storage/app/public/...` e o frontend
  faz **polling** (`generation-status.js` no CMS, `viewer.js` no portal) até o arquivo estar pronto.
- Nenhuma variável `FTP_*` em `.env.example`.
- **Conclusão**: se houver push para FTP/validador externo (ex.: validar.iti.gov.br citado no rodapé),
  ele **não está** neste módulo — seria necessário confirmar em outro serviço/Job fora do escopo mapeado.

---

## 11. Fluxo de geração de PDF (resumo)

1. `store`/`update` (CMS) salva a edição e chama `dispatchGeneration()` → `generation_status='pending'`.
2. Frontend (`preview-diario.js` / `generation-status.js`) chama `refresh_PDF_preview/{id}`.
3. `refresh_PDF_preview` → `generatePdfFile($id)`:
   - Carrega edição, config e **certificado**; valida certificado (senão retorna false).
   - Gera QR code (`img/qrcode.png`) com a URL pública.
   - `new FPdfService()` com cabeçalho/rodapé/certificado/colunas/linha configurados.
   - Se houver `cover_image` → `addCoverPage()`.
   - Itera áreas/matérias: texto via `PrintChapter`; PDF anexo via `printAnexoMateria`.
   - `progressCallback` atualiza `generation_progress` (JSON) a cada página.
   - `Storage::put($caminho, $pdf->Output(...,'S'))` → `generation_status='completed'`.
4. Portal (`showPDF`/`viewer.js`) faz polling de `file-info` e exibe o `<embed>`.

Caminho do PDF: `storage/app/public/diario-oficial/content/{id}/pdf/diário-{edicao}.pdf`
(`DiarioOficialRepository::getPdfPath` `:80`).

---

## 12. Workflow de publicação e Segregação de Funções (NOVO na v6)

- Colunas em `diarios`: `status_workflow` (1 Rascunho / 2 Em Revisão / 3 Publicado),
  `created_by_user_id`, `updated_by_user_id`, `published_by_user_id`, `published_at`
  (`2026_09_03_100000_add_workflow_to_diarios_table.php`).
- `DiarioController@update` aceita `acao=enviar_revisao` → `EM_REVISAO`.
- `DiarioController@publish` exige `EM_REVISAO` e bloqueia o próprio elaborador (4 olhos).
- Config `diario_oficial_segregacao_funcoes` (checkbox) alterna entre o fluxo novo e o antigo
  (ativar/desativar direto).
- Seeds: `AddDiarioOficialWorkflowRolesSeeder` (papéis `redator-diario-oficial`,
  `revisor-diario-oficial`), `AddDiarioOficialPublishPermissionSeeder` (permissão `publish`),
  `AddDiarioOficialSegregacaoFuncoesConfigSeeder` (config de segregação).
- View `diario_oficial` atualizada com `status_workflow`/`status_workflow_label`.

---

## 13. Auditoria pública (NOVO na v6)

- `DiarioOficialRepository::getPublicAuditTrail($id)` `:398` lê `activity_log` filtrando por
  `properties->id_diario`, mapeia ícones/explicações e **só expõe lista branca** de campos
  (`humanizarDetalhePublico` `:471`), mascarando nomes de operadores (`maskUserName`).
- Eventos registrados nos controllers: `Criação de edição`, `Edição de dados da edição`,
  `Envio para revisão`, `Homologação de publicação`, `Retificação de edição publicada`,
  `Reordenação de matérias` (e matérias em repository/área controller).
- View `portal/layouts/diario-oficial/auditoria.blade.php`.

---

## 14. Imagem de capa (NOVO/evoluído na v6)

- `2025_09_19_164216` adicionou coluna `cover_image` (texto) em `diarios`.
- `2026_09_10_100100_add_cover_image_to_diarios_table.php` adiciona `cover_image_id` (FK → `archives`,
  `onDelete set null`) — a capa passa a ser um `Archive`.
- Upload em `DiarioController::attachCoverImage` `:197`; remoção em `delete_cover_image` `:279`.
- Renderização em `FPdfService::addCoverPage` `:64` (imagem A4 cheia antes do conteúdo).
- Widget CMS: `components/cover-image.blade.php` + `cover-image.js` (validação 5 MB, preview, DELETE).

---

## 15. Views (Blade) — resumo por pasta

**CMS** (`resources/views/prefecture/contents/diario-oficial/`):
`index` (DataTable), `create`/`form` (formulário + preview), `loading`, `components/{cover-image,image,pdf-file-upload}`,
`configuracoes/{create,form}`, `diario-areas/*`, `diario-subareas/*`, `modal/areas/{index,modal}`,
`pdf/{index,style,summernote}`.

**Certificado** (`resources/views/prefecture/contents/certificado/`): `create`, `form`, `index`.

**Preview CMS** (`resources/views/prefecture/contents/components/preview/diario-oficial/`): `index`, `style`, `summernote`.

**Portal** (`resources/views/portal/layouts/diario-oficial/`): `index`, `show-pdf`, `auditoria` [NOVO].

---

## 16. JS / CSS (frontend)

| Arquivo | Papel |
|--------|-------|
| `contents/diario-oficial/index.js` | toggle de status (CMS). |
| `contents/diario-oficial/datatable.js` | DataTable da listagem; badge de `generation_status`, botões (refresh/ver/baixar/publicar/excluir). |
| `contents/diario-oficial/generation-status.js` | **[NOVO]** polling `/cms/ajax/diario-generation-status/{id}` (10s). |
| `contents/diario-oficial/cover-image.js` | **[NOVO]** widget capa (5 MB, preview, DELETE). |
| `contents/diario-oficial/config.js` | imagem de cabeçalho (config). |
| `contents/diario-oficial/areas.js` | modal de matérias; texto vs arquivo; Sortable → `/sort`. |
| `contents/diario-oficial/areas-diario/index.js` | habilita salvar em Área. |
| `contents/diario-oficial/diario_portal.js` | listagem portal (filtro `/filtro`, paginação). |
| `contents/areas-do-diario/datatable.js`, `contents/sub-areas-diario/datatable.js` | DataTables de áreas/subáreas. |
| `portal/diario-oficial/viewer.js` | visualizador portal (busca, file-info, polling 5s). |
| `utilities/helpers/preview-diario.js` | preview CMS (iframe → refresh → show). |
| `css/portal/diario-oficial-viewer.css` | layout do visualizador (embed + sidebar). |

---

## 17. Rotas

- **CMS/admin** — `routes/basepro.php`: `diario-oficial` (resource), `diario-oficial.publish` (PUT),
  `certificado`/`area`/`subarea` (resources), `diario.destroyAll`/`sort`/`status`,
  `diario/configuracoes` (get/update), `diario/configuracoes/header-img/{id}` (DELETE),
  `diario-oficial/{id}/cover-image` (DELETE), `diario-area/{id}` (DELETE),
  `diario-generation-status/{id}`, `refresh-PDF`, `refresh-diario-preview`, `dados_diario`,
  DataTables `diario_oficial`/`areas_diario`/`sub_areas_diario` (em `DatatableController`).
- **Portal** — `routes/web.php`: `/diario-oficial` (index), `/diario-oficial/{id}` (showPDF),
  `/diario-oficial/{id}/auditoria`, `/diario-oficial/viewer/search`, `/diario-oficial/viewer/{id}/file-info`,
  `/diario-oficial/filtro`.
- **Breadcrumbs** — `routes/breadcrumbs.php` (registro `diario-oficial`).

---

## 18. Migrações (banco)

Base PostgreSQL. Principais (ordem cronológica):
- `2023_01_16` certificados · `2023_01_17` diarios/areas/subareas/has_areas · `2023_01_31` alter edicao
  · `2023_02_06` itens · `2023_04_10`/`04_19` view · `2023_05_22` view pdf · `2023_05_29` views áreas/sub
  · `2023_05_31` configs · `2023_09_18` view pdf · `2024_07_03` lei_validadora · `2024_07_31` number_column
  · `2024_09_17` permission_edit (+ view) · `2024_10_31` has_line · `2024_11_19` logo_position/header_img
  · `2025_01_29` order_column · `2025_09_19` central_line_customs + cover_image (texto)
  · `2025_09_20` **diario_adendos** (tabela) · `2025_09_22` adendo_id/file_in/path em has_areas
  · `2025_10_23` views áreas/sub ("_two")
- **v6 (novas):**
  - `2026_09_03_100000` **workflow** (`status_workflow`, `*_by_user_id`, `published_at`) + `100100` view com workflow.
  - `2026_09_04_150000` **file_attachment** (`type`, `file_in`, `path` em `diario_has_areas`).
  - `2026_09_10_100000` **line customs** (`line_style`, `line_color`) · `100100` **cover_image_id** (FK archives)
    · `100200` **generation_status/error/progress/started/completed** · `100300` view com `generation_status`.

> Nota: as migrações de `generation_status` da v5 (datadas `2026_07_07`) foram **re-datadas para
> `2026_09_10`** nesta v6. O campo `generation_progress` é adicionado junto em `100200` (JSON de progresso).

---

## 19. Seeds

- `AtualizacaoDiario`, `DiarioCaturiteSeeder`, `UpdateManualAreasDiarioSeeder` (conteúdo/áreas).
- **v6 (novos):** `AddDiarioOficialPublishPermissionSeeder`, `AddDiarioOficialSegregacaoFuncoesConfigSeeder`,
  `AddDiarioOficialWorkflowRolesSeeder` (workflow + papéis redator/revisor + permissão `publish`).

---

## 20. Diferenças principais vs versão antiga (`diario-oficial-reimplementacao/`)

| Item | Antigo (v5) | Atual (v6) |
|------|-------------|------------|
| Workflow / 4 olhos | Não existia | **NOVO**: `status_workflow`, `publish`, segregação de funções, papéis redator/revisor |
| Geração assíncrona | Síncrona por request | **NOVO**: `generation_status` + polling (`generation-status.js`, `viewer.js`) |
| Imagem de capa | Coluna texto `cover_image` | **Evoluído**: `cover_image_id` (FK Archive) + `addComponentCoverImage` + `cover-image.js` |
| Auditoria pública | Não existia | **NOVO**: `auditoria.blade.php` + `getPublicAuditTrail` (LGPD) |
| Anexo PDF (file_in) | Colunas existiam | Mantido + `file_in` importa páginas inteiras ou imagens no layout |
| Enum `DiarioHasAreasTypesEnum` | Existia | **Removido** (usa coluna `type` em `diario_has_areas`) |
| Sub-serviços PDF (`CoverHandler`,`HeaderRenderer`,`ImageProcessor`,`LayoutManager`) | Existiam | **Removidos**; restam `FPdfService` + `PdfConverter` |
| `DiarioAdendo` (model/request) | Existia (`Requests/DiarioAdendo`, tabela `diario_adendos`) | Tabela `diario_adendos` ainda existe (migration `2025_09_20`); porém **sem model/controller/request** aparente no v6 — possível objeto órfão |
| `line_style`/`line_color` | Não existiam | **NOVO** (`2026_09_10_100000`) |
| Rotas | `basepro.php` + `web.php` (arquivos completos da origem) | `basepro.php` + `web.php` (diário isolado); mais `prefecture.php`, `api.php` etc. no projeto |
| FTP | Não implementado | **Ainda não implementado** (confirmado por busca) |
| `loading.blade.php`, `pdf/*` | Existem | Mantidos |

---

## 21. Riscos / pontos de atenção

1. **Segurança A1**: `shell_exec("openssl … -passin pass:$password")` em `DiarioCertificadosController@store`
   expõe a senha do certificado na linha de comando (visível em `ps`/logs). Recomenda-se arquivo temporário.
2. **TCPDF `setSignature`** depende de OpenSSL/PHP openssl; assinatura é "permission" (nível 2), não timestamp.
3. **Dependência Imagick/Ghostscript** em `PdfConverter` (conversão de anexos).
4. **Geração síncrona em request** ainda é possível via `refresh_PDF` (botão "Atualizar"); pode estourar timeout
   em diários grandes — o polling (`refresh_PDF_preview`) é o caminho preferencial.
5. **Objeto órfão**: tabela `diario_adendos` existe mas sem model/controller no v6; verificar se ainda usada.
6. **Coluna `cover_image` (texto, 2025_09_19) vs `cover_image_id` (FK, 2026_09_10)** coexistem — possível
   redundância; o código atual usa `cover_image_id`.
7. **Typo** `DiarioCerticado` mantido (classe e arquivo) — cuidado ao referenciar.
8. **Views SQL** (`diario_oficial`, áreas, subáreas) são recriadas via `DROP VIEW` + `CREATE` nas migrations;
   qualquer alteração de coluna nas tabelas base exige atualizar a view correspondente.
