# Concursos e PSS — Resumo Executivo

> **Versão analisada:** `v5` (o módulo **não existe** na `v6`)
> **Slug do módulo:** `concurso-pss` (tabela `resources`, id 16 na base v5)
> **Natureza:** Ambos (CMS `/cms/concursos-pss` + Portal público `/concursos-pss`)
> **Estado:** apenas v5 — reimplementação completa na v7

---

## 1. Objetivo

Módulo de **publicação de certames de seleccionar servidores** — Concursos Públicos,
Processos Seletivos Simplificados (PSS) e Testes Seletivos. O servidor público do CMS
cadastra cada certame com número, ano, objeto, situação, vagas ofertadas/preenchidas,
validade e os PDFs do edital; o portal entrega o citizen a listagem filtrável e a
página de detalhe com os arquivos para download.

O módulo substitui, na prática, a página estática "Concurso Público" que ainda
existe no menu (`menu_items` id 35 e 59, `category_contents_id = 18`): o conteúdo
antigo era uma página fixa; a v5 introduz um **cadastro estruturado e pesquisável**.

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Lista pública de certames com filtro por ano, tipo e texto da descrição; página de detalhe por certame com download dos editais em PDF. |
| Prefeitura (CMS) | Tela de cadastro/edição/exclusão com upload de múltiplos PDFs por certame, listagem em DataTable server-side e exportação (Excel/PDF/CSV/TXT). |
| Transparência e legalidade | Publica objeto do certame, situação e vagas — dados exigidos pela legislação de concursos. A data de `validade` permite ao cidadão saber quando o certame expira. |
| Operação técnica | Tabela única `concursos_pss` + view SQL `concursos_pss_view`; resource de permissão `concurso-pss` (id 16) e linha de contador em `menu_orders` (id 36). |

## 3. Comportamento

- Um registro por certame: `tipo`, `numero`, `ano`, `descricao`, `situacao`,
  `vagas_ofertadas`, `vagas_preenchidas`, `validade` (opcional), `arquivo` (opcional,
  JSON) e `slug` (gerado).
- `tipo`, `numero`, `ano`, `descricao` e `situacao` são **obrigatórios**; as duas
  colunas de vagas, a validade e os arquivos são opcionais
  (`v5/app/Http/Requests/ConcursoPssRequest.php`).
- O `slug` é gerado automaticamente em `tipo-numero-ano-id`
  (`str_slug`, em `v5/app/Http/Model/Prefecture/ConcursoPss.php:29-34`); é ele que
  identifica o certame na URL pública `/concurso-pss/{slug}`.
- A exclusão é **soft delete** (`deleted_at`); a view `concursos_pss_view` já filtra
  os excluídos, mas o controller do CMS ainda encontra o registro por id.
- A listagem do portal ordena por `ano` desc e, em empate, por `created_at` desc.
- A busca textual do portal actua **somente sobre `descricao`**, insensível a acentos
  via `translate()` + `clean_slug()`.
- A exportação acontece pela **mesma URL** da listagem, com o parâmetro `?type=`
  (`xls`, `pdf`, `csv`, `txt`), respeitando os filtros aplicados.

## 4. Como o Usuário Interage

**Operador (CMS).** Em `/cms/concursos-pss` vê a listagem em DataTable (ID, Tipo,
Número, Ano, Descrição truncada em 80 caracteres, Situação, Ações). O botão
"Cadastrar" só aparece com a permissão `concurso-pss.create`. No formulário há campos
para tipo, número, ano, situação, vagas ofertadas, vagas preenchidas, validade
(`dd/mm/aaaa`) e descrição; o bloco "Adicionar Arquivo" cria dinamicamente campos
`<input type="file" name="arquivo[]">` + `arquivo_desc[]` (descrição livre por
arquivo). Arquivos já enviados são listados com download/visualizar e botão de
remoção via `DELETE /cms/concursos-pss/{id}/arquivo/{index}`.

**Cidadão (Portal).** Em `/concursos-pss` vê um card de filtros (Ano, Tipo, busca por
Descrição) com botões "Consultar" e "Limpar campos", a tabela de resultados
(15 por página) com link de detalhe, e o bloco "Salvar como: xls / pdf / csv / txt".
Em `/concurso-pss/{slug}` vê os dados do certame em tabela e a lista de arquivos para
download.

## 5. Detalhes e Particularidades Técnicas

- **Camadas:** `Route` → middleware (`check.logged` + `check.route.permission` no CMS;
  `check.site.manutention` no portal) → `Controller` → `FormRequest` → `Model`
  (Eloquent + SoftDeletes) → View Blade / DataTable / Export.
- **Sem Repository e sem Service:** o CRUD chama o Model diretamente; o portal também.
- **SQL manual:** a busca do portal usa `whereRaw` com `translate(lower(...)) ILIKE ?`.
- **Paginação em memória:** o portal faz `->get()` e pagina o array com
  `LengthAwarePaginator` — sem paginação no banco.
- **`flash()`** (`laracasts/flash` 3.0) para feedback; **`activity()`** (spatie
  activitylog) **não** é usada neste módulo; **`menuClicks()`** **não** é chamada
  apesar da linha em `menu_orders`.
- **Dependências:** `maatwebsite/excel` 3.1, `barryvdh/laravel-dompdf` 0.8,
  `yajra/laravel-datatables` 1.5, `cartalyst/sentinel`, `laracasts/flash`.

## 6. Estrutura de Dados

| Objeto | Descrição |
|---|---|
| `concursos_pss` | Tabela base, 14 colunas, PK `id`, soft delete. |
| `concursos_pss_view` | View SQL com `row_number()` como `value` e filtro `deleted_at IS NULL`. |
| `resources` (id 16) | `slug = 'concurso-pss'`, nome "Concursos e PSS". |
| `menu_orders` (id 36) | `slug = 'concurso-pss'`, contador de cliques (nunca incrementado). |

## 7. Como Testar

Cenários manuals: cadastrar um certame com 2 PDFs e 2 descrições; editar sem anexar
novo arquivo (preserva os anteriores); remover o 1º arquivo e conferir o índice;
filtrar o portal por ano/tipo/texto; exportar em 4 formatos; excluir e verificar que
sumiu da listagem do portal.

## 8. Migração para Laravel Moderno

Reconstrução do zero em PHP 8.x + Laravel 11/12: model enxuto com casts, `enum` para
`tipo` e `situacao`, `FormRequest` com `authorize()` delegando a uma Policy, anexos
em disco privado com download autenticado, API Resource JSON, paginação real no banco
(`simplePaginate`/`cursorPaginate`), exportação via `Excel::download`/`PDF` com
template único e trilha de auditoria com `spatie/laravel-activitylog` 4.x.

## 9. Resumo Geral

O módulo `concursos-pss` publica a lista de certames de seleção da prefeitura. Ele
existe **apenas na v5**: a v6 não tem controller, model, request, export, view nem
rota para ele, e o banco v6 não possui a resource `concurso-pss`. Na v5 o fluxo é
simples e funcional — CMS cadastra certame com PDFs, portal lista, filtra por
ano/tipo/descrição, abre o detalhe por slug e exporta em 4 formatos — mas carrega
gambiarras: paginação manual em memória, `whereRaw` com `translate()`, lista de tipos
hardcoded no controller, duplo `flash()` no tratamento de erro, `<tbody>` repetido
por linha na view de exportação e ausência de auditoria. A v7 deve reimplementar o
comportamento observável preservando as URLs públicas, os nomes dos parâmetros de
filtro, o formato de slug e os quatro formatos de exportação.

---

## Índice do dossiê

| Arquivo | Conteúdo |
|---|---|
| `00-RESUMO.md` | Este documento |
| `01-ARQUITETURA.md` | Camadas, classes e o diagrama de fluxo |
| `02-MODELAGEM.md` | Estrutura de dados detalhada |
| `03-ROTAS-E-CONTROLADORES.md` | Rotas, controllers, requests, permissões |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, exportação |
| `05-REGRAS-E-PORTABILIDADE.md` | Particularidades e armadilhas |
| `06-MIGRACAO-MODERNA.md` | Plano de reconstrução em Laravel moderno |
| `07-TESTES.md` | Estratégia e casos de teste |
| `08-GAPS-E-DIVIDAS.md` | Pendências, riscos, comparativo v5 vs v6 |
