Preloader
Drag
Il gestionale GNAMMM aperto sul computer e il menu digitale sul telefono
Web App

GNAMMM: il menù digitale che diventa il gestionale del ristorante

Piattaforma SaaS multi tenant per ristoranti: il cliente apre il menù inquadrando un QR, il ristoratore governa carta, ordini, prenotazioni e clienti, il cameriere prende la comanda al tavolo con un palmare che la stampa.

  • ristoranti attivi

  • servizi in produzione

  • tabelle, un database solo

  • ×

    più veloce l'analytics ordini

In sintesi

In breve

Un PDF online non fa guadagnare niente

Nel 2024 il menù con il QR era già una cosa comune: decine di servizi trasformavano un PDF in una pagina web. Il punto è che un PDF online non porta un euro in più a un ristorante. Non dice quali piatti vengono guardati e non ordinati, non raccoglie un contatto, non prende una prenotazione, non manda una comanda in cucina.

GNAMMM parte dal menù, l’unica cosa che il cliente apre spontaneamente senza installare niente, e lo usa come porta d’ingresso per i dati: ogni scansione è un cliente che entra nel sistema. È una scelta che ha deciso l’architettura prima della prima riga di codice, perché il menù deve essere velocissimo e pubblico mentre il gestionale deve essere ricco e protetto. Col tempo sono diventati due backend diversi.

Lo stesso menu digitale con tre temi diversi, uno per ogni ristorante

Lo stesso codice, un aspetto per ogni locale

Il menù del cliente è una web app in React e Ionic, servita come PWA. Il percorso è QR, pagina, menù: un’app da installare avrebbe fermato il cliente al primo passo.

La parte che conta non è la lista dei piatti, è la personalizzazione. Colori, carattere, raggio dei bordi, sfondi e disposizione arrivano al caricamento dal tema salvato sul database, quindi due ristoranti sullo stesso dominio non si somigliano. Qui accanto c’è lo stesso identico codice con tre temi diversi: un chalet di pesce, una burgheria e un locale notturno.

Dal menù all'ordine, alla prenotazione, alla recensione

La scheda prodotto non è una riga di listino: porta la foto, gli allergeni con le icone, le aggiunte configurabili come farciture, granelle e varianti di formato, i contrassegni tipo il più venduto e il pulsante per mettere nel carrello, quando il locale ha attivato l’ordinazione.

Dallo stesso menù il cliente ordina al tavolo, da asporto o in consegna, prenota un tavolo e lascia una recensione. Tre percorsi che nel gestionale sono poi diventati tre sezioni intere, con il carrello che tiene anche le note per singolo piatto.

Scheda prodotto con foto, allergeni e aggiunte, e carrello con le note per piatto
Catalogo prodotti del gestionale, con filtri, prezzi e disponibilita

Il gestionale del ristoratore

La dashboard è in Next.js 15 con TypeScript e Tailwind: circa duecento hook, uno per ogni operazione delle API, e una cinquantina di aree funzionali. La home è un quadro di analytics con ordini, fatturato, clienti unici e il confronto fra tutti i locali dello stesso proprietario, perché molti clienti hanno più di un ristorante.

Prodotti, menù, categorie e aggiunte si riordinano trascinandoli, con filtri per disponibilità e giacenza e un sistema di caratteristiche (vegano, piccante, senza glutine, fatto in casa) che conta 24 voci comuni più quelle del singolo locale. Accanto ci sono la board degli ordini a tre colonne divisa per canale, le sale con i tavoli, le prenotazioni a calendario, il programma fedeltà, l’anagrafica clienti e i messaggi su WhatsApp Business.

L'editor del tema, con l'anteprima viva

È la schermata di cui vado più orgoglioso. Il ristoratore cambia colore del marchio, carattere, raggio dei bordi e sfondi, e vede il risultato mentre lo cambia, dentro un telefono simulato sulla stessa pagina. Niente salvataggi alla cieca, niente ricarica la pagina e guarda com’è venuta.

Il tema non è un foglio di stile scritto a mano per ogni cliente: sono valori sul database che il menù legge all’avvio. Per questo un locale cambia faccia senza che nessuno debba rilasciare una versione nuova.

Editor del tema del ristorante, con l anteprima che si aggiorna dentro un telefono simulato
Pagina pubblica che raccoglie i ristoranti della piattaforma, filtrabile per citta

Un menù in React che Google riesce a leggere

Una pagina costruita in JavaScript è invisibile a metà dei programmi che indicizzano il web. Qui la soluzione è il dynamic rendering: nginx riconosce il programma che sta chiedendo la pagina e lo manda su un indirizzo Python che restituisce HTML completo, con titolo, descrizione, Open Graph e dati strutturati del ristorante, del menù e degli orari. Le persone continuano a ricevere la web app.

Il file robots.txt e la sitemap sono generati dal database: un ristorante nuovo entra in sitemap da solo, senza ricostruire niente, e restano fuori i locali senza prodotti, quelli in costruzione e quelli disattivati. C’è anche una pagina pubblica che raccoglie tutti i locali della piattaforma e si filtra per città: fra quelle presenti ci sono Giulianova e Roseto degli Abruzzi.

Prima misurare, poi riscrivere

Nell’estate 2026 il gestionale era diventato lento, e la richiesta naturale sarebbe stata riscrivere il backend. Prima di scrivere una riga ho misurato l’infrastruttura, e il quadro era un altro: il backend girava con un solo processo di lavoro sincrono mentre la piattaforma gli mandava fino a 80 richieste insieme, il database era l’istanza più piccola disponibile, condivisa da cinque servizi e per giunta in una regione diversa, e nessun servizio aveva istanze sempre accese.

Rimessa a posto la configurazione del server applicativo, due processi con otto thread ciascuno, e ridotto il numero di connessioni al database per non spostare la coda da una parte all’altra, dieci richieste in parallelo sono passate da 879 a 352 millisecondi. Solo a quel punto ho riscritto, e neanche tutto insieme: un secondo backend FastAPI affiancato al Flask, con le rotte spostate una risorsa per volta, prima le letture e per ultime le scritture. Una mappa che dice quale backend serve quale risorsa, in un file solo del frontend, permette di spostare una risorsa, o di riportarla indietro, cambiando una riga. L’analytics degli ordini su un anno è passata da 110 secondi a mezzo secondo: non per un algoritmo più furbo, ma perché una catena di query annidate è diventata un numero fisso di aggregazioni.

Analytics degli ordini per ora del giorno e per giorno della settimana

Il tempo reale, senza un secondo archivio

Una board ordini che si aggiorna a intervalli significa comande viste con mezzo minuto di ritardo. Nel gestionale c’erano tre tentativi di tempo reale abbandonati: un pezzo di codice che puntava a un indirizzo mai scritto, un client commentato e un server che con un processo sincrono non avrebbe funzionato comunque. Li ho tolti tutti e ne ho fatto uno che funziona, con i Server Sent Events sul backend FastAPI, dove una connessione aperta è una procedura sospesa e non un processo bloccato.

Le scelte meno ovvie sono due. Niente secondo archivio dati: un database apposta per il tempo reale avrebbe voluto dire una doppia scrittura che può perdere ordini e un secondo sistema di autenticazione da tenere allineato. E il flusso non trasporta i dati, segnala soltanto che qualcosa è cambiato: la lista resta l’unica fonte di verità, così un messaggio perso non lascia la pagina in uno stato incoerente. Per le prenotazioni, che non avevano una colonna con la data di modifica, il cambiamento si riconosce da una firma calcolata su stato, coperti, tavolo e orario.

Il palmare che stampa la comanda al tavolo

L’ultimo capitolo è hardware. I ristoratori chiedevano una cosa che il browser non può dare: prendere la comanda al tavolo e stamparla subito, anche con il wifi che va e viene. Il palmare è un’app Kotlin con Jetpack Compose per un terminale industriale con stampante termica da 58 millimetri, NFC e lettore di codici. Il produttore non fornisce strumenti di sviluppo, quindi il modo di parlare con la stampante è stato ricostruito dal programma di sistema.

L’app legge soltanto dal database che ha a bordo e lascia che sia la rete ad aggiornarlo in sottofondo, così il cameriere non aspetta mai una risposta dal server. Gli ordini creati e i cambi di stato finiscono in una coda d’uscita e partono quando la linea torna, con una chiave che impedisce i doppioni se la risposta si perde per strada. I palmari sono sparsi nei locali, quindi una versione nuova se la scaricano e se la installano da soli.

Home del sito vetrina di GNAMMM, con la presentazione del menu digitale

Dieci servizi, un database solo

Oggi la piattaforma è fatta da un backend Flask che scrive, quattro servizi FastAPI che servono il menù pubblico, il gestionale con il tempo reale, il pannello di amministrazione e la traduzione dei menù con un modello linguistico, un microservizio per i messaggi WhatsApp, tre interfacce, l’app Android e il sito vetrina in WordPress, tenuto fuori dal cloud apposta, perché il marketing possa cambiare una frase senza un rilascio.

La scelta più discussa è il database unico, ed è deliberata: con dieci servizi e una squadra minuscola, dieci database avrebbero voluto dire dieci copie della stessa tabella da tenere allineate. Il prezzo è che una modifica allo schema tocca cinque servizi insieme, quindi le regole sono rigide: colonne sempre compatibili con il passato e un ordine di rilascio obbligato, prima lo schema, poi i servizi, infine le interfacce. Lo sviluppo in locale resta però un comando solo: un Makefile accende il collegamento al database, cinque backend e tre frontend su porte fisse, anche in più sessioni di lavoro contemporanee sulla stessa macchina.

Il pacchetto

Cosa è stato consegnato

In dettaglio

Scheda tecnica

Le schermate vengono dai sistemi in produzione: i dati del gestionale sono quelli di un account dimostrativo, i menù sono quelli pubblici dei locali attivi. Numeri rilevati a ottobre 2026.

Parliamone

Ti serve un software così?

Se hai un processo che oggi gestisci a mano e vorresti automatizzare, raccontamelo: capiamo insieme se ha senso costruirci sopra uno strumento.

Serve qualcosa di simile? Questo progetto è un esempio di sviluppo di web app e gestionali su misura. Il primo incontro e il preventivo sono gratuiti: scrivimi e ne parliamo.