node-renderer
node-renderer
In sintesi
Motore di rendering testuale server-side basato su Handlebars: compila template parametrici (HTML, testo, frammenti JSON, intestazioni email) combinandoli con i dati forniti in input e restituisce il documento sorgente al chiamante. Si posiziona a monte della filiera documentale del tenant ditta: produce il contenuto rappresentativo del documento, lasciando a node-print la trasformazione in PDF/ZPL e il dispatch al device, e a node-notification il recapito quando si tratta di email o messaggi. Il servizio è stateless rispetto al singolo render, ma persiste su PostgreSQL la libreria di template gestita dagli operatori e supporta sorgenti template multiple (file, DB, VCS, memoria, contenuto inline).
Funzionalità principali
- Rendering Handlebars sincrono via REST (
POST /render,GET /render) con risoluzione del template pertemplateIdregistrato otemplateContentinline e dati provenienti da JSON diretto, URL esterno o dataset statico - Multi-sorgente template tramite provider pattern:
file(filesystem./templates/*.hbs),database(tabella PostgreSQL parametrica con colonne id/content configurabili),vcs(repository Git via@pzeta/vclcon endpointservices.pzeta.it/git),memory(template in-process per test e fixture) - Gestione CRUD libreria template su PostgreSQL (
GET/POST/PUT/DELETE /templates,POST /templates/{id}/validate) con validazione strutturale (sintassi Handlebars, helper noti, riferimenti dato) e supporto al hot-reload - Helper library estesa: catalogo introspettabile (
GET /helpers,/helpers/categories,/helpers/search,/helpers/{name}) con helper di formatting, condizionali, iterazione, manipolazione date/numeri e helper temporanei iniettabili a richiesta - Cache di compilazione e di template opzionale (TTL configurabile via
CACHE_TTL, massimo 24h) sia sui sorgenti che sui template compilati Handlebars, per abbattere le latenze sui rendering ripetitivi - Integrazione orchestrator via
@pzeta/orchestrator-node: il servizio si registra come modulo con i taskrender-template,render-batch(rendering parallelo con concurrency configurabile),validate-template,get-template-info,cache-warm - Rate limiting granulare su quattro bucket (
global,infrastructure,template-management,rendering,monitoring) per proteggere il servizio dagli abusi senza penalizzare le probe operazionali - Sicurezza render: domini permessi per data-URL esterni (
ALLOWED_DOWNLOAD_DOMAINS), CSP iniettabile su risposte HTML (HTML_CSP_POLICY), escape automatico Handlebars con opt-out controllato (ALLOW_NO_ESCAPE), validazione Zod di tutte le request
Architettura
Stack: Fastify v5 · Inversify (DI con constructor injection) · PostgreSQL via driver pg per la libreria template · Handlebars 4 come template engine · @pzeta/vcl per accesso a repository Git remoti · @pzeta/orchestrator-node come SDK di registrazione al hub · @pzeta/fastify-utils (auth, security, OpenAPI, healthcheck) · @pzeta/log con correlation IDs · Zod per validazione schema-first.
Layout DDD (src/):
| Layer | Contenuto |
|---|---|
domain/ | Interfacce (ITemplateService, ITemplateCompiler, IDataService, IRenderingStrategy, IRenderingPipelineExtension), errori applicativi (RenderingError, TemplateNotFoundError, TemplateValidationError, DataFetchError) |
application/ | TemplateCompilerService, TemplateCommandService, TemplateManagementService, TemplateSyntaxAnalyzer, RenderContextBuilder, HelperManager, ConfigurationService |
infrastructure/ | HandlebarsCompiler, provider template (DbTemplateProvider, MemoryTemplateProvider, FileTemplateProvider, VcsTemplateProvider), provider dati (StaticDataProvider, UrlDataProvider), pipeline extensions (AsyncHelpersPipelineExtension, LoggingPipelineExtension), OrchestratorBootstrap |
presentation/ | Controllers (PostRenderController, GetRenderController, CRUD template, helpers, configuration), route plugin (RenderRoutes, TemplateManagementRoutes, ConfigurationRoutes, MonitoringRoutes), schemi Zod/JSON-Schema |
Pattern adottati: Strategy (sorgenti template intercambiabili), Factory (TemplateProviderFactory, TemplateCompilerFactory, WebServerFactory), Chain of Responsibility (fallback fra provider quando un template non è trovato sulla sorgente primaria), Repository (astrazione IDatabaseConnection su PostgreSQL), Pipeline Extension (estensioni in coda al compilatore: helper async, logging strutturato).
Differenza rispetto a node-print: questo servizio è il renderer puro — produce il documento sorgente (stringa) a partire da template + dati. node-print è invece il device gateway: prende il sorgente già renderizzato (o invoca questo servizio per ottenerlo), lo converte nel formato richiesto dal dispositivo (PDF, ZPL, etichetta termica) e gestisce la coda di stampa verso la stampante fisica o la scarica come file. Le due responsabilità sono separate per consentire di renderizzare lo stesso template anche per scenari non di stampa (email HTML, anteprima a video, payload di report).
Casi d'uso
- Fattura PDF:
node-printriceve la richiesta di stampa documento dal frontend, chiamaPOST /rendercontemplateId="fattura-vendita"e i dati della testata/righe, ottiene l'HTML sorgente e lo converte in PDF prima di archiviarlo sunode-storagee inviarlo al device - Email transazionale:
node-notificationinvoca il task orchestratorrender-templateper produrre il corpo HTML (e l'oggetto come secondo render) di una mail di conferma ordine, partendo da template registrati sul DB del renderer e dati pescati dal workflow - Report custom: il frontend Vue richiede un'anteprima parametrica di un report (estratto conto, riepilogo turno, scheda capo lavanderia) tramite
GET /render?templateId=...&data=..., riceve HTML da iniettare in un'area di stampa client-side - Generazione batch documenti: un workflow
node-orchestratordistribuisce N documenti (es. mailing massivo, contratti per gruppo di clienti) sul taskrender-batchconparallel=trueemaxConcurrency=5per il rendering parallelo, poi inoltra ogni output al servizio downstream - Etichette e ricevute: per i flussi di lavanderia industriale,
node-printchiede al renderer una stringa ZPL/EPL parametrica (template testuale, non HTML) da inviare alla stampante termica di etichettatura capi
Identità & esposizione
| Campo | Valore |
|---|---|
| Categoria | document-output |
| Versione cluster | 1.0.14 |
| Image | gitea.pzetatouch.it/pzeta_touch/node-renderer:1.0.13 |
| URL pubblico | https://ditta.pzeta.it/renderer |
| Path regex ingress | `/renderer(/ |
| Rewrite a backend | /$2 |
| DNS interno | node-renderer-ditta.ditta.svc.cluster.local:3000 |
| Auth nginx | auth_request → node-user-auth |
| Repository | node-renderer |
| Endpoint REST | 12 (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/renderer/health | liveness probe |
https://ditta.pzeta.it/renderer/ready | readiness probe |
https://ditta.pzeta.it/renderer/metrics | metriche Prometheus |
https://ditta.pzeta.it/renderer/api-docs.json | spec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true) |
https://ditta.pzeta.it/renderer/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 |
|---|---|
TEMPLATE_PROVIDERS | Lista CSV dei provider attivi: file, database, vcs, memory. L'ordine determina la priorità di lookup (chain of responsibility) |
TEMPLATE_FILE_PATH / TEMPLATE_FILE_EXT | Cartella radice e estensione (default .hbs) per il provider file |
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAME | Connessione PostgreSQL per il provider database — alternativa: DATABASE_URL |
DATABASE_TABLE / DATABASE_ID_COL / DATABASE_CONTENT_COL | Tabella e colonne (default templates / id / content) — i nomi sono validati per evitare SQL injection |
VERSION_CONTROL_API_URL / _CATEGORY | Endpoint del repository Git remoto per il provider vcs (default https://services.pzeta.it/git, categoria template) |
DATA_PROVIDERS | Sorgenti dati abilitate per il render (static, url) |
ORCHESTRATOR_ENABLED / ORCHESTRATOR_URL / ORCHESTRATOR_API_KEY | Registrazione del modulo presso node-orchestrator per ricevere task |
CACHE_ENABLED / CACHE_TTL | Cache di template e compilazioni (TTL in secondi, max 86400) |
RATE_LIMIT_*_MAX / _WINDOW | Limiti per bucket (global, infrastructure, template-mgmt, rendering, monitoring) |
ALLOWED_DOWNLOAD_DOMAINS / TRUSTED_DATA_DOMAINS | Whitelist di domini per fetch dati esterni e propagazione token Bearer |
HTML_CSP_POLICY / ALLOW_NO_ESCAPE | Hardening output HTML: CSP iniettata sulle risposte rendered, opt-in per disabilitare l'escape Handlebars |
Lo storage dei file template grandi e degli asset binari richiamati dai template (loghi, immagini intestazione) resta su node-storage: il renderer riceve solo i riferimenti via dato di input e Handlebars produce gli URL nel sorgente HTML.
Note eventing NATS
Il servizio non pubblica e non si sottoscrive direttamente a subject NATS applicativi: lo scanner statico riporta zero publish/subscribe espliciti. La comunicazione asincrona avviene tramite la SDK @pzeta/orchestrator-node, che incapsula la registrazione al hub e la consegna delle reply ai task: il renderer riceve invocazioni dei task render-template, render-batch, validate-template, get-template-info, cache-warm su subject derivati dal manifest e risponde request/reply. Tutta la logica di retry, dispatch e timeline rimane in node-orchestrator.
Quando ORCHESTRATOR_ENABLED=false (default in sviluppo) il servizio espone solo l'API REST sincrona, utile per chiamate dirette da node-print e dal frontend Vue.
Dipendenze e dipendenti
Dipende da (servizi che questo servizio chiama):
Consumato da (chi chiama questo servizio):
node-printfrontend Vue
Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.