node-xmlvalidation
node-xmlvalidation
In sintesi
Servizio specializzato nella validazione di documenti XML rispetto a schemi XSD versionati e a regole di business specifiche per il contesto fiscale italiano. Combina la validazione strutturale (XSD via xmllint-wasm) con un motore a regole pluggabili che, per la Fattura Elettronica PA, copre oltre 50 controlli normativi (algoritmo codice fiscale, coerenza P.IVA, aliquote IVA, codice destinatario, firma digitale P7M, ecc.). Esiste come microservizio dedicato perché concentra dipendenze native pesanti (xmllint-wasm, node-forge, xml-crypto), una libreria di XSD versionati con selezione automatica per data documento, e regole business riusabili che sarebbe controproducente duplicare nei singoli servizi consumer.
Funzionalità principali
- Validazione XSD multi-versione: gli schemi sono registrati per configurazione con
validFrom/validTo; il servizio sceglie automaticamente lo schema corretto in base alla data del documento, con fallback a schema di default o a schema "open-ended" se non c'è match esatto - Motore regole pluggabili (50+ regole italiane): codice fiscale, partita IVA, aliquote IVA vs riepilogo, natura/esigibilità, calcolo imponibile e imposta, coerenza tipo documento, duplicati di lotto, numero fattura, codice ufficio, dichiarazione d'intento, gruppo IVA
- Verifica firma digitale PKI su file
.xml.p7m(PKCS#7): catena al CA, scadenza/revoca certificato, riferimento temporale, conformità AgID - Modalità sincrona e asincrona: validazione sincrona per file singoli e XML inline; job asincrono con lifecycle tracking (
pending→processing→completed/failed) e endpoint di stato/risultato - Batch processing di più file XML per configurazione
- Notifiche di stato job opzionali via webhook HTTP, email SMTP o coda messaggi (NATS/RabbitMQ)
- Integrazione orchestrator: il servizio si registra come modulo presso
node-orchestratoresponendo taskvalidate-xml-sync-base64/validate-xml-sync-stringquandoORCHESTRATOR_ENABLED=true - Storage pluggabile (locale o S3) per upload temporanei e file XSD
- Configurazioni multiple: lo stesso servizio può servire profili di validazione differenti (es.
fatture-da-inviare,fatture-ricevute, EDI custom) ognuno con il proprio set di regole e XSD
Architettura
Stack: Fastify v5 · TypeScript strict · @pzeta/fastify-utils (auth nginx, security, healthcheck, OpenAPI) · @pzeta/log · xmllint-wasm (validazione XSD WebAssembly, no native bindings) · node-forge + xml-crypto + @xmldom/xmldom + xpath (firma digitale e canonicalizzazione) · xml2js (parsing per regole business) · @pzeta/orchestrator-node (registrazione modulo opzionale) · Zod per request/response validation.
Layout DDD (src/):
| Layer | Contenuto |
|---|---|
domain/ | validation-rules/italian-invoice/ (50+ regole), services/XsdSchemaManager + XsdSchemaSelector (selezione schema per data), strategie (XsdBusinessRulesStrategy, SchematronValidationStrategy, ExternalServiceValidationStrategy), value object (ValidationResult, ValidationError), repository interfaces, eventi |
application/ | ValidatorOrchestrator (entry point validazione), StrategizedValidatorOrchestrator, SchemaValidatorService, RuleRegistryService, ValidationJobManager + NotifyingValidationJobManager, JobExecutorService, ConfigurationManagerService, NotificationService, DTO request/response |
infrastructure/ | XsdSchemaManager con preload xmllint-wasm, rule-loading/ (FileSystem/Database/Api rule loader + factory), storage/ (Local + S3 strategy), file-handling/ (upload e temp file manager), notifications/ (Webhook/Email/Queue notifier), orchestrator/OrchestratorAdapter, monitoring/ (Prometheus), repositories/RuleRepository |
presentation/ | Controller (ValidationController, JobController, SchemaController, ConfigurationController, RuleController), route (XmlValidationRoutes, JobRoutes, SchemaRoutes, ConfigurationRoutes, RuleRoutes), schemi Zod, formatters di errore |
Pattern adottati: Strategy (motori di validazione intercambiabili: XSD+business, Schematron, external service), Factory (rule loader, storage, document date extractor), Repository, Event Publisher in-memory per eventi di dominio (ValidationStarted, ValidationCompleted, ValidationFailed), Adapter (orchestrator).
Schema registry: gli XSD non sono embedded nell'immagine. Sono caricati a runtime da una configurazione JSON versionata (storage/configuration.json) che, per ciascun profilo (fatture-da-inviare, ecc.), elenca gli schemi con id, name, version, validFrom, validTo. I file XSD veri e propri vivono nello storage (locale storage/uploads/ o S3) e possono essere caricati/sostituiti via API (POST /configurations/{id}/xsd). XsdSchemaManager esegue il preload tramite xmllint-wasm risolvendo gli import di schemi esterni; XsdSchemaSelector applica la logica di scelta in base alla data del documento.
Output validazione: ogni richiesta restituisce un ValidationResult strutturato con isValid, errors[] e warnings[]. Ogni errore include code, severity (error/warning/info), message localizzato, ruleId, ed eventuali coordinate XML (line, column, xpath) quando emergono da xmllint-wasm. Il batch produce un AggregatedValidationResult per file con un summary aggregato.
Casi d'uso
- Validazione pre-invio Fattura Elettronica SDI: il flusso fatturazione invoca
POST /validate/{configId}/single/syncprima di trasmettere il file allo SDI. Il servizio applica XSDFatturaPA v1.2.x, regole fiscali e, se il file è.xml.p7m, verifica della firma digitale CAdES - Controllo massivo fatture ricevute: import notturno di un lotto di fatture passive — il servizio fatturazione carica i file via
POST /validate/{configId}/batche itera sulAggregatedValidationResultper separare i documenti conformi da quelli da contestare al fornitore - Validazione asincrona orchestrata: un workflow di
node-orchestratorriceve un XML da una pipeline EDI, chiama il taskvalidate-xml-sync-base64esposto dall'OrchestratorAdaptere, in base al risultato, instrada il documento verso l'import oppure verso una coda di anomalie - Validazione documenti EDI/custom: nuove configurazioni vengono create via
POST /configurationscon i propri XSD e regole, permettendo di riusare la stessa infrastruttura per schemi non-fattura (ordini, DDT, tracciati custom B2B) - Diagnostica regole: durante l'introduzione di una nuova regola fiscale, l'operatore consulta
GET /rules/diagnostics/{configId}per verificare quali regole sono attive eGET /rules/statistics/{configId}per le metriche di applicazione su validazioni passate
Identità & esposizione
| Campo | Valore |
|---|---|
| Categoria | integration |
| Versione cluster | 1.0.0 |
| Image | gitea.pzetatouch.it/pzeta_touch/node-xmlvalidation:1.0.14 |
| URL pubblico | https://ditta.pzeta.it/xmlvalid |
| Path regex ingress | `/xmlvalid(/ |
| Rewrite a backend | /$2 |
| DNS interno | node-xmlvalidation-ditta.ditta.svc.cluster.local:3000 |
| Auth nginx | auth_request → node-user-auth |
| Repository | node-xmlvalidation |
| Endpoint REST | 20 (vedi sezione "API reference") |
Endpoint operazionali
Endpoint convenzionali esposti da tutti i microservizi PZeta basati su @pzeta/fastify-utils:
| Path pubblico | Scopo |
|---|---|
https://ditta.pzeta.it/xmlvalid/health | liveness probe |
https://ditta.pzeta.it/xmlvalid/ready | readiness probe |
https://ditta.pzeta.it/xmlvalid/metrics | metriche Prometheus |
https://ditta.pzeta.it/xmlvalid/api-docs.json | spec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true) |
https://ditta.pzeta.it/xmlvalid/api-docs | Swagger UI (solo in NODE_ENV !== production) |
Configurazione
Variabili d'ambiente che un integratore deve conoscere (lista completa in .env.default):
| Variabile | Ruolo |
|---|---|
HOST / PORT | Bind del server Fastify (default 0.0.0.0:3000) |
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAME | Connessione PostgreSQL — usata da DatabaseRuleLoader quando le regole sono caricate da DB invece che da filesystem |
STORAGE_TYPE | local (default) o s3; determina la strategy di FileStorageFactory per XSD e upload temporanei |
STORAGE_LOCAL_BASE_PATH | Path base per storage locale (default /usr/src/app/storage) |
CONFIG_PATH | Override del path del file configuration.json con i profili di validazione |
JOB_RETENTION_MS | TTL dei job completati prima del cleanup (default 3600000 = 1 h) |
JOB_CLEANUP_INTERVAL_MS | Frequenza del cleanup automatico (default 300000 = 5 min, 0 per disabilitare) |
NOTIFICATIONS_ENABLED / NOTIFICATION_EVENTS | Abilita notifiche di stato job e filtra gli eventi (started,processing,completed,failed,cancelled) |
NOTIFICATION_WEBHOOK_* / NOTIFICATION_EMAIL_* / NOTIFICATION_QUEUE_* | Configurazione dei tre canali di notifica (HTTP, SMTP, message queue) |
ORCHESTRATOR_ENABLED | Se true, registra il servizio come modulo presso node-orchestrator |
ORCHESTRATOR_URL / ORCHESTRATOR_MODULE_ID / ORCHESTRATOR_API_KEY | Coordinate per la registrazione modulo |
ORCHESTRATOR_NATS_URL / ORCHESTRATOR_NATS_NAMESPACE | NATS opzionale usato dall'orchestrator-node SDK per event publishing dei task |
ENABLE_CORS / CORS_ORIGIN | CORS per l'uso diretto dal frontend Vue |
APP_URL | URL pubblico dell'applicazione (usato in link nei messaggi di notifica) |
I profili di validazione (XSD + regole + soglie file size) non si configurano via env: sono definiti in storage/configuration.json e gestibili via API REST (/configurations, /configurations/{id}/xsd, /rules/load).
Note eventing NATS
Lo scanner statico non rileva subject NATS — il servizio non pubblica né sottoscrive subject di dominio in modo dichiarativo (nats.json vuoto). L'unica integrazione con NATS è indiretta e opzionale: quando ORCHESTRATOR_ENABLED=true, l'SDK @pzeta/orchestrator-node apre una connessione a ORCHESTRATOR_NATS_URL per ricevere task in request/reply dall'orchestrator e pubblicare eventi di task completion sul namespace configurato (ORCHESTRATOR_NATS_NAMESPACE, default xml-validation). I subject sono derivati a runtime dal manifest del modulo, quindi non figurano nel report statico.
Il canale NOTIFICATION_QUEUE_* può a sua volta pubblicare notifiche di stato job su NATS/RabbitMQ/Redis (default topic xml-validation.notifications), ma è una funzionalità opt-in pensata per integrazioni esterne, non per l'eventing inter-servizio del cluster.
Dipendenze e dipendenti
Dipende da (servizi che questo servizio chiama):
Consumato da (chi chiama questo servizio):
node-orchestratorfrontend Vue
Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.