ghinfe 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.env.example +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +413 -0
  4. package/docs/developer-guide.html +421 -0
  5. package/docs/openapi.yaml +428 -0
  6. package/examples/emitir-nfce.js +51 -0
  7. package/examples/emitir-nfe.js +83 -0
  8. package/examples/emitir-nfse.js +46 -0
  9. package/examples/endpoints-sefaz.js +14 -0
  10. package/examples/eventos-nfe.js +49 -0
  11. package/examples/gerar-chave.js +25 -0
  12. package/examples/gerar-danfe.js +75 -0
  13. package/examples/layouts-nfse.js +51 -0
  14. package/examples/mock-sefaz.js +52 -0
  15. package/examples/nfse-eventos.js +57 -0
  16. package/examples/reforma-ibscbs.js +27 -0
  17. package/examples/reforma-nfe-xml.js +52 -0
  18. package/examples/status-sefaz.js +12 -0
  19. package/examples/validar-xsd.js +48 -0
  20. package/package.json +68 -0
  21. package/schemas/nfe/PL_009_V4/consReciNFe_v4.00.xsd +9 -0
  22. package/schemas/nfe/PL_009_V4/consSitNFe_v4.00.xsd +9 -0
  23. package/schemas/nfe/PL_009_V4/consStatServ_v4.00.xsd +9 -0
  24. package/schemas/nfe/PL_009_V4/enviNFe_v3.10.xsd +9 -0
  25. package/schemas/nfe/PL_009_V4/enviNFe_v4.00.xsd +9 -0
  26. package/schemas/nfe/PL_009_V4/inutNFe_v4.00.xsd +9 -0
  27. package/schemas/nfe/PL_009_V4/leiauteNFe_v4.00.xsd +7339 -0
  28. package/schemas/nfe/PL_009_V4/nfe_v4.00.xsd +9 -0
  29. package/schemas/nfe/PL_009_V4/tiposBasico_v4.00.xsd +598 -0
  30. package/schemas/nfe/PL_009_V4/xmldsig-core-schema_v1.01.xsd +98 -0
  31. package/scripts/download-schemas.js +39 -0
  32. package/scripts/test-xsd.js +34 -0
  33. package/src/api/server.js +316 -0
  34. package/src/constants/sefaz.js +69 -0
  35. package/src/danfe/DanfeService.js +205 -0
  36. package/src/danfe/xml-extract.js +69 -0
  37. package/src/errors/GhinfeError.js +13 -0
  38. package/src/errors/SefazError.js +25 -0
  39. package/src/errors/XsdValidationError.js +15 -0
  40. package/src/index.js +60 -0
  41. package/src/nfce/builders/NFCeXmlBuilder.js +178 -0
  42. package/src/nfce/constants/qrcode.js +26 -0
  43. package/src/nfce/services/NFCeService.js +188 -0
  44. package/src/nfce/services/NFCeXmlService.js +38 -0
  45. package/src/nfce/types/NFCeDocument.js +42 -0
  46. package/src/nfce/utils/qrcode.utils.js +92 -0
  47. package/src/nfe/builders/NFeEventoXmlBuilder.js +110 -0
  48. package/src/nfe/builders/NFeXmlBuilder.js +215 -0
  49. package/src/nfe/mocks/sefaz-responses.js +195 -0
  50. package/src/nfe/services/NFeEventoService.js +95 -0
  51. package/src/nfe/services/NFeService.js +196 -0
  52. package/src/nfe/services/NFeSignService.js +111 -0
  53. package/src/nfe/services/NFeSoapService.js +437 -0
  54. package/src/nfe/services/NFeXmlService.js +41 -0
  55. package/src/nfe/services/NFeXsdService.js +56 -0
  56. package/src/nfe/types/NFeDocument.js +92 -0
  57. package/src/nfe/types/NFeEvento.js +44 -0
  58. package/src/nfse/NFSeMunicipioResolver.js +42 -0
  59. package/src/nfse/builders/NFSeEventoXmlBuilder.js +92 -0
  60. package/src/nfse/builders/NFSeXmlBuilder.js +16 -0
  61. package/src/nfse/constants/municipios.js +82 -0
  62. package/src/nfse/layouts/adapters.js +202 -0
  63. package/src/nfse/mocks/nfse-responses.js +142 -0
  64. package/src/nfse/services/NFSeService.js +191 -0
  65. package/src/nfse/services/NFSeSoapService.js +232 -0
  66. package/src/nfse/services/NFSeXmlService.js +12 -0
  67. package/src/nfse/types/NFSeDocument.js +54 -0
  68. package/src/queue/NFCeQueue.js +63 -0
  69. package/src/queue/NFSeQueue.js +59 -0
  70. package/src/queue/NFeQueue.js +76 -0
  71. package/src/reforma/ibscbs.js +175 -0
  72. package/src/sefaz/SefazEndpointResolver.js +95 -0
  73. package/src/sefaz/endpoints.registry.js +205 -0
  74. package/src/shared/fiscal.helpers.js +53 -0
  75. package/src/utils/certificate.utils.js +47 -0
  76. package/src/utils/chave.utils.js +117 -0
  77. package/src/utils/date.utils.js +26 -0
  78. package/src/utils/xml.utils.js +44 -0
  79. package/src/validation/XsdValidator.js +114 -0
  80. package/src/validation/schemas.js +14 -0
package/.env.example ADDED
@@ -0,0 +1,15 @@
1
+ # Redis (Bull queue)
2
+ REDIS_HOST=127.0.0.1
3
+ REDIS_PORT=6379
4
+ # REDIS_PASSWORD=
5
+
6
+ # API de testes / Swagger
7
+ PORT=3333
8
+
9
+ # SEFAZ (produção — use com cuidado)
10
+ # SEFAZ_MOCK=true
11
+ # SEFAZ_ENDPOINT=https://homologacao.nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx
12
+
13
+ # Certificado A1
14
+ # PFX_PATH=./certs/certificado.pfx
15
+ # PFX_PASSWORD=
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Victor Henrique Ghilardi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,413 @@
1
+ # GHINFE
2
+
3
+ Biblioteca Node.js para emissão de documentos fiscais eletrônicos brasileiros: **NF-e**, **NFC-e** e **NFS-e**.
4
+
5
+ Inspirada na filosofia do [ACBr](https://projetoacbr.com.br/) (objeto de domínio → XML → assinatura → envio SEFAZ), a GHINFE separa responsabilidades em serviços modulares, prontos para integração com **Sequelize**, filas **Bull/Redis** e ambientes de alta escala.
6
+
7
+ ## Funcionalidades (v0.6)
8
+
9
+ | Módulo | Status |
10
+ |--------|--------|
11
+ | Geração XML NF-e / NFC-e / NFS-e | ✅ |
12
+ | IBS/CBS injetado no XML NF-e (item + totais) | ✅ experimental |
13
+ | Cancelamento e substituição NFS-e | ✅ |
14
+ | DANFE / DANFCE (HTML imprimível) | ✅ |
15
+ | Assinatura A1, XSD, multi-UF, filas Bull | ✅ |
16
+ | Injeção completa conforme XSD PL_010 estável | 🔜 |
17
+
18
+ ## Estrutura de pastas
19
+
20
+ ```
21
+ ghinfe/
22
+ ├── docs/
23
+ │ ├── openapi.yaml # Especificação Swagger/OpenAPI
24
+ │ └── developer-guide.html # Guia completo para desenvolvedores
25
+ ├── examples/
26
+ │ ├── emitir-nfe.js # Exemplo de geração + mock
27
+ │ └── mock-sefaz.js # Cenários de retorno SEFAZ
28
+ ├── src/
29
+ │ ├── api/
30
+ │ │ └── server.js # Servidor Express + Swagger UI
31
+ │ ├── constants/
32
+ │ │ └── sefaz.js # UF, cStat, URLs, versão layout
33
+ │ ├── errors/
34
+ │ │ ├── GhinfeError.js
35
+ │ │ └── SefazError.js # Erros reais da SEFAZ (cStat)
36
+ │ ├── nfe/
37
+ │ │ ├── builders/
38
+ │ │ │ ├── NFeXmlBuilder.js
39
+ │ │ │ └── NFeEventoXmlBuilder.js # Cancelamento, CC-e
40
+ │ │ ├── mocks/
41
+ │ │ │ └── sefaz-responses.js
42
+ │ │ ├── services/
43
+ │ │ │ ├── NFeXmlService.js
44
+ │ │ │ ├── NFeSignService.js
45
+ │ │ │ ├── NFeSoapService.js
46
+ │ │ │ ├── NFeEventoService.js # Eventos SEFAZ
47
+ │ │ │ └── NFeService.js
48
+ │ │ └── types/
49
+ │ │ ├── NFeDocument.js
50
+ │ │ └── NFeEvento.js
51
+ │ ├── sefaz/
52
+ │ │ ├── endpoints.registry.js # URLs por autorizador (SVRS, SP, MG...)
53
+ │ │ └── SefazEndpointResolver.js
54
+ │ ├── nfse/
55
+ │ │ ├── builders/NFSeXmlBuilder.js
56
+ │ │ ├── services/ # NFSeService, NFSeSoapService
57
+ │ │ └── NFSeMunicipioResolver.js
58
+ │ ├── queue/
59
+ │ │ ├── NFeQueue.js
60
+ │ │ ├── NFCeQueue.js
61
+ │ │ └── NFSeQueue.js
62
+ │ ├── utils/
63
+ │ │ ├── certificate.utils.js
64
+ │ │ ├── chave.utils.js # Chave de acesso + DV
65
+ │ │ ├── date.utils.js
66
+ │ │ └── xml.utils.js
67
+ │ └── index.js # Exports públicos
68
+ ├── .env.example
69
+ └── package.json
70
+ ```
71
+
72
+ ## Instalação
73
+
74
+ ```bash
75
+ npm install
76
+ cp .env.example .env
77
+ npm run schemas:download # baixa XSDs se necessário (já inclusos em schemas/)
78
+ ```
79
+
80
+ ## Uso rápido
81
+
82
+ ### 1. Montar o objeto e gerar XML (chave automática)
83
+
84
+ ```javascript
85
+ import { NFeService } from 'ghinfe';
86
+
87
+ const service = new NFeService();
88
+
89
+ const documento = {
90
+ // chaveAcesso é opcional — gerada automaticamente
91
+ ambiente: 2,
92
+ ide: { uf: 'SP', codigoMunicipio: '3550308', serie: 1, numero: 1 },
93
+ emitente: { cnpj: '12345678000199', /* ... */ },
94
+ destinatario: { /* ... */ },
95
+ itens: [{ /* ... */ }],
96
+ };
97
+
98
+ const xml = service.gerarXml(documento);
99
+ ```
100
+
101
+ ### 1b. Gerar chave de acesso manualmente
102
+
103
+ ```javascript
104
+ import { gerarChaveAcesso, validarChaveAcesso } from 'ghinfe';
105
+
106
+ const chave = gerarChaveAcesso({
107
+ uf: 'SP',
108
+ cnpj: '12345678000199',
109
+ serie: 1,
110
+ numero: 42,
111
+ });
112
+ console.log(validarChaveAcesso(chave)); // true
113
+ ```
114
+
115
+ ### Endpoints SEFAZ automáticos (multi-UF)
116
+
117
+ ```javascript
118
+ import { SefazEndpointResolver, NFeService } from 'ghinfe';
119
+
120
+ // Por UF — resolve autorizador (SVRS, SP, MG...) automaticamente
121
+ const urls = SefazEndpointResolver.paraNFe('RJ', 2); // homologação
122
+ console.log(urls.endpoint);
123
+
124
+ // No serviço — basta informar UF
125
+ const service = new NFeService({ mock: false, uf: 'SP', ambiente: 2 });
126
+
127
+ // Ou configurar em runtime a partir do documento
128
+ service.configurarUf('MG', 2);
129
+ ```
130
+
131
+ ### NFS-e (layouts municipais)
132
+
133
+ ```javascript
134
+ import { NFSeService, NFSE_LAYOUTS, NFSeMunicipioResolver } from 'ghinfe';
135
+
136
+ // Layout explícito ou automático pelo município
137
+ const service = new NFSeService({ mock: true, layout: NFSE_LAYOUTS.GINFES });
138
+ const xml = service.gerarXml(documento);
139
+
140
+ // Assinatura A1 do RPS
141
+ const xmlAssinado = service.gerarXmlAssinado(documento, { pfx, senha });
142
+
143
+ // Emissão com assinatura opcional
144
+ const resultado = await service.emitir(documento, { pfx, senha });
145
+ ```
146
+
147
+ Layouts: `abrasf`, `ginfes`, `betha`, `issnet` — municípios pré-cadastrados em SP, RJ, BH, Curitiba, POA, Floripa, Salvador, Recife, Fortaleza.
148
+
149
+ ### Consulta status SEFAZ
150
+
151
+ ```javascript
152
+ const service = new NFeService({ mock: true });
153
+ const status = await service.consultarStatus('SP', 2);
154
+ // { emOperacao: true, cStat: '107', xMotivo: 'Serviço em Operação', tMed: '1' }
155
+ ```
156
+
157
+ ### Reforma tributária (IBS/CBS no XML)
158
+
159
+ ```javascript
160
+ import { NFeService, calcularIBSCBS } from 'ghinfe';
161
+
162
+ const item = {
163
+ codigo: '001', descricao: '...', ncm: '...', cfop: '5102',
164
+ unidade: 'UN', quantidade: 1, valorUnitario: 100, valorTotal: 100,
165
+ reforma: calcularIBSCBS(100, { pIBSUF: 0.1, pIBSMun: 0.05, pCBS: 0.9 }),
166
+ };
167
+
168
+ const xml = service.gerarXml({ ...documento, itens: [item] });
169
+ // XML contém <IBSCBS> no item e <IBSCBSTot> nos totais
170
+ // Não use validarXsd:true com reforma até o schema PL_010 estar embutido
171
+ ```
172
+
173
+ ### Cancelamento / substituição NFS-e
174
+
175
+ ```javascript
176
+ await service.cancelar({
177
+ numeroNfse: '2026000001',
178
+ cnpjPrestador: '...',
179
+ inscricaoMunicipal: '...',
180
+ codigoMunicipio: '3550308',
181
+ });
182
+
183
+ await service.substituir({
184
+ numeroNfseSubstituida: '2026000001',
185
+ cnpjPrestador: '...',
186
+ inscricaoMunicipal: '...',
187
+ codigoMunicipio: '3550308',
188
+ documentoSubstituto: { /* novo RPS */ },
189
+ });
190
+ ```
191
+
192
+ ### DANFE / DANFCE
193
+
194
+ ```javascript
195
+ import { DanfeService } from 'ghinfe';
196
+
197
+ const danfe = new DanfeService();
198
+ const { html } = await danfe.gerarDanfe(xmlNfe, { protocolo: '...' });
199
+ const { html: cupom } = await danfe.gerarDanfce(xmlNfce, { qrCodeUrl: '...' });
200
+ // Salve o HTML e imprima / “Salvar como PDF” no navegador
201
+ ```
202
+
203
+ ### Consulta status SEFAZ
204
+
205
+ ```javascript
206
+ import { NFeService, XsdValidationError } from 'ghinfe';
207
+
208
+ const service = new NFeService({ validarXsd: true });
209
+
210
+ try {
211
+ service.validarXsd(xml, { preAssinatura: true });
212
+ } catch (error) {
213
+ if (error instanceof XsdValidationError) console.error(error.erros);
214
+ }
215
+ ```
216
+
217
+ Schemas oficiais em `schemas/nfe/PL_009_V4/`.
218
+
219
+ ### NFC-e (modelo 65)
220
+
221
+ ```javascript
222
+ import { NFCeService } from 'ghinfe';
223
+
224
+ const service = new NFCeService({ mock: true });
225
+
226
+ const documento = {
227
+ ambiente: 2,
228
+ ide: { uf: 'SP', codigoMunicipio: '3550308', serie: 1, numero: 1 },
229
+ emitente: { cnpj: '...', razaoSocial: '...', ie: '...', crt: '1', endereco: { /* ... */ } },
230
+ itens: [{ codigo: '001', descricao: '...', ncm: '...', cfop: '5102', unidade: 'UN', quantidade: 1, valorUnitario: 10, valorTotal: 10 }],
231
+ csc: { idCSC: '000001', codigo: 'SEU-CSC-SEFAZ' },
232
+ };
233
+
234
+ const xml = service.gerarXml(documento);
235
+ // QR Code v3 é adicionado após assinatura:
236
+ const { xml: xmlCompleto, qrCode } = service.gerarXmlAssinado(documento, { pfx, senha });
237
+ ```
238
+
239
+ ### 2. Assinar com certificado A1
240
+
241
+ ```javascript
242
+ import fs from 'fs';
243
+
244
+ const pfx = fs.readFileSync('./certs/certificado.pfx');
245
+ const xmlAssinado = service.gerarXmlAssinado(documento, {
246
+ pfx,
247
+ senha: process.env.PFX_PASSWORD,
248
+ });
249
+ ```
250
+
251
+ ### 3. Enviar para SEFAZ (mock em desenvolvimento)
252
+
253
+ ```javascript
254
+ const service = new NFeService({ mock: true });
255
+
256
+ const resultado = await service.emitir(documento, { pfx, senha: '...' });
257
+
258
+ if (resultado.retorno.autorizado) {
259
+ console.log('Protocolo:', resultado.retorno.protocolo);
260
+ }
261
+ ```
262
+
263
+ ### 4. Persistir no banco (Sequelize)
264
+
265
+ ```javascript
266
+ const payload = service.toPersistencePayload(resultado);
267
+
268
+ await NotaFiscal.create({
269
+ chave_acesso: payload.chave_acesso,
270
+ xml_nfe: payload.xml_nfe,
271
+ xml_protocolo: payload.xml_protocolo,
272
+ protocolo: payload.protocolo,
273
+ status: payload.status,
274
+ });
275
+ ```
276
+
277
+ ### 5. Cancelar NF-e
278
+
279
+ ```javascript
280
+ const resultado = await service.cancelar({
281
+ chaveAcesso: '35260712345678000199550010000000011000000011',
282
+ cnpj: '12345678000199',
283
+ uf: 'SP',
284
+ protocolo: '135260000000001',
285
+ justificativa: 'Cancelamento por erro de digitacao no pedido',
286
+ }, { pfx, senha });
287
+
288
+ console.log(resultado.retorno.cStat); // '135' — evento registrado
289
+ ```
290
+
291
+ ### 6. Carta de Correção (CC-e)
292
+
293
+ ```javascript
294
+ const resultado = await service.cartaCorrecao({
295
+ chaveAcesso: '...',
296
+ cnpj: '12345678000199',
297
+ uf: 'SP',
298
+ sequencia: 1,
299
+ correcao: 'Correcao do endereco de entrega: Rua Nova, 500',
300
+ }, { pfx, senha });
301
+ ```
302
+
303
+ ### 7. Fila assíncrona (Bull + Redis)
304
+
305
+ ```javascript
306
+ import { NFeQueue } from 'ghinfe';
307
+
308
+ const queue = new NFeQueue({
309
+ redis: { host: '127.0.0.1', port: 6379 },
310
+ nfeOptions: { mock: true },
311
+ });
312
+
313
+ await queue.adicionarEmissao({ documento, certificado: { pfx, senha } });
314
+
315
+ queue.onCompleted(async (resultado) => {
316
+ await NotaFiscal.create(service.toPersistencePayload(resultado));
317
+ });
318
+ ```
319
+
320
+ ## Tratamento de erros SEFAZ
321
+
322
+ ```javascript
323
+ import { SefazError } from 'ghinfe';
324
+
325
+ try {
326
+ await service.enviar(xmlAssinado, chaveAcesso);
327
+ } catch (error) {
328
+ if (error instanceof SefazError) {
329
+ console.error(`Rejeição ${error.cStat}: ${error.xMotivo}`);
330
+ // 204 = duplicidade, 225 = schema, 280 = certificado...
331
+ }
332
+ }
333
+ ```
334
+
335
+ ## API de testes (Swagger)
336
+
337
+ ```bash
338
+ npm start
339
+ ```
340
+
341
+ | URL | Descrição |
342
+ |-----|-----------|
343
+ | http://localhost:3333/docs | Swagger UI interativo |
344
+ | http://localhost:3333/guia/developer-guide.html | Guia HTML do desenvolvedor |
345
+ | http://localhost:3333/health | Health check |
346
+
347
+ ### Endpoints
348
+
349
+ - `GET /sefaz/endpoints/:uf?ambiente=2` — URLs SEFAZ por UF
350
+ - `GET /sefaz/ufs` — Lista UFs suportadas
351
+ - `POST /nfse/cancelar-mock` — Cancela NFS-e (mock)
352
+ - `POST /nfse/substituir-mock` — Substitui NFS-e (mock)
353
+ - `POST /danfe` — Gera DANFE/DANFCE (JSON ou `?format=html`)
354
+ - `GET /sefaz/status/:uf?cenario=ok` — Consulta status SEFAZ (mock)
355
+ - `GET /nfse/layouts` — Layouts NFS-e suportados
356
+ - `POST /reforma/calcular` — Calcula IBS/CBS + fragmento XML
357
+ - `POST /nfse/xml?layout=ginfes` — Gera XML RPS NFS-e
358
+ - `POST /nfse/enviar-mock` — Emite NFS-e mock
359
+ - `GET /nfse/municipios` — Municípios configurados
360
+ - `POST /nfe/xml?validarXsd=true` — Gera XML com validação XSD
361
+ - `POST /nfe/validar-xsd` — Valida XML existente
362
+ - `POST /nfce/xml` — Gera XML NFC-e (modelo 65)
363
+ - `POST /nfce/enviar-mock` — Envia NFC-e mock
364
+ - `POST /nfe/xml` — Gera XML a partir do JSON
365
+ - `POST /nfe/enviar-mock?cenario=autorizado` — Fluxo completo mock
366
+ - `POST /nfe/cancelar-mock` — Cancelamento simulado
367
+ - `POST /nfe/cce-mock` — Carta de correção simulada
368
+ - `GET /nfe/cenarios-mock` — Lista cenários de teste
369
+
370
+ ## Exemplos CLI
371
+
372
+ ```bash
373
+ npm run example:nfe # Gera XML e simula retorno
374
+ npm run example:mock # Testa cenários SEFAZ mock
375
+ npm run example:endpoints # Endpoints SEFAZ por UF
376
+ npm run example:reforma-xml # NF-e com IBSCBS no XML
377
+ npm run example:nfse-eventos # Cancelamento / substituição NFS-e
378
+ npm run example:danfe # Gera HTML em tmp/
379
+ npm run example:status # Status SEFAZ mock
380
+ npm run example:layouts # ABRASF / GINFES / Betha / ISSNet
381
+ npm run example:reforma # Cálculo IBS/CBS
382
+ npm run example:nfse # NFS-e mock
383
+ npm run example:nfce # Gera NFC-e modelo 65
384
+ npm run example:xsd # Valida XML contra XSD
385
+ npm run example:eventos # Cancelamento e CC-e mock
386
+ npm run schemas:download # Baixa schemas XSD da SEFAZ
387
+ ```
388
+
389
+ ## Arquitetura
390
+
391
+ ```
392
+ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ ┌────────────┐
393
+ │ Seu App │────▶│ NFeService │────▶│ NFeXmlService │────▶│ XML NF-e │
394
+ │ (Sequelize) │ │ (orquestrador)│ └───────────────┘ └────────────┘
395
+ └─────────────┘ │ │────▶│ NFeSignService│────▶│ XML Assinado│
396
+ │ │ │ └───────────────┘ └────────────┘
397
+ │ │ │────▶│ NFeSoapService│────▶│ SEFAZ/Mock │
398
+ ▼ └──────────────┘ └───────────────┘ └────────────┘
399
+ ┌─────────────┐
400
+ │ NFeQueue │ Bull/Redis — processamento assíncrono
401
+ └─────────────┘
402
+ ```
403
+
404
+ ## Roadmap
405
+
406
+ - [ ] Validação XSD PL_010 completa (quando SEFAZ publicar pacote estável)
407
+ - [ ] Mais municípios / provedores NFS-e
408
+ - [ ] PDF nativo (puppeteer opcional) no DanfeService
409
+ - [ ] Assinatura XML de cancelamento NFS-e por layout
410
+
411
+ ## Licença
412
+
413
+ MIT — veja [LICENSE](LICENSE).