# Solicitações LAI (e-SIC) — Resumo Executivo

> **Versão analisada:** `v6` (módulo também existe na `v5`, com diferenças — ver `08-GAPS-E-DIVIDAS.md`)
> **Slug do módulo:** `solicitacoes-lai` (tabela `modulos`, id 33, nome "Solicitações LAI")
> **Natureza:** CMS (painel administrativo) + Portal (público)
> **Estado:** migrado v5 -> v6 (funcionalmente equivalente; divergências documentadas no item 08)

---

## 1. Objetivo

O módulo implementa o e-SIC (Sistema Eletrônico de Informações ao Cidadão) da Lei de
Acesso à Informação (Lei 12.527/2011): o cidadão registra uma solicitação de
informação pública pela internet, recebe um número de protocolo e acompanha o
andamento; a prefeitura (CMS) recebe as solicitações numa caixa de entrada,
classifica o status (em tramitação, atendido, indeferido, prorrogado), responde e
anexa arquivos. O mesmo conjunto de dados alimenta o Relatório Estatístico
público (art. 30, III da Lei 12.527/2011).

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Protocola pedidos 24/7, recebe protocolo numérico (`date('YmdHis')`), consulta andamento e resposta pelo próprio número de protocolo, sem login. |
| Prefeitura (CMS) | Painel "Solicitações (LAI)" com contadores por status, listagem em DataTable, resposta com texto e anexos, e-mail automático de resposta/indeferimento/prorrogação. |
| Transparência e legalidade | Publica o Relatório Estatístico (quantidade por status, dentro/fora do prazo) e cumpre o prazo legal de 20 dias; a listagem completa pode ser desligada por configuração (`full_list_requests_disabled`). |
| Operação técnica | Gravação de `mask_request` (mascaramento LGPD do texto do pedido) com apoio opcional de IA (Gemini); backfill histórico do mascaramento; quatro vistas SQL (`em_tramitacao`, `atendidos`, `indeferidos`, `prorrogados`) alimentam as DataTables. |

## 3. Comportamento

- **Protocolo:** gerado no Blade do formulário (`<input type="hidden" name="protocol" value="{{date('YmdHis')}}">`) e validado como `unique:informations_requests|numeric`. A unicidade real vem do `unique` do banco/servidor; a data+hora do cliente pode colidir.
- **Pessoa e endereço são gravados a cada pedido:** `persons`, `addresses`, `emails` e `phones` recebem um registro novo por solicitação (não há reaproveitamento por CPF/CNPJ).
- **Status inicial:** `status_id = 1` (Em Tramitação) — `v6/app/Http/Controllers/Portal/InformationController.php:120`.
- **Estados e transições (CMS):** 1 Em Tramitação → 2 Atendido / 3 Indeferido / 4 Prorrogado. A transição para 4 é feita por `GET cms/solicitacoes/{id}/lai/{status}`; as transições para 2 e 3 acontecem como efeito colateral do registro da resposta (`Prefecture\AnswerController@store`).
- **Prazo legal:** o texto de 20 dias está **hard-coded** em `whereRaw('EXTRACT(DAY FROM now() - created_at) > 20')` (`v6/app/Http/Model/Prefecture/InformationsRequest.php:112`) e nas views/e-mails ("Em até 20 (vinte) dias"). A chave de configuração `response_time` (valor 20) existe mas é usada apenas pela Ouvidoria.
- **Mascaramento:** todo texto de pedido é gravado duas vezes — `request` (original) e `mask_request` (mascarado por regex determinística + refinamento opcional por IA).
- **Consulta pública por protocolo:** `POST cms/ajax/get/information/by/protocol` devolve o registro **completo** (inclusive `request` sem máscara e dados do solicitante) a partir do número de protocolo, sem autenticação.

## 4. Como o Usuário Interage

**Portal (cidadão):**
1. Acessa "Solicitar Informação" (página estática `solicitar-informacao` → `acesso-rapido.index`), preenche o formulário (Pessoa Física ou Jurídica, endereço, telefone, e-mail, texto da solicitação, reCAPTCHA) e submete.
2. Recebe a tela de confirmação com o número de protocolo e o prazo de 20 dias.
3. Em "Acompanhe sua solicitação" informa o protocolo e vê status, solicitante, data e descrição do pedido, além das respostas anexadas.
4. No "LAI - Relatório Estatístico" consulta o gráfico de prazo e (se habilitado) a lista completa, com exportação em xls/csv/pdf/txt.

**CMS (operador):**
1. Menu "Solicitações (LAI)" → submenus Em Tramitação / Prorrogados / Atendidos / Indeferidos.
2. DataTable por status (com botões Responder, Prorrogar, Visualizar).
3. Tela de detalhe (`/cms/respostas-lai/{id}`) com todos os dados do solicitante, o pedido, as respostas e os anexos; botões "Responder", "Indeferir" e "Voltar".

## 5. Detalhes e Particularidades Técnicas

- Camadas: `Route` (web.php / basepro.php) → `Portal\InformationController` ou `Prefecture\InformationsRequestController` → `InformationsRequestRequest` (FormRequest) → Eloquent (`App\Prefecture\InformationsRequest`) → tabelas `informations_requests`, `persons`, `addresses`, `emails`, `phones`, `answers`, `answer_archives`, `statuses`.
- Não há repository nem camada de service dedicada: a lógica vive nos controllers e no model. `App\Http\Traits\DataMaskTrait` é a camada reaproveitada para mascaramento.
- Views SQL (`em_tramitacao`, `atendidos`, `indeferidos`, `prorrogados`) são lidas por `DB::table(...)` em `Prefecture\DatatableController` — nenhuma dessas colunas é filtrada por `mask_request`.
- O CMS usa `check.route.permission` (via `Prefecture\Controller::__construct`); as rotas de ajax do portal, sob o prefixo `cms/ajax`, **não** exigem `check.logged`.
- Dependências de terceiros: `cartalyst/sentinel` (sessão/roles), `yajra/laravel-datatables`, `maatwebsite/excel`, `barryvdh/laravel-dompdf`, `greggilbert/recaptcha`, `spatie/laravel-activitylog`, `guzzlehttp/guzzle` (chamada à API Gemini).

## 6. Estrutura de Dados

- `informations_requests` (tabela do módulo): `id`, `created_at`, `updated_at`, `deleted_at`, `request`, `ip`, `browser`, `protocol`, `persons_id` → `persons.id`, `status_id` → `statuses.id`, `mask_request`.
- `statuses` (1 Em Tramitação, 2 Atendido, 3 Indeferido, 4 Prorrogado) + `status_categories` (1 Solicitação de Informação, 2 Licitações).
- `answers` (respostas) → `informations_request_id`; `answer_archives` (pivot answer↔arquivo) + `archives`.
- Migrations: `v6/database/migrations/2018_04_13_192114_create_informations_requests_table.php` e `v6/database/migrations/2025_10_14_154644_add_mask_request_to_informations_request_table.php`.
- Seeds: `v6/database/seeds/LaiCaturiteSeeder.php` (dados de teste), `v6/database/seeds/UpdateConfigurationOrderSeederRelatorioLai.php` (chave `relatorio_completolai`), `v6/database/seeds/UpdateRequestToMaskRequestInInformationRequest.php` (backfill de `mask_request`).

## 7. Como Testar

- **Manual (portal):** submeter o formulário de solicitação; conferir protocolo na tela de confirmação; repetir em "Acompanhe sua solicitação"; verificar o Relatório Estatístico e as exportações.
- **Manual (CMS):** abrir cada status do menu; responder com e sem anexo; indeferir; prorrogar; conferir os e-mails no MailHog (porta 8025 do container `v6_6f22e1bd-mailhog-1`).
- **Automatizado (a criar na v7):** feature tests de validação (min 20 caracteres no pedido, CPF/CNPJ), de transição de status, de unicidade de protocolo e de mascaramento (ver `07-TESTES.md`).

## 8. Migração para Laravel Moderno

- `InformationsRequestRequest` vira Form Request com `Rule::unique` e `Rule::cpf`/`Rule::cnpj` reais; hoje as regras `cpf`/`cnpj` dependem de `laravellegends/pt-br-validator` e o reCAPTCHA é opcional.
- Status viram **enum** (`StatusLai::EM_TRAMITACAO = 1`, etc.) em vez de `status_id` numérico solto.
- Introduzir `Policy` para as transições (hoje o `check.route.permission` só checa a rota, não o estado atual).
- Respostas e anexos passam a `HasMany`/`HasManyThrough` corretos (hoje `InformationsRequest::answers()` aponta para uma coluna inexistente — ver item 08).
- Texto mascarado vira coluna gerada e versionada; a chamada à IA sai do caminho de escrita (fila) e vira job idempotente.
- Endpoints REST/JSON para o portal e para o CMS, com API Resources e `mask_request` como único texto exposto.

## 9. Resumo Geral

O módulo e-SIC é a implementação da Lei de Acesso à Informação no portal: o
cidadão preenche um formulário, recebe um protocolo e acompanha o pedido; o
operador responde no CMS, alterando o status entre Em Tramitação, Atendido,
Indeferido e Prorrogado, com e-mails automáticos. Os dados moram em
`informations_requests`, ligada a `persons`, `statuses` e `answers`; quatro
vistas SQL (criadas por migrations) alimentam as listagens do CMS. A partir de
outubro de 2025 o texto do pedido é gravado também em `mask_request`, mascarado
por regex e opcionalmente por IA, para atender à LGPD — mas apenas o relatório
público usa as versões mascaradas; o acompanhamento por protocolo devolve o
texto original e os dados do solicitante. O prazo legal de 20 dias aparece
hard-coded no SQL, nos textos e nos e-mails, sem configuração possível. A reconstrução
deve preservar o contrato funcional (protocolo, estados, prazos, anexos,
relatório e exportações) e eliminar os problemas de relacionamentos, de
endereço de e-mail e de permissões listados no dossiê de lacunas.

---

## Í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, resources |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `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 |
