Case study web app — configuratore B2B
5 giorni per un preventivo.
I clienti non aspettano.
La concorrenza nemmeno.
Un'azienda manifatturiera con 300+ varianti di prodotto configurabili perdeva commesse perché i preventivi arrivavano troppo tardi. Ho costruito un configuratore interattivo con motore di pricing real-time in Node.js: ogni commerciale — e ogni cliente — può comporre il prodotto, vedere il prezzo aggiornato al volo e generare l'offerta in PDF in meno di 20 minuti.
Case study configuratore prodotti B2B Node.js
300 varianti di prodotto.
Ogni preventivo fatto a mano.
L'azienda — un produttore italiano di valvole e componenti idraulici industriali su misura — rifornisce impianti di processo, cantieri navali e industria alimentare in tutta Europa. I loro prodotti sono altamente configurabili: diametro, pressione nominale, materiale del corpo, tipo di connessione, rivestimento interno, certificazioni richieste. Combinando le variabili si arriva a oltre 300 configurazioni possibili, ognuna con un prezzo diverso.
Prima di questo progetto, ogni richiesta di offerta seguiva lo stesso percorso: il commerciale raccoglieva le specifiche del cliente, le girava per email all'ufficio tecnico, che verificava la fattibilità della configurazione e passava i dati all'ufficio prezzi, che produceva il preventivo in un foglio Excel e lo restituiva al commerciale. Tempo medio: 3–5 giorni lavorativi.
In un mercato dove i competitor tedeschi e cechi rispondevano con offerte in meno di 24 ore, questo processo era diventato un handicap competitivo misurabile. L'azienda stimava di perdere il 20–25% delle trattative esclusivamente per tempi di risposta.
«Sappiamo già che il prodotto lo facciamo. Il problema è che il cliente non lo sa — perché ci vogliono quattro giorni per dirglielo. Nel frattempo ha già chiamato qualcun altro.»
— Direttore commerciale, chiamata di kickoffRequisiti configuratore industriale B2B
Da 5 giorni a 20 minuti.
Senza errori di configurazione.
Configuratore guidato step-by-step con validazione in tempo reale
Il sistema deve guidare l'utente attraverso i parametri del prodotto mostrando solo le combinazioni tecnicamente valide. Se selezioni DN 150 con pressione 40 bar, il materiale "bronzo" deve sparire dalla lista — perché quella combinazione non è omologata. Le regole di compatibilità sono gestite lato server, non lato client.
Pricing real-time con listini differenziati per cliente
Il prezzo deve aggiornarsi a ogni modifica di parametro, senza click su "calcola". Ogni cliente B2B ha un listino personalizzato (sconti, maggiorazioni per certificazioni, prezzi bloccati su alcune famiglie). Il motore di pricing deve applicare le regole corrette in base all'utente loggato, senza mai esporre il listino base al frontend.
Generazione PDF offerta brandizzato in un click
Il PDF dell'offerta deve includere: intestazione aziendale, dati cliente, descrizione tecnica completa del prodotto configurato, prezzo netto con breakdown, condizioni di fornitura, validità offerta e firma digitale del commerciale. Generazione in meno di 5 secondi, inviato via email al cliente automaticamente.
Sincronizzazione automatica con CRM HubSpot
Ogni offerta generata deve creare automaticamente un deal in HubSpot con tutti i dettagli della configurazione, il valore dell'offerta e il commerciale assegnato. Se il cliente esiste già nel CRM, il deal viene collegato al contatto esistente. Se è nuovo, viene creato il contatto. Nessun doppio inserimento manuale.
Accesso self-service per clienti diretti con area riservata
I clienti più grandi devono poter accedere al configuratore direttamente, senza passare da un commerciale. Vedono solo il proprio listino, lo storico delle offerte precedenti e possono ripartire da una configurazione salvata. L'ufficio commerciale riceve una notifica per ogni nuova offerta generata da un cliente in autonomia.
Sfide tecniche pricing engine real-time
Un motore di pricing
che non mente mai.
Un configuratore sbagliato è peggio di nessun configuratore: se genera un prezzo errato o valida una combinazione impossibile, l'azienda si trova a dover rinegoziare un'offerta già accettata. La sfida principale non era tecnica — era di correttezza assoluta.
Processo sviluppo configuratore B2B
10 settimane per trasformare
la conoscenza tacita in software.
Ho passato due settimane con il responsabile tecnico e il più esperto dei commerciali a mappare ogni regola di compatibilità esistente. Non erano documentate — vivevano nella testa delle persone e in un file Excel usato internamente. Ho prodotto un documento strutturato con 1.247 regole in forma "SE [parametro A] = X E [parametro B] = Y → ALLORA [parametro C] non può essere Z". Questo documento è diventato il modello di dati del motore di regole.
Ho sviluppato il cuore del sistema: il motore di regole in Node.js legge le regole da PostgreSQL, le valuta in ordine di priorità e restituisce le opzioni disponibili per ogni step. Il pricing engine applica le regole del listino attivo per l'utente loggato — base price × coefficiente materiale × coefficiente pressione + optional, poi applica lo sconto contrattuale del cliente. Redis cacca i listini con TTL di 15 minuti. Test di carico: 200 richieste/secondo senza degrado delle performance.
Interfaccia React con step progressivi: ogni selezione chiama il backend per ottenere le opzioni valide del passo successivo. Il prezzo si aggiorna in tempo reale tramite debounce a 300ms sulla chiamata API. Lo stato della configurazione viene salvato su PostgreSQL ogni 30 secondi — se il commerciale chiude il browser e riapre, trova tutto esattamente com'era. Ho anche costruito la sezione "storico offerte" per l'accesso self-service dei clienti diretti.
Il template PDF è stato costruito in HTML/CSS puro e replicato pixel-per-pixel dal modello cartaceo esistente. Puppeteer renderizza il template in un worker Node.js dedicato e produce il PDF in 3–4 secondi. Il file viene caricato su S3, poi inviato via Nodemailer al cliente e al commerciale. In parallelo, la stessa offerta viene inviata a HubSpot via API: upsert del contatto, creazione del deal con tutti i campi custom della configurazione, associazione al commerciale responsabile.
Due settimane di test con 8 commerciali e 3 agenti esterni. Ho rilevato 2 regole di compatibilità mancanti (casi rarissimi mai emersi nelle interviste) e 1 sconto cliente non applicato correttamente su una famiglia di prodotti. Fix rapidi grazie al motore a regole configurabile — nessun deploy per correggere le regole. Go-live con rollout graduale: prima la rete commerciale interna, poi gli agenti, infine i clienti self-service dopo 3 settimane di stabilità.
Soluzione: motore regole e pricing Node.js
Il motore di regole:
1.247 vincoli, zero hardcoding.
La scelta architetturale più importante è stata separare nettamente le regole di business dal codice applicativo. Ogni volta che l'ufficio tecnico aggiunge una nuova variante o modifica una compatibilità, aggiorna una riga su database — senza toccare il deploy.
Rule engine configurabile — modificabile senza codice
Ogni regola è una riga PostgreSQL con quattro campi: param_key,
param_value, excluded_key, excluded_values
e una priority per la gestione dei conflitti. Il motore Node.js carica
le regole rilevanti per la configurazione corrente, le valuta in ordine e restituisce
un array di opzioni valide per il passo successivo. L'ufficio tecnico
gestisce le regole da un pannello admin costruito con React Table — nessun
intervento del developer per aggiungere o modificare vincoli.
PDF in 4 secondi — identico al modello cartaceo
Puppeteer renderizza un template HTML/CSS con i dati dell'offerta iniettati server-side. Il template replica esattamente il formato cartaceo storico dell'azienda: intestazione con logo vettoriale, tabella parametri tecnici con unità di misura, breakdown prezzo, condizioni di fornitura, validità offerta e firma del commerciale come immagine PNG firmata digitalmente. Il worker Puppeteer gira in un processo separato per non bloccare il thread Express principale — con timeout di 10 secondi e retry automatico in caso di crash. Tempo medio di generazione: 3,8 secondi.
CRM sempre aggiornato — senza toccare HubSpot
Ogni offerta generata innesca una sequenza asincrona: prima il PDF viene caricato su S3,
poi parte il job di sincronizzazione HubSpot. Il job cerca il contatto per email —
se esiste lo aggiorna, se non esiste lo crea. Poi crea o aggiorna il deal con un campo
custom offerta_id come chiave di idempotenza: se per qualsiasi ragione
il job gira due volte, non crea un duplicato. I commerciali trovano ogni offerta in
HubSpot già associata al contatto giusto, con il PDF allegato, il valore del deal
e la pipeline stage impostata su "Offerta inviata". Zero inserimenti manuali
da quando il sistema è online.
Dato post go-live: nei primi 3 mesi il sistema ha generato 412 offerte e sincronizzato 412 deal in HubSpot. Zero duplicati rilevati. Il responsabile commerciale ha smesso di fare il "giro serale" per aggiornare il CRM manualmente.
Stack tecnologico Node.js React PostgreSQL
Node.js al centro.
Ogni strumento al suo posto.
Perché Node.js e non PHP/Laravel?
Il pricing engine valuta decine di regole in sequenza per ogni richiesta — un'operazione CPU-bound veloce ma ad alta frequenza. Node.js gestisce meglio la concorrenza I/O-bound tipica di un'API che fa molte query Redis e PostgreSQL in parallelo, senza il overhead del thread model di PHP-FPM. Inoltre il team aveva già familiarità con JavaScript: usare TypeScript sia sul frontend che sul backend ha ridotto il contesto switching e i bug di interfaccia tra i due layer.
Perché Puppeteer e non una libreria PDF?
Librerie come PDFKit o jsPDF richiedono di costruire il layout programmaticamente — ogni riga, ogni tabella, ogni margine definito in codice. Il template HTML/CSS è infinitamente più manutenibile: un grafico può modificare l'aspetto dell'offerta cambiando CSS, senza toccare JavaScript. Il prezzo è un processo leggermente più pesante, risolto con il worker isolato e il pre-warm di Puppeteer all'avvio del server.
Risultati configuratore B2B: -70% ciclo offerta
Da 5 giorni a 20 minuti.
412 offerte in 3 mesi.
Dati rilevati nei primi 3 mesi dopo il go-live completo (commerciali interni + agenti + clienti self-service), confrontati con lo stesso periodo dell'anno precedente.
«Il primo cliente che ha usato l'accesso self-service ci ha inviato un ordine alle 22:30 di un venerdì sera. Prima avrebbe dovuto aspettare lunedì mattina. Quella sera abbiamo capito che il sistema funzionava davvero.»
— Direttore commerciale, 3 mesi dopo il go-liveLearnings sviluppo configuratore prodotti
Cosa porterei
nel prossimo progetto.
Separare le regole di business dal codice è un investimento che si ripaga subito. Nelle prime settimane dopo il go-live sono state aggiunte 23 nuove regole di compatibilità per nuovi prodotti — tutte gestite dall'ufficio tecnico dal pannello admin, senza nessun intervento di sviluppo.
Il pricing deve essere calcolato sempre e solo lato server. Avevo valutato l'opzione di calcolare il prezzo nel frontend per ridurre le chiamate API. L'ho scartata subito: esporre i coefficienti di listino nel JavaScript del browser avrebbe significato regalare alla concorrenza la struttura dei prezzi. Il debounce a 300ms rende l'esperienza percepita comunque real-time.
Il salvataggio automatico della sessione vale sempre il costo di implementazione. Durante l'UAT, due commerciali hanno perso una configurazione per un refresh accidentale. Da quel momento il salvataggio automatico è diventato un requisito non negoziabile per qualsiasi web app con form complessi.
L'idempotenza dei job di sync non è un dettaglio — è fondamentale.
In produzione, il job HubSpot ha girato due volte sullo stesso deal in 3 occasioni
(timeout + retry). Senza il check sull'offerta_id avremmo avuto
6 deal duplicati nel CRM. L'idempotenza ha salvato la qualità dei dati nel momento
più critico: i primi giorni dopo il lancio.
Il self-service B2B cambia il rapporto con il cliente più di qualsiasi funzionalità. I clienti che usano l'accesso diretto generano il 34% delle offerte fuori dall'orario di ufficio. Non chiedono sconti extra, non negoziano il prezzo — perché il processo trasparente e veloce crea una fiducia diversa rispetto alla telefonata con il commerciale.
Hai un processo di vendita che merita di essere automatizzato?
Configuratori, preventivi, cataloghi complessi — se la logica esiste già, si può codificare.