node-excel-export
node-excel-export
In sintesi
Servizio di esportazione tabellare che trasforma payload JSON o query su PostgreSQL in file Excel (XLSX) e CSV pronti al download. Espone due workflow distinti: uno legacy a payload diretto (il chiamante passa righe e intestazioni) e uno dinamico basato su modelli persistiti su DB, dove il client indica risorsa, campi, filtri e ordinamento, e il servizio costruisce la query, esegue l'estrazione paginata e formatta il file. È il punto di uscita standard per le funzioni "Esporta" del frontend Vue del tenant ditta.
Funzionalità principali
- Export sincrono da payload JSON (
POST /export) per fogli singoli o multi-worksheet con intestazioni, righe e merge cells dichiarate dal client - Export dinamico da template DB (
POST /api/export/dynamic) che esegue query sicure su risorse registrate (anagrafica,articoli, ecc.) applicando campi, filtri, ordinamento e limite - CRUD modelli di export persistiti su PostgreSQL (
modelliexport): creazione, aggiornamento, soft delete e contatorevolteusatoper le statistiche - Discovery metadati campi per risorsa (
GET /api/export/metadata/:risorsa/fields) consumata dalla libreria@pzeta/vue-importexportper costruire l'UI di selezione - Strategy multi-formato (XLSX via
exceljs, CSV streaming) selezionata dinamicamente dalformatorichiesto - Rate limiting per IP configurabile (default 10 richieste / 60 s) sulla rotta di export, applicato dal
securityPlugindi@pzeta/fastify-utils - Validazione strutturale Zod su request, schema OpenAPI auto-generato e formattazione uniforme degli errori HTTP 400/422
- Logging applicativo delle esportazioni su tabella
logexportazioniper audit e diagnostica, con request ID di tracing propagato - Migrazioni automatiche dello schema
importexportall'avvio (idempotenti) seRUN_MIGRATIONS=true
Architettura
Stack: Fastify v5 · TypeScript strict · @pzeta/fastify-utils (security/error-handler/healthcheck/openapi/metrics/tracing/logging) · @pzeta/log per logging strutturato · PostgreSQL via driver pg diretto · exceljs per la generazione XLSX · Zod per la validazione · DI container interno (infrastructure/container/DIContainer.ts) con risoluzione per token string.
Layout DDD (src/):
| Layer | Contenuto |
|---|---|
domain/ | Entità (ExportJob, ExportTemplate, ExportLog, Workbook, Worksheet), repository interface (IExportTemplateRepository, IExportLogRepository, IFileManager, IDatabaseQueryProvider), servizi di dominio per formattazione ed export |
application/ | DTO request/response, ExportApplicationService, DynamicExportService, DynamicQueryService, RequestValidationService, adapter verso strategie infrastrutturali |
infrastructure/ | PostgresConnection (pool pg), MigrationRunner, repository concreti, ExportStrategyFactory con XlsxExportStrategy e CsvExportStrategy, EnvironmentConfig singleton |
presentation/ | Plugin di route (export.routes, dynamicExport.routes, exportLimits.routes, exportExamples.routes, buildInfo.routes), controller dedicati per ciascuna famiglia di endpoint, schemi Fastify+JSON-Schema generati da Zod |
Pattern adottati: Strategy (un'implementazione per ogni formato di output), Factory per la selezione della strategia, Repository per la persistenza dei template e dei log, DI container leggero con resolve per token. La generazione del file avviene in memoria (stream) e ritorna Content-Disposition: attachment direttamente nella response, senza scrittura su disco né caricamento su storage esterno.
Sicurezza: dietro nginx con auth_request verso node-user-auth (strategia nginx); nessun token applicativo verificato dal servizio. Il rate limiting è applicato per IP a livello di plugin.
Casi d'uso
- Export "Esporta tabella" dal frontend: una griglia Vue del Laundry ERP (anagrafiche, articoli, ordini) invoca
POST /api/export/execute(alias compatibile con@pzeta/vue-importexport) con risorsa, campi selezionati, filtri della ricerca e ordinamento corrente; riceve il file XLSX da scaricare - Riuso di un modello salvato: l'operatore seleziona un template precedente (
GET /api/export/templates/:risorsa), il servizio lo applica con i filtri runtime e incrementavolteusatoper le statistiche d'uso - Export ad-hoc da modulo legacy: un microservizio chiama
POST /exportpassando direttamente intestazioni e righe già pronte (ad esempio un report aggregato calcolato altrove), senza coinvolgere la pipeline dinamica - Step di un workflow orchestrato:
node-orchestratoresegue un export programmato come task di un workflow notturno e inoltra l'output anode-storageo a un destinatario vianode-notification - Discovery UI: la libreria
@pzeta/vue-importexportchiamaGET /api/export/metadata/:risorsa/fieldsper popolare il selettore campi con i metadati ufficiali della risorsa (label, tipo, gruppo)
Identità & esposizione
| Campo | Valore |
|---|---|
| Categoria | data-io |
| Versione cluster | 1.0.3 |
| Image | gitea.pzetatouch.it/pzeta_touch/node-excel-export:1.0.3 |
| URL pubblico | https://ditta.pzeta.it/excel-export |
| Path regex ingress | `/excel-export(/ |
| Rewrite a backend | /$2 |
| DNS interno | node-excel-export-ditta.ditta.svc.cluster.local:3000 |
| Auth nginx | auth_request → node-user-auth |
| Repository | node-excel-export |
| Endpoint REST | 13 (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/excel-export/health | liveness probe |
https://ditta.pzeta.it/excel-export/ready | readiness probe |
https://ditta.pzeta.it/excel-export/metrics | metriche Prometheus |
https://ditta.pzeta.it/excel-export/api-docs.json | spec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true) |
https://ditta.pzeta.it/excel-export/api-docs | Swagger UI (solo in NODE_ENV !== production) |
Configurazione
Variabili d'ambiente che un integratore deve conoscere (per la lista completa vedi .env.example del repo):
| Variabile | Ruolo |
|---|---|
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAME | Connessione PostgreSQL; lo schema applicativo è importexport (template, log) ma il servizio interroga anche le tabelle business per l'export dinamico |
DATABASE_POOL_MAX / _IDLE_TIMEOUT_MS / _CONNECTION_TIMEOUT_MS | Tuning del pool pg; default 20 / 30000 / 2000 ms |
RUN_MIGRATIONS | Esegue le migrazioni dello schema importexport all'avvio; true di default |
TEMP_DIRECTORY | Cartella per file temporanei di lavoro (./temp); il servizio non persiste l'output, ma può usarla per buffering |
MAX_FILE_SIZE_MB | Limite hard sulla dimensione del file generato (default 50 MB); oltre il limite la richiesta fallisce con 413 |
EXPORT_RATE_LIMIT_REQUESTS / EXPORT_RATE_LIMIT_WINDOW_MS | Rate limit per IP sulle rotte di export (default 10 richieste / 60 s) |
CORS_ALLOWED_ORIGINS | Origini consentite in produzione, separate da virgola; in NODE_ENV !== production la policy è aperta |
REVERSE_PROXY | Abilita trustProxy di Fastify quando il servizio è dietro nginx |
Swagger UI è esposto solo se NODE_ENV !== production; le metriche Prometheus sono pubblicate con prefisso excel_export_.
Note eventing NATS
Il servizio non partecipa al bus NATS: lo scanner statico ha rilevato zero subject pubblicati e zero subscription attive (vedi nats.json). L'integrazione è puramente sincrona via HTTP REST: il client (frontend Vue, altro microservizio, node-orchestrator come step di workflow) effettua una POST e riceve in risposta lo stream del file. Eventuali audit cross-servizio sulle esportazioni vanno costruiti sopra la tabella logexportazioni di questo servizio, non su eventi di dominio.
Dipendenze e dipendenti
Dipende da (servizi che questo servizio chiama):
Consumato da (chi chiama questo servizio):
frontend Vue
Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.