Instalação

Pré-requisitos, onde o certificado A1 fica e como rodar.

Pré-requisitos

FerramentaPara quêComo ter
Go 1.26compilar o binárioo flake.nix traz, ou go.dev/dl
Taskas tasks do Taskfile.yamlflake, ou taskfile.dev
Tailwind CSS v4 standaloneo CSS do painel (sem Node)task css chama por nix shell; sem Nix, o binário tailwindcss no PATH
openssl, libxml2conferir o .pfx; validar a DPS no XSDflake
passopcional: guardar o certificado fora do bancosó no modo "certificado no pass"

Com Nix: nix develop abre um shell com tudo. Docker não é usado no desenvolvimento — só a imagem do deploy.

Onde o certificado A1 fica: dois modos

ModoLiga comComo o certificado entraBom para
Cofre no banco (recomendado)NFSE_CERT_KEY definida (32 bytes em base64: openssl rand -base64 32)pelo painel, em Configurações → Certificado; .pfx e senha selados juntos com AES-256-GCMservidor, várias contas, quem não usa pass
passNFSE_CERT_KEY vaziatask cert:import -- "<arquivo>.pfx" grava em pass (prefixo NFSE_PASS_PREFIX, padrão bassi/nfse)uma conta só, na máquina do dono

⚠️ Guarde a NFSE_CERT_KEY num cofre: perdê-la deixa os certificados selados ilegíveis (cada conta reenvia o .pfx) e obriga a informar de novo a senha de app do Gmail.

Rodar

task build                  # gera o CSS e compila bin/nfse
task serve                  # painel em http://127.0.0.1:8735 (SQLite local, SEFIN real)
task cert:check             # (modo pass) confere titular e validade do A1

O painel local escuta só em 127.0.0.1. Banco: ~/.local/share/nfse-digital/nfse.db (ou --db/NFSE_DB; uma URL libsql:// usa o Turso). Passkeys exigem abrir por http://localhost:8735 (o WebAuthn não aceita IP).

TaskO que faz
cssgera static/app.css com o Tailwind standalone (sem Node)
buildbin/nfse
testtodos os testes
test:covgate de cobertura (seção 10)
test:tursoexclusão de conta contra o Turso real, com conta descartável
e2eponta a ponta no SQLite: cria conta e emitente, emite, reinicia e confere que nada se perdeu
xsd:checkvalida a DPS de referência no XSD oficial com xmllint
smoke:homologationemite R$ 1,00 na homologação com o A1 real (NFSE_SMOKE_TAKER=<CNPJ do tomador>)
servesobe o painel local
deploypublica no Fly (seção 11)
api:smokeAPI REST no binário real: banco temporário, token gerado pela tela, 23 checagens (sem SEFIN)
sdk:generate · sdk:check · sdk:smokeregera os SDKs Go/Python/TypeScript do openapi.json · reprova SDK fora do contrato · roda os três contra o binário real
email:smokeenvio por e-mail no binário real contra o Mailpit: 19 checagens, sem Gmail (KEEP=1 deixa no ar)
dnsCNAME no Cloudflare
cancelcancela pela CLI uma nota do painel publicado (task cancel -- <id> --production)
nfse:xmlbaixa da SEFIN o XML de uma NFS-e pela chave (task nfse:xml -- <chave> [--production])
diagramregenera docs/diagram (HTML + PNG claro e escuro)

Nesta página