Per i gestionali complessi uso Angular sul frontend, NestJS sul backend e TypeScript su tutto lo stack. Non perché siano «i migliori» in assoluto, ma perché danno a un’applicazione grande e longeva una struttura chiara, contratti tipizzati tra le parti e un solo linguaggio per tutto il team. Hanno anche dei limiti, e per alcuni progetti sceglierei altro: li vediamo in fondo.
Il problema non è scegliere il framework migliore
Un gestionale non è un sito vetrina. Ha decine di schermate, form lunghi con regole incrociate, ruoli e permessi, e soprattutto una vita lunga: verrà modificato per anni, spesso da persone diverse da chi l’ha scritto. La domanda giusta quindi non è «quale framework è più veloce o più di moda», ma «con quale stack questo progetto resterà comprensibile e modificabile da chi lo manterrà».
Perché Angular per applicazioni gestionali
Angular è un framework completo e con opinioni precise. Per un back-office di grandi dimensioni questo è un vantaggio:
- Form. I reactive forms gestiscono bene form lunghi, campi dipendenti l’uno dall’altro, validazioni sincrone e asincrone.
- Routing. Lazy loading delle sezioni e guard sulle rotte per nascondere aree a chi non ha i permessi.
- Dependency injection. Servizi iniettabili e facili da sostituire nei test.
- Struttura uniforme. Due progetti Angular si somigliano: chi entra nel codice sa dove cercare.
- Componenti pronti. Angular Material offre tabelle, dialog, date picker e form field coerenti, utili quando l’interfaccia è fatta soprattutto di dati.
Perché NestJS sul backend
NestJS porta sul backend Node.js un’organizzazione simile a quella di Angular:
- Moduli che separano i domini (prenotazioni, fornitori, pagamenti) e dichiarano cosa espongono.
- Dependency injection, che rende i servizi componibili e testabili.
- Guard per autenticazione e autorizzazione, applicate in modo dichiarativo sui controller.
- Pipe di validazione che controllano i dati in ingresso prima che arrivino alla logica.
- Code e job in background, tramite le integrazioni ufficiali, quando servono elaborazioni asincrone.
Chi conosce Angular si orienta in fretta in un progetto NestJS, e viceversa.
TypeScript end-to-end
Usare TypeScript su frontend e backend significa:
- tipi condivisi: la forma di una prenotazione è definita una volta sola e usata da entrambe le parti;
- refactoring più sicuri: se rinomino un campo, il compilatore segnala ogni punto da aggiornare, nel client e nel server;
- un solo linguaggio per il team: meno cambi di contesto, revisioni del codice più semplici, persone che possono lavorare su tutto lo stack.
C’è però un limite importante: TypeScript non valida i dati a runtime. I tipi spariscono dopo la compilazione; una richiesta HTTP può contenere qualsiasi cosa. Validazione esplicita e test restano necessari.
DTO e contratti condivisi
La soluzione che uso è separare il contratto dalla validazione. Il tipo vive in una libreria condivisa:
// libs/shared/types/src/prenotazione.ts
export interface CreaPrenotazione {
clienteId: string;
data: string; // ISO 8601
persone: number;
}
Il backend lo implementa con un DTO che aggiunge le regole di validazione:
// apps/api/src/prenotazioni/crea-prenotazione.dto.ts
import { IsISO8601, IsInt, IsUUID, Min } from 'class-validator';
import type { CreaPrenotazione } from '@gestionale/shared/types';
export class CreaPrenotazioneDto implements CreaPrenotazione {
@IsUUID() clienteId!: string;
@IsISO8601() data!: string;
@IsInt() @Min(1) persone!: number;
}
Con il ValidationPipe di NestJS attivo, una richiesta che non rispetta queste regole viene respinta prima di toccare la logica. Il frontend usa la stessa interfaccia per tipizzare le chiamate: se il contratto cambia, la compilazione segnala il problema su entrambi i lati.
Nx e monorepo
Frontend, backend e librerie condivise stanno nello stesso monorepo Nx, con regole che impediscono dipendenze sbagliate tra le parti. Ho descritto la struttura che uso in un articolo dedicato: come organizzo un gestionale in un monorepo Nx.
Un esempio di architettura
Uno schema illustrativo, da adattare a ogni progetto:
Angular (back-office)
↓ HTTP/JSON, tipi condivisi
NestJS API: guard, validazione, controller
↓
Servizi di dominio: prenotazioni, fornitori, documenti
↓
PostgreSQL o MySQL
↔ Redis e code, solo se servono job asincroni
↔ provider esterni: pagamenti, email, altri software
Il gestionale per un’agenzia viaggi che ho sviluppato usa proprio questo stack: Nx, Angular, NestJS e MySQL. Conviene isolare ogni integrazione con software esterni in un modulo dedicato, così un cambio di fornitore non si propaga al resto del codice; ne parlo nell’articolo su API e integrazioni tra software aziendali.
Quando non sceglierei Angular + NestJS
- Siti di contenuto e landing page. Per un sito come questo uso Astro: Angular sarebbe sovradimensionato.
- Siti gestiti da un CMS, dove chi scrive i contenuti ha bisogno di un editor e non di un’applicazione.
- MVP molto semplici da validare in fretta, dove la struttura di Angular pesa più di quanto restituisca.
- Team con competenze diverse. Se chi manterrà il software lavora in PHP o in un altro stack, spesso conviene restare lì: uso PHP anch’io quando il contesto lo richiede.
- Software esistente che funziona. Riscrivere solo per cambiare framework raramente ha senso; ne parlo nell’articolo su quando evolvere un software legacy e quando riscriverlo.
Va detto anche che Angular ha una curva di apprendimento più ripida di librerie più leggere: è un costo che si ripaga su applicazioni grandi, non su quelle piccole.
Manutenibilità nel lungo periodo
Nessuno stack garantisce che un software resti facile da mantenere. Quello che aiuta è la combinazione di struttura prevedibile, tipi condivisi, validazione esplicita, test e confini chiari tra i moduli. Conta anche aggiornare le dipendenze con regolarità invece di accumulare versioni arretrate. Nei miei progetti codice sorgente e documentazione vengono consegnati al cliente, così chi arriverà dopo può partire da una base leggibile.
Se devi costruire o far evolvere un’applicazione gestionale complessa, possiamo ragionare insieme sull’architettura. Trovi come lavoro sui gestionali su misura, oppure puoi contattarmi.
Domande frequenti
TypeScript sostituisce la validazione dei dati?
No. TypeScript controlla il codice in fase di compilazione, ma i dati che arrivano da una richiesta HTTP vanno validati a runtime, per esempio con DTO e pipe di validazione.
Quando conviene un monorepo Nx?
Quando frontend e backend condividono tipi e logica e vengono sviluppati insieme. Per un singolo progetto piccolo può essere più struttura del necessario.
