# Checklist técnico — Fechamento MVP (M2 → M3)

**Base:** Documentação Funcional Simulador CBS/IBS (v1.0, 14/01/2026)  
**Estado atual:** M1 ~80% · M2 ~35% · M3 ~75%  
**Objetivo:** Alinhar o produto ao posicionamento consultivo (prontidão + pendências + confiabilidade + governança)

---

## Visão das sprints

| Sprint | Marco doc | Foco | Entregável principal |
|--------|-----------|------|----------------------|
| **S3** | M2 (início) | Modelo de pendências + motor de confronto | Tabelas + services + regras MVP |
| **S4** | M2 (fim) | Painel de Pendências + Prontidão (v1) | UI acionável + score por cliente |
| **S5** | M3 (início) | Governança (audit/versioning) + de-para | Trilha de alterações + CRUD regras |
| **S6** | M3 (fim) | Confiabilidade + relatórios executivos | Bloqueio simulação + PDFs consultivos |
| **S7–S8** | M4 | Piloto agro + ajustes | Validação com caso real |

**Premissa:** 2 semanas por sprint · time 1–2 devs PHP/Laravel

---

## Sprint 3 — Motor de confronto e modelo de pendências

### S3.1 — Migration: tabelas de pendência e prontidão

**Criar migration** `2026_07_XX_create_pendencia_prontidao_tables.php`:

```sql
-- simulacao_pendencia
id, idtenant, idpessoa, idsimulacao (nullable), idimport (nullable),
tipo (enum), codigo_regra (varchar), titulo, descricao,
criticidade (alta|media|baixa),
impacto_simulacao (bloqueia|ressalva|informativo),
acao_recomendada (text),
referencia_tipo (produto|import|cadastro|unidade|geral),
referencia_id / referencia_chave (cod_item, cnpj, etc.),
status (aberta|em_revisao|resolvida|ignorada),
responsavel (maiore|cliente),
resolvido_por, resolvido_em, justificativa_resolucao,
created_at, updated_at

-- simulacao_prontidao (snapshot por cliente/simulação)
id, idtenant, idpessoa, idsimulacao (nullable),
score (0-100),
classificacao (simulavel|simulavel_ressalva|nao_simulavel),
criterios_json (detalhe dos checks),
pendencias_bloqueantes (int), pendencias_ressalva (int),
calculado_em
```

**Critério de aceite:** migrations rodam em MySQL; models com `TenantScope`; índices em `(idtenant, idpessoa, status)`.

**Arquivos novos:**
- `database/migrations/2026_07_XX_create_pendencia_prontidao_tables.php`
- `app/Models/SimulacaoPendencia.php`
- `app/Models/SimulacaoProntidao.php`

---

### S3.2 — Service: catálogo de regras de confronto (MVP)

**Criar** `app/Services/ConfrontoRegrasCatalog.php` com regras fixas v1:

| Código | Tipo | Criticidade | Impacto | Gatilho |
|--------|------|-------------|---------|---------|
| `PROD_SEM_0200` | cadastro | alta | bloqueia | `COD_ITEM` em C170 sem registro 0200 |
| `NCM_AUSENTE` | produto | alta | bloqueia | item sem NCM (0200 e C170) |
| `ORIGEM_INDEFINIDA` | produto | media | ressalva | `origem_classificada = indefinido` em `reforma_produto_item` |
| `UNIDADE_DIVERGENTE` | unidade | media | ressalva | mesma `cod_item` com `unid` diferentes em `sped_doc_item` |
| `PROD_DUPLICADO` | produto | baixa | informativo | mesmo NCM+descr similar, múltiplos `cod_item` |
| `CADASTRO_AUSENTE` | cadastro | media | ressalva | `cod_item` SPED sem match em `prodserv` (quando cadastro existir) |
| `INTEGRIDADE_BAIXA` | import | alta | bloqueia | `% integridade` < 95 em `SpedRelatorioService` |
| `PERIODO_INCOMPLETO` | geral | media | ressalva | cliente com < 12 meses SPED no consolidado |
| `SIMPLES_NAO_CONSULTADO` | cadastro | baixa | informativo | `pessoa.regimetributario` vazio e CNPJ válido |

**Critério de aceite:** cada regra retorna `PendenciaDto` padronizado; sem side-effects.

---

### S3.3 — Service: motor de confronto

**Criar** `app/Services/ConfrontoService.php`:

```php
public function executarParaImport(SpedImport $import): Collection;
public function executarParaSimulacao(SimulacaoTributaria $sim): Collection;
public function executarParaPessoa(Pessoa $pessoa, ?Carbon $periodoInicio, ?Carbon $periodoFim): Collection;
public function persistirPendencias(Collection $pendencias, bool $resolverAutomaticas = true): int;
```

**Lógica:**
1. Rodar regras do catálogo sobre dados já normalizados
2. Upsert em `simulacao_pendencia` (chave: `idtenant + codigo_regra + referencia_chave + idpessoa`)
3. Auto-resolver pendências cuja condição não existe mais
4. Não duplicar pendências abertas

**Integrar em:**
- `SpedImportProcessor::processFile()` — ao final do parse OK
- `ReformaAnaliseService::syncProdutos()` — após agregação de produtos
- `SimulacaoFromSpedService` — pós-import one-click

**Critério de aceite:** import SPED gera pendências automaticamente; reimport limpa/resolver conforme estado atual.

---

### S3.4 — Confronto produto × cadastro interno

**Criar** `app/Services/ProdutoCadastroMatcher.php`:

- Cruzar `sped_reg_0200.cod_item` / `reforma_produto_item.cod_item` com `prodserv` (`Produto`) por:
  - match exato código (se houver campo de código externo — avaliar `prodserv` ou criar `cod_item_sped` opcional)
  - fallback: similaridade de descrição + NCM (Levenshtein ou `LIKE` — MVP simples)
- Gerar pendência `CADASTRO_AUSENTE` ou `CADASTRO_INCONSISTENTE` (NCM diferente)

**Nota:** tabela `prodserv` hoje não tem `cod_item` SPED — migration opcional:
```php
$table->string('cod_item_sped', 60)->nullable()->index();
```

**Critério de aceite:** relatório lista % produtos SPED com/sem cadastro; pendência criada para ausentes.

---

### S3.5 — Confronto de unidades e duplicidade

**Em** `ConfrontoService`:

- **Unidades:** `GROUP BY cod_item HAVING COUNT(DISTINCT unid) > 1` em `sped_doc_item`
- **Duplicidade:** `GROUP BY ncm, LEFT(descr_item, 30) HAVING COUNT(DISTINCT cod_item) > 1` em `sped_reg_0200`

**Critério de aceite:** regras `UNIDADE_DIVERGENTE` e `PROD_DUPLICADO` populadas com `referencia_chave` legível.

---

### S3.6 — Testes unitários das regras críticas

**Criar** `tests/Unit/ConfrontoRegrasTest.php`:
- Cenário: C170 sem 0200 → `PROD_SEM_0200` bloqueante
- Cenário: origem indefinida → `ORIGEM_INDEFINIDA` ressalva
- Cenário: integridade 90% → `INTEGRIDADE_BAIXA`

**Critério de aceite:** CI verde; pelo menos 6 casos cobrindo bloqueio e ressalva.

---

## Sprint 4 — Painel de Pendências + Prontidão para Simular

### S4.1 — Service: cálculo de prontidão

**Criar** `app/Services/ProntidaoService.php`:

```php
public function calcular(Pessoa $pessoa, ?SimulacaoTributaria $sim = null): SimulacaoProntidao;
public function classificar(int $score, int $bloqueantes, int $ressalvas): string;
```

**Score v1 (pesos sugeridos):**

| Critério | Peso | Fonte |
|----------|------|-------|
| Integridade média imports | 25 | `SpedRelatorioService::integridade()` |
| % produtos com origem definida | 25 | `reforma_produto_item` |
| % produtos com NCM | 15 | `reforma_produto_item` / `sped_reg_0200` |
| Cobertura meses (12m) | 20 | imports por período |
| Pendências bloqueantes = 0 | 15 | `simulacao_pendencia` |

**Classificação:**
- `nao_simulavel`: qualquer pendência bloqueante OU score < 50
- `simulavel_ressalva`: sem bloqueante E (score < 80 OU ressalvas > 0)
- `simulavel`: score ≥ 80 E zero bloqueantes E ≤ 3 ressalvas

Persistir snapshot em `simulacao_prontidao`; recalcular após confronto.

**Critério de aceite:** método retorna os 3 estados do documento funcional.

---

### S4.2 — Controller + rotas do painel de pendências

**Criar** `app/Http/Controllers/Admin/PendenciaController.php`:

| Método | Rota | Ação |
|--------|------|------|
| GET | `admin/pendencias` | Lista global (filtros: cliente, status, criticidade) |
| GET | `admin/clientes/{id}/pendencias` | Pendências do cliente |
| GET | `admin/simulacoes/{id}/pendencias` | Pendências da simulação |
| PATCH | `admin/pendencias/{id}` | Atualizar status, responsável, justificativa |
| POST | `admin/pendencias/recalcular` | Reprocessar confronto + prontidão (cliente ou simulação) |

**Registrar em** `routes/web.php` no grupo `admin` + middleware `role:ADMIN`.

---

### S4.3 — Views: Painel de Pendências

**Criar:**
- `resources/views/admin/pendencias/index.blade.php`
- `resources/views/admin/pendencias/_tabela.blade.php`
- `resources/views/admin/pendencias/_filtros.blade.php`

**Colunas (conforme doc):**
Tipo · Criticidade (badge cor) · Impacto (bloqueia/ressalva) · Descrição · Ação recomendada · Status · Responsável · Ações

**Ações inline:** marcar "em revisão", "resolvida" (com justificativa obrigatória), atribuir responsável.

**Critério de aceite:** consultor Maiore consegue priorizar backlog sem abrir Excel.

---

### S4.4 — Widget de prontidão nas telas existentes

**Inserir componente** `resources/views/components/prontidao-badge.blade.php`:

- **Cliente** (`admin/clientes/index.blade.php`, `edit.blade.php`): badge + score
- **Simulação** (`admin/simulacoes/index.blade.php`, `edit.blade.php`): banner no topo
- **Consolidado** (`_consolidado.blade.php`): faixa "Prontidão do grupo"

Cores: verde (`simulavel`), amarelo (`simulavel_ressalva`), vermelho (`nao_simulavel`).

**Critério de aceite:** estado visível em < 3 segundos ao abrir simulação de cliente.

---

### S4.5 — Integração: pendências na aba Reforma

**Em** `resources/views/admin/simulacoes/_reforma.blade.php`:

- Card "Pendências ativas" (top 5 bloqueantes + link "ver todas")
- Desabilitar botão **Recalcular** se `nao_simulavel` (com tooltip explicando o bloqueio)
- Listar premissas/ressalvas no card de resultado

**Critério de aceite:** usuário entende por que não pode simular antes de clicar.

---

### S4.6 — Auto-identificação Simples pós-cadastro (melhoria doc)

**Em** `ClienteController@store` e `PessoaController@store` (fornecedor):

- Se CNPJ 14 dígitos: disparar `BrasilApiService` em fila (`ConsultaSimplesJob`)
- Registrar pendência `SIMPLES_NAO_CONSULTADO` até conclusão

**Arquivos:**
- `app/Jobs/ConsultaSimplesJob.php`
- Ajuste em `app/Services/BrasilApiService.php` (idempotência)

**Critério de aceite:** novo cliente com CNPJ tem regime preenchido em até 30s (ou aviso de falha API).

---

## Sprint 5 — Governança: auditoria, versionamento e de-para

### S5.1 — Estender `simulacao_evento_log`

**Migration** para ampliar tipos e contexto:

```php
// novos tipos: parametro_alterado, cenario_alterado, pendencia_resolvida,
//              prontidao_recalculada, depara_alterado, origem_produto_alterada
$idusuario (nullable), idpessoa (nullable), justificativa (varchar 500)
```

**Criar** `app/Services/AuditoriaService.php`:

```php
public function registrar(string $tipo, Model $contexto, array $payload, ?string $justificativa = null): void;
```

**Instrumentar:**
- `ReformaCenarioController` — create/update/delete cenário
- `SimulacaoTributariaController::reformaUpdateParametros`
- `SimulacaoTributariaController::reformaUpdateProdutoOrigem`
- `PendenciaController@update`

**Critério de aceite:** toda alteração de parâmetro/cenário/origem gera log com usuário + timestamp.

---

### S5.2 — Versionamento de cenários e parâmetros

**Criar tabelas:**

```sql
reforma_cenario_versao (idcenario, versao, snapshot_json, idusuario, justificativa, created_at)
reforma_parametro_versao (idreforma, versao, snapshot_json, idusuario, justificativa, created_at)
```

**Alterar fluxo:**
- `ReformaCenarioService::salvar()` → insert versão antes de update
- `reforma_parametro` update → snapshot em `_versao`
- Toda `reforma_resultado` passa a gravar `versao_cenario` e `versao_parametro`

**UI:** dropdown "histórico de versões" em `admin/reforma/cenarios.blade.php` e aba parâmetros.

**Critério de aceite:** simulação de janeiro referencia versão X; alteração em fevereiro não retroativa.

---

### S5.3 — CRUD de-para (`simulacao_mapa_depara`)

**Criar** `app/Http/Controllers/Admin/MapaDeparaController.php`:

| Rota | Ação |
|------|------|
| `admin/depara` | index + filtros |
| `admin/depara/create` | formulário |
| `admin/depara/{id}` | update / destroy |

**Campos:** origem_sped, cfop, cst, ncm, destino_categoria, destino_tipo, prioridade, ativo.

**Criar** `app/Services/MapaDeparaResolver.php`:
- Dado item SPED (cfop, cst, ncm) → retorna categoria/tipo simulação
- Usado em `ReformaAnaliseService::syncProdutos` para grupo interno

**Migration:** adicionar `idtenant` em `simulacao_mapa_depara` (multi-tenant).

**Critério de aceite:** regra CFOP 5102 → categoria "produtos" reflete na agregação reforma.

---

### S5.4 — Justificativa obrigatória em alterações sensíveis

**Modal** de justificativa (mín. 10 caracteres) ao:
- Alterar origem de produto manualmente
- Alterar alíquota CBS/IBS fora do cenário padrão
- Marcar pendência como "ignorada"

**Critério de aceite:** request sem justificativa retorna 422; log contém texto.

---

### S5.5 — Tela de auditoria (admin)

**Criar** `admin/auditoria` — timeline filtrável por cliente, usuário, tipo, período.

**View:** `resources/views/admin/auditoria/index.blade.php`  
**Controller:** `AuditoriaController@index` lendo `simulacao_evento_log`.

**Critério de aceite:** diretor Maiore vê quem alterou alíquota e por quê.

---

## Sprint 6 — Confiabilidade, bloqueio e relatórios executivos

### S6.1 — Classificação de confiabilidade na simulação

**Adicionar em** `reforma_simulacao` (migration):

```php
confiabilidade (alta|media|baixa)
confiabilidade_motivos (json) // lista de premissas e pendências consideradas
versao_cenario, versao_parametro
```

**Criar** `app/Services/ConfiabilidadeService.php`:

| Nível | Regra v1 |
|-------|----------|
| `baixa` | prontidão `nao_simulavel` OU > 20% itens indefinidos OU fallback alíquota em > 30% base |
| `media` | prontidão `simulavel_ressalva` OU pendências ressalva > 0 |
| `alta` | prontidão `simulavel` E integridade ≥ 98% E zero ressalvas |

Chamar em `ReformaCalculoService` antes de persistir `reforma_resultado`.

**Critério de aceite:** export PDF/Excel exibe badge de confiabilidade + motivos.

---

### S6.2 — Bloqueio formal de simulação

**Em** `ReformaCalculoService::calcular()` e `SimulacaoTributariaController::reformaRecalcular`:

```php
if ($prontidao->classificacao === 'nao_simulavel') {
    throw new SimulacaoBloqueadaException($pendenciasBloqueantes);
}
```

- Simulação com ressalva: permitir, mas gravar `confiabilidade = media` e listar premissas
- Override admin: flag `forcar_simulacao` com justificativa auditada (só role ADMIN)

**Critério de aceite:** regra funcional doc §6 "pendência crítica bloqueia" implementada.

---

### S6.3 — Dashboard: qualidade do dado

**Em** `SimulacaoConsolidacaoService::dashboardAnalitico` adicionar série:

- % simulável / ressalva / não simulável (por valor operação ou por qtd produtos)
- Top 10 pendências bloqueantes (cross-mês)
- Evolução do score de prontidão (últimas N execuções de `simulacao_prontidao`)

**Views:** novos gráficos em `_consolidado.blade.php` + KPI cards.

**Critério de aceite:** dashboard responde "quanto do cliente é simulável?" em um gráfico.

---

### S6.4 — Relatório: Sumário Executivo (PDF, 1–2 páginas)

**Criar** `app/Services/RelatorioExecutivoService.php` + view `admin/simulacoes/export-executivo-pdf.blade.php`

**Conteúdo:**
1. Cliente, período, data, versão parâmetros
2. Prontidão (score + classificação + 3 bullets principais)
3. Impacto CBS/IBS agregado (R$ e % vs atual)
4. Confiabilidade + premissas
5. Top 5 pendências críticas + prazo estimado saneamento (heurística: 1–3 dias por bloqueante)
6. Disclaimer consultivo

**Rota:** `GET admin/simulacoes/{id}/export/executivo-pdf`

**Critério de aceite:** PDF gerado em < 10s para consolidado 12 meses; legível por diretor não técnico.

---

### S6.5 — Relatório: Pendências técnicas (PDF/Excel)

**Criar** `app/Services/RelatorioPendenciasService.php`

**Conteúdo:** todas pendências abertas + em revisão, agrupadas por tipo/criticidade, com ação recomendada e referência (cod_item, período, arquivo SPED).

**Rotas:**
- `GET admin/clientes/{id}/pendencias/export/pdf`
- `GET admin/clientes/{id}/pendencias/export/excel`

**Critério de aceite:** operacional do cliente consegue executar saneamento sem acesso ao sistema.

---

### S6.6 — Evolução antes/depois entre iterações

**Em** `simulacao_prontidao`: manter histórico (não sobrescrever — novo row por cálculo).

**UI no consolidado:** card "Evolução" comparando:
- 1ª importação vs última recalculada
- pendências resolvidas no período
- delta do score de prontidão
- delta impacto CBS/IBS

**Critério de aceite:** consultor demonstra ganho do saneamento em reunião com cliente.

---

### S6.7 — Ajustes nos exports existentes

**Atualizar** `ReformaExportService` e `SimulacaoConsolidadoExportService`:

- Cabeçalho com prontidão + confiabilidade
- Seção "Premissas e limitações"
- Referência `versao_cenario` / `versao_parametro`

**Critério de aceite:** Excel/PDF reforma atuais incluem qualidade do dado (regra doc §6).

---

## Sprint 7–8 — Piloto agro e estabilização (M4)

### S7.1 — Caso piloto: Lagoa Bonita / multi-filial

- Importar 12 meses × N filiais (SP/PR/MG/RS)
- Validar confronto em volume alto (performance: confronto < 60s para 50k itens)
- Ajustar regras com especialista fiscal Maiore

### S7.2 — Performance e filas

- `ConfrontoService` e `ProntidaoService` em `ShouldQueue` para imports grandes
- Índices: `sped_doc_item(idimport, cod_item)`, `simulacao_pendencia(idtenant, status, criticidade)`

### S7.3 — Completar parser SPED txt (bloco D)

- `SpedTxtParser`: adicionar `D500`, `D501` (paridade com `SpedExcelParser`)

### S7.4 — Documentação operacional

- Atualizar `docs/SIMPLES-NACIONAL-CONSULTA.md`
- Criar `docs/GUIA-CONSULTOR-PRONTIDADE.md` (fluxo comercial → entrega)

### S7.5 — Testes de aceite piloto

| # | Cenário | Resultado esperado |
|---|---------|-------------------|
| 1 | SPED com 5% itens sem 0200 | `nao_simulavel`, relatório lista bloqueantes |
| 2 | Após corrigir 0200 e reimportar | `simulavel_ressalva` ou `simulavel` |
| 3 | Alterar alíquota CBS manualmente | Log auditoria + versão parâmetro |
| 4 | Export sumário executivo | PDF 2 páginas com impacto e prontidão |
| 5 | Cliente Simples identificado | regime preenchido, pendência resolvida |

---

## Mapa de dependências

```mermaid
flowchart TD
    S31[S3.1 Migrations] --> S32[S3.2 Catálogo regras]
    S32 --> S33[S3.3 ConfrontoService]
    S33 --> S34[S3.4 Match cadastro]
    S33 --> S35[S3.5 Unidade/duplicidade]
    S33 --> S41[S4.1 ProntidaoService]
    S41 --> S43[S4.3 Widget prontidão]
    S33 --> S42[S4.2 Painel pendências]
    S42 --> S45[S4.5 Integração Reforma]
    S51[S5.1 Auditoria] --> S52[S5.2 Versionamento]
    S53[S5.3 De-para CRUD] --> S61[S6.1 Confiabilidade]
    S41 --> S61
    S61 --> S62[S6.2 Bloqueio simulação]
    S62 --> S64[S6.4 Sumário executivo]
    S42 --> S65[S6.5 Relatório pendências]
```

---

## Estimativa resumida

| Sprint | Tasks | Estimativa |
|--------|-------|------------|
| S3 | 6 | 8–10 dias |
| S4 | 6 | 8–10 dias |
| S5 | 5 | 7–9 dias |
| S6 | 7 | 9–12 dias |
| S7–S8 | 5 | 8–10 dias |
| **Total** | **29** | **~40–51 dias úteis** |

---

## Fora deste checklist (manter como roadmap fase 2)

- Integração SEFAZ / robô download NF-e
- Classificação fiscal por NCM como produto principal
- IA/N8n (orquestração externa) — preparar endpoint `POST /api/webhooks/confronto` quando necessário
- IBS municipal por IBGE
- Imposto Seletivo (IS)
- Dashboard multi-cliente executivo (todos tenants do escritório)

---

## Quick wins (podem antecipar S3)

1. Exibir contagem de `indefinido` na aba Reforma (1–2h)
2. Popular `simulacao_evento_log` em `reformaRecalcular` (2–3h)
3. Desabilitar recalcular se integridade < 90% — hardcode até ProntidaoService (1h)
4. Link "Identificar Simples" automático ao salvar cliente CNPJ (S4.6 antecipado)

---

*Documento gerado em 02/07/2026 · Revisar após cada sprint com status `[ ]` → `[x]`.*
