Skip to main content Integrações SEFAZ (NF-e/CT-e/MDF-e) no padrão FiscalZen: DistDFe, Manifestação e eventos — com certificados A1, SOAP, retry/backoff e persistência no produto.
npx skills add majiayu000/claude-skill-registry --skill "Fiscalzen SEFAZ" 🏗️ Contexto do Projeto (como o FiscalZen é estruturado)
Monorepo com pnpm-workspace + Turborepo
Código em TypeScript (ESM "type": "module")
Backend: Fastify 4 (apps/api)
Jobs: BullMQ (workers + scheduler)
Persistência: Drizzle ORM + PostgreSQL
Cache/queues: Redis
Logging: Pino
Pacote fiscal principal: @fiscalzen/sefaz-client (NF-e/CT-e/MDF-e)
Parser fiscal: @fiscalzen/xml-parser (usado pelo sefaz-client e api)
✅ Regra: alterações de SEFAZ geralmente tocam packages/ (cliente) e/ou apps/api/ (orquestração + persistência).
🎯 Objetivo (o que esta skill resolve)
Aplicar mudanças relacionadas a SEFAZ mantendo consistência com a codebase:
Preferir abstrações internas (@fiscalzen/sefaz-client) em vez de reimplementar SOAP/assinatura/certificado
Validar certificado e permissões no backend antes de chamar SEFAZ
Respeitar retry/backoff e throttling
Persistir eventos e atualizar documentos do jeito do produto
Garantir validação (unit/integration + homolog)
🧭 Onde mexer (mapa rápido)
Cliente SEFAZ (packages/sefaz-client)
packages/sefaz-client/src/client.ts → política de timeout/retry/backoff, https.Agent, dispose(), logging
packages/sefaz-client/src/soap-client.ts + src/soap/envelope.ts → SOAP + envelope
packages/sefaz-client/src/services/* → implementações por domínio:
nfe-distdfe.ts (DistDFe NF-e)
cte-distdfe.ts, mdfe-distdfe.ts (DistDFe CT-e/MDF-e)
manifestacao.ts (eventos do destinatário)
Produto (apps/api)
apps/api/src/modules/manifestacao/service.ts → fluxo real de manifestação + persistência
apps/api/src/modules/certificates/* → validação de certificados (gate antes de SEFAZ)
apps/api/src/modules/documents/* → documento + status/manifestações
apps/api/src/jobs/queues.ts → criação/agenda de jobs SEFAZ
apps/api/src/modules/nsu/* + packages/database/src/schema/nsu-control.ts → controle de NSU/sync
✅ Regras obrigatórias (gates)
1) Sempre validar certificado antes de chamar SEFAZ (no produto)
Se a chamada vier do apps/api, não chame SEFAZ sem passar pelo gate :
empresa existe
company.certificate e company.certificatePassword existem
certificado não expirou
(se aplicável) tenantId correto (multi-tenant)
2) Não vazar segredo (PFX/senha)
nunca logar senha do certificado
nunca logar buffer do PFX
ao logar erro, sanitize campos sensíveis
3) TLS estrito
não desabilitar validação TLS (rejectUnauthorized)
4) Erros externos padronizados
No apps/api, problemas da SEFAZ devem virar erro de serviço externo (padrão do projeto), mantendo mensagem útil.
🔁 Retry/Backoff e Throttling (padrão FiscalZen)
Ponto único de política: packages/sefaz-client/src/client.ts
✅ Regra: se você precisar mudar retry/backoff/timeout, faça no client (não espalhe retry pelos services).
Throttling (ex.: cStat 656)
Recomendação de implementação consistente:
tratar como erro recuperável
aplicar retry com backoff exponencial + jitter
evitar tempestade: preferir job/queue para processar em série por empresa/UF
📦 DistDFe (Golden Path) — como fazer no FiscalZen
Cenários típicos
Consulta por último NSU (sync contínuo)
Consulta por NSU específico
Consulta por chave (pontual)
Padrão de implementação
Validar parâmetros (CNPJ, chave, nsu/ultNSU)
Montar request XML conforme tipo de consulta
Enviar via SoapClient / SefazClient (abstração interna)
Parsear retorno (cStat/xMotivo/ultNSU/maxNSU)
Extrair docZip e:
decodificar
detectar schema
derivar tipo/chave usando @fiscalzen/xml-parser
Retornar DistDFeResponse consistente
Se estiver no produto (apps/api): persistir e atualizar controle de NSU
Regras de robustez
nsu e ultNSU sempre como string com 15 dígitos (padStart(15,'0'))
docZip inválido não deve derrubar o lote inteiro (registrar erro e seguir)
ao tratar throttling, preferir política central no client
🧾 Manifestação do Destinatário (Golden Path) — padrão do produto
Passo a passo (apps/api)
obter empresa com certificado (gate)
buscar documento por chave com tenantId
montar CertificadoA1 no formato do @fiscalzen/sefaz-client
usar env.SEFAZ_AMBIENTE
chamar o client do pacote
se sucesso=false: lançar ExternalServiceError('SEFAZ', xMotivo)
persistir em documentEvents + atualizar documents.manifestacao
Regras específicas
eventos devem ser idempotentes na camada do produto (não duplicar o mesmo evento sem necessidade)
manter rastreabilidade (documentId/chave/tipoEvento/protocolo/dataRegistro)
🧪 Validação (Fase V) — mínimo obrigatório
Unit / pacote (sefaz-client)
validar validateParams (CNPJ/chave)
validar montagem de request por ultNSU/nsu/chave
validar parsing de resposta (cStat e campos)
validar docZip: sucesso e falha isolada
Integration / produto (apps/api)
empresa sem certificado → erro de validação
certificado expirado → erro de validação
documento inexistente → NotFound
retorno sucesso=false da SEFAZ → ExternalServiceError
persistência: criou event + atualizou documento
Homologação
testar ao menos:
DistDFe por ultNSU
Manifestação (um evento)
cenário de throttling (se possível reproduzir)
🧰 Prompt templates (como invocar a skill)
Manifestação (produto)
“Aplique a skill fiscalzen-sefaz para ajustar o fluxo de manifestação em apps/api.
Preserve o gate de certificado + multi-tenant e mapeie falhas SEFAZ para erro externo padrão. Atualize persistência em documentEvents e documents.manifestacao.”
DistDFe (pacote)
“Aplique a skill fiscalzen-sefaz para modificar packages/sefaz-client/src/services/nfe-distdfe.ts.
Preserve validações, padStart(15) e parsing docZip com @fiscalzen/xml-parser. Se tratar 656, preferir política central no client.”
event-query.ts (consulta eventos)
cte-events.ts (eventos CT-e)
packages/sefaz-client/src/types.ts → contratos + erros tipados (SefazError, TimeoutError, CertificadoError, etc.)
packages/sefaz-client/src/certificate.ts → A1 (PFX), cache/invalidação, validações
packages/sefaz-client/src/signature.ts → digest/assinatura (helpers)Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
CLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
CLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).