# Plano do Projeto e Homologacao

Data: 08/07/2026

## Objetivo

Construir um motor de leitura e sincronizacao de NFS-e/DF-e do Ambiente de Dados Nacional (ADN), com foco inicial em operacao por municipio, gravando os documentos em um banco MySQL 5.6 novo, proprio do motor.

O sistema legado nao deve ser reescrito. A primeira versao deve criar uma camada nova de dados `nfse_*`, que pode ser consultada depois pelo CodeIgniter ou por outro modulo.

## Estado atual do projeto

Ja existe:

- proposta tecnica/comercial em `proposta-motor-leitura-nfse.md`;
- mapa de documentacao oficial em `doc-map.md`;
- migration inicial em `migrations/001_create_nfse_tables.sql`;
- base local mock em `mock.sql`;
- Docker local com MySQL em `docker/`;
- scripts de smoke test em `scripts/`;
- documentacao sobre certificados, posse do certificado, processamento paralelo e homologacao.

Ainda nao existe:

- worker Python real;
- cliente real da API ADN;
- parser definitivo dos XMLs;
- rotina real de criptografia/descriptografia da senha do certificado;
- instalador final para VPS sem Docker;
- integracao com a base oficial do cliente;
- certificado real/autorizado para homologacao.

## Decisoes tecnicas atuais

- Linguagem: Python 3.12.
- Banco: MySQL 5.6 novo, proprio do motor.
- Producao: rodar direto na VPS, sem Docker obrigatorio.
- Local: Docker Compose apenas para desenvolvimento.
- Certificado: A1 `.pfx`.
- Certificado A1: criptografado no banco novo.
- Senha do certificado: criptografada no banco novo.
- Chave mestra: fora do banco, por exemplo `NFSE_MASTER_KEY`.
- Concorrencia: paralelismo entre municipios; processamento sequencial dentro do mesmo municipio.

## Modelo de banco proposto

Tabelas novas:

- `nfse_municipios`;
- `nfse_certificados`;
- `nfse_sync_state`;
- `nfse_documentos`;
- `nfse_eventos`;
- `nfse_sync_logs`.

Essas tabelas foram criadas separadas para reduzir risco sobre o sistema legado.

## E se ja existir tabela de municipios no banco oficial?

E provavel que exista. Quando o banco oficial chegar, nao devemos assumir que a tabela `nfse_municipios` sera a fonte final de municipios.

Existem tres caminhos possiveis:

### Opcao A: manter `nfse_municipios` como tabela tecnica

Usar `nfse_municipios` apenas para os municipios habilitados para o motor NFS-e.

Vantagens:

- Menor acoplamento com o legado.
- Migration atual funciona sem depender da estrutura existente.
- Permite habilitar apenas municipios que terao certificado/autorizacao.

Quando usar:

- Se a tabela legada de municipios nao tiver codigo IBGE confiavel.
- Se a tabela legada tiver muitos registros que nao devem ser processados.
- Se nao quisermos criar dependencia direta com modelo antigo.

### Opcao B: referenciar a tabela legada

Adaptar `nfse_municipios` para guardar uma referencia ao municipio legado, por exemplo `legacy_municipio_id`.

Vantagens:

- Mantem vinculo claro com cadastros existentes.
- Facilita telas/relatorios no sistema legado.

Quando usar:

- Se a tabela legada for limpa e tiver codigo IBGE.
- Se a aplicacao CodeIgniter ja usa essa tabela como fonte principal.

Possivel ajuste de migration:

```sql
ALTER TABLE nfse_municipios
  ADD COLUMN legacy_municipio_id BIGINT UNSIGNED NULL,
  ADD KEY idx_nfse_municipios_legacy (legacy_municipio_id);
```

### Opcao C: nao criar `nfse_municipios`

Usar diretamente a tabela legada como fonte de municipios e criar apenas tabelas `nfse_*` auxiliares apontando para ela.

Vantagens:

- Evita duplicidade de municipios.

Riscos:

- Acopla o motor a uma tabela que ainda nao conhecemos.
- Dificulta testar antes de receber a base.
- Pode exigir alteracoes em varias tabelas `nfse_*`.

Recomendacao atual: comecar pela Opcao A e, depois de ler a base oficial, decidir se vale migrar para Opcao B. Nao recomendo Opcao C antes de conhecer bem a estrutura legada.

## Quando o banco oficial chegar

### 1. Nao alterar nada de imediato

Primeiro abrir uma copia ou ambiente de teste. Nao aplicar migration diretamente em producao sem backup e validacao.

### 2. Levantar metadados

Coletar:

```sql
SELECT VERSION();
SELECT DATABASE();
SHOW TABLES;
SHOW VARIABLES LIKE 'character_set_database';
SHOW VARIABLES LIKE 'collation_database';
```

Para tabelas candidatas de municipio:

```sql
SHOW COLUMNS FROM nome_da_tabela;
SHOW INDEX FROM nome_da_tabela;
SELECT * FROM nome_da_tabela LIMIT 20;
```

Procurar campos como:

- codigo IBGE;
- nome do municipio;
- UF;
- status ativo/inativo;
- CNPJ do municipio/prefeitura;
- relacionamento com usuarios, empresas ou orgaos.

### 3. Mapear conflitos

Verificar se ja existem tabelas com prefixo `nfse_`:

```sql
SHOW TABLES LIKE 'nfse_%';
```

Se existir conflito de nome, revisar a migration antes de aplicar.

### 4. Decidir fonte de municipios

Com base na tabela legada:

- manter `nfse_municipios` independente;
- ou adicionar `legacy_municipio_id`;
- ou adaptar o desenho.

### 5. Aplicar migration em teste

Rodar:

```sh
mysql -h HOST -u USER -p DATABASE < migrations/001_create_nfse_tables.sql
```

Validar:

```sql
SHOW TABLES LIKE 'nfse_%';
DESCRIBE nfse_certificados;
DESCRIBE nfse_sync_state;
DESCRIBE nfse_documentos;
```

### 6. Cadastrar municipios reais

Inserir apenas municipios que serao processados pelo motor.

Campos minimos:

- codigo IBGE;
- nome;
- UF;
- ambiente (`producao_restrita` primeiro);
- perfil (`municipio`);
- ativo.

### 7. Cadastrar certificados

Para cada municipio:

- certificado `.pfx` criptografado;
- senha criptografada;
- algoritmo;
- `senha_key_id`;
- validade;
- status ativo.

O arquivo `.pfx` pode ser usado no cadastro/smoke test, mas na versao final fica armazenado no banco como blob criptografado.

### 8. Configurar chave mestra

Configurar fora do banco:

```text
NFSE_MASTER_KEY=...
```

Essa chave abre as senhas criptografadas dos certificados. Ela nao pode ser salva no mesmo banco.

## Teste sem certificado

Sem certificado real, o que da para homologar:

- endpoints oficiais respondem e exigem certificado cliente;
- migration do banco;
- dados mock;
- leitura de configuracao de municipios/certificados;
- certificado A1 mock;
- fluxo local de extracao de certificado/chave;
- simulacao de workers paralelos;
- logs;
- parser XML com arquivos mock;
- validacao contra XSD, quando os XSDs forem baixados.

Comandos atuais:

```sh
./scripts/smoke_endpoints_sem_cert.sh
./scripts/check_db_mock.sh
./scripts/listar_certificados_configurados.sh
./scripts/gerar_certificado_mock.sh 3550308 mock123
PFX_PASSWORD='mock123' ./scripts/test_certificado_homolog.sh certificados/municipios/3550308/certificado.pfx
python3 scripts/simular_workers.py --concurrency 4 --ciclos 3
```

Resultado ja observado:

```text
ADN producao restrita sem certificado: HTTP 496
Certificado mock contra ADN: HTTP 495 SSL Certificate Error
```

Interpretacao:

- `496`: servidor exige certificado cliente.
- `495`: certificado foi enviado, mas e invalido/nao autorizado.

Isso prova o requisito de mTLS, mas nao homologa consumo real.

## Teste com certificado real

Pre-requisitos:

- certificado digital A1 `.pfx` do municipio/prefeitura ou certificado autorizado formalmente;
- senha do certificado para cadastro criptografado;
- chave mestra configurada fora do banco;
- municipio cadastrado;
- certificado vinculado ao municipio;
- acesso ao ambiente de producao restrita.

Smoke test inicial:

```sh
PFX_PASSWORD='senha-real' ./scripts/test_certificado_homolog.sh /caminho/certificado.pfx
```

Esse script ainda recebe a senha em env apenas para smoke test manual. No worker real, a senha vira do banco criptografada e sera aberta com `NFSE_MASTER_KEY`.

Resultado esperado:

- se o certificado estiver valido e autorizado: HTTP 2xx/3xx ou resposta da API/Swagger;
- se o certificado nao for aceito: erro 495 ou erro de autorizacao;
- se faltar certificado: erro 496.

Depois do smoke test:

1. Implementar cliente real da API ADN.
2. Consultar distribuicao por NSU em producao restrita.
3. Gravar XML bruto em `nfse_documentos` ou `nfse_eventos`.
4. Atualizar `nfse_sync_state.last_nsu`.
5. Registrar logs.
6. Repetir com um municipio apenas.
7. Aumentar para mais municipios com concorrencia baixa.

## Como ficam os consumos depois da primeira instalacao

Depois de instalado:

```text
worker inicia
  busca municipios ativos
  para cada municipio:
    busca certificado vinculado
    busca .pfx criptografado no banco
    busca senha criptografada no banco
    descriptografa PFX e senha com NFSE_MASTER_KEY
    abre certificado em memoria
    le last_nsu
    consulta ADN
    grava documentos/eventos
    atualiza last_nsu
    registra logs
  aguarda proximo ciclo
```

Nao e necessario informar certificado/senha em cada consumo.

## O que falta fazer

### Banco e configuracao

- Ler a base oficial do cliente.
- Identificar tabela legada de municipios.
- Decidir Opcao A ou B para municipios.
- Ajustar migration se necessario.
- Criar migration complementar se houver `legacy_municipio_id`.
- Definir rotina para cadastrar senha criptografada.

### Seguranca

- Implementar criptografia real da senha do `.pfx`, preferencialmente AES-256-GCM.
- Definir formato do payload criptografado.
- Gerar e validar `NFSE_MASTER_KEY`.
- Documentar permissao de arquivos em VPS.
- Definir politica de rotacao de chave/certificado.

### Motor Python

- Criar estrutura do projeto Python.
- Criar loader de configuracao.
- Criar repositorios de banco.
- Criar leitor de certificado A1.
- Criar cliente HTTP mTLS.
- Criar cliente ADN.
- Criar parser XML.
- Criar persistencia de documentos/eventos.
- Criar controle de lock por municipio.
- Criar loop/scheduler.
- Criar logs estruturados.

### Homologacao

- Rodar smoke sem certificado.
- Rodar smoke com certificado A1 real.
- Testar um municipio em producao restrita.
- Validar `last_nsu`.
- Validar XML bruto salvo.
- Validar campos principais extraidos.
- Validar retentativa e erro.

### Producao

- Criar script de instalacao para VPS sem Docker.
- Criar exemplo de servico `systemd`.
- Criar `.env` de exemplo para producao.
- Criar rotina de backup/restore das tabelas `nfse_*`.
- Definir monitoramento minimo.

## Perguntas em aberto para o cliente/prefeitura

- Qual e a tabela legada de municipios?
- Ela possui codigo IBGE confiavel?
- Quais municipios entram no MVP?
- O certificado sera A1?
- O certificado e do municipio/prefeitura e esta autorizado na producao restrita?
- Quem sera responsavel por colocar o `.pfx` na VPS?
- Quem sera responsavel por configurar `NFSE_MASTER_KEY`?
- Havera ambiente de teste separado do banco legado?
- O cliente aceita que as primeiras tabelas sejam independentes `nfse_*`?
- Existe alguma politica interna para armazenamento de certificado digital?
