gentiluomo — estetica e benessere per l'uomo
Piano di sviluppo/ Gestionale CRM/ 4 settembre 2026/ Laravel · React · Expo

Dalle specifiche
al software, a SAL

Sei stati di avanzamento su otto settimane, dal 7 settembre al 31 ottobre. Ognuno chiude con qualcosa di realmente testabile online e con la stessa checklist di verifica. Le decisioni sono prese; quello che manca è dichiarato.

01

Identità visiva e design system

Il marchio è rigorosamente monocromo: nero e bianco puri, nessun colore d'accento. È una scelta forte e vincola l'interfaccia — la gerarchia si costruisce con peso, scala e spazio, non con il colore.

Il principio

Il vincolo monocromo è del logo, non dell'interfaccia. #000000 su #FFFFFF a tutta pagina, per otto ore di uso continuato, affatica: nero e bianco puri restano al logo e a pochissimi elementi di enfasi massima. Tutto il resto vive su una scala di grigi a 12 gradini con semantica fissa, e il colore compare solo come stato.

Scala grigi — 12 step

01sfondo app
02sfondo tenue
03componente
04hover
05attivo
06separatori
07bordi input
08bordo hover
09solido
10solido scuro
11testo tenue
12testo pieno

Lo step 07 è il bordo dei campi, non un grigio chiaro decorativo: quando il bordo è l'unico modo di riconoscere un campo, WCAG 1.4.11 impone 3:1. È la violazione più frequente nei design monocromi, e la evitiamo per costruzione.

Stati — l'unico posto dove entra il colore

Da confermare Confermato Completato In ritardo No-show Conflitto risorsa

Ogni stato porta sempre un'etichetta oltre al colore: in bianco e nero deve restare riconoscibile (WCAG 1.4.1). Valori funzionali presi dal GOV.UK Design System, già collaudati: errore #CA3535, successo #0F7A52, focus #FFDD00 su testo #0B0C0C.

Il focus da tastiera è trattato come colore funzionale a sé, giallo pieno: un anello grigio su fondo grigio è invisibile, e questa è un'app che si usa tutto il giorno anche da tastiera.

Tipografia — le font del marchio

Maven Pro 700 · titoli e numeri di rilievo
Agenda di giovedì
Mulish 400/600 · testo, tabelle, moduli
Percorso EpilGent, seduta 4 di 12. Residuo Gentil Card 1.240 €. La seconda operatrice si libera alle 15:30.
IBM Plex Mono · importi, orari, codici
10:00 – 11:30  ·  1.240,00 €  ·  TESS-0042

Maven Pro e Mulish non sono una scelta mia: sono le font già in uso su gentiluomoestetica.it, lette dal CSS del sito in produzione. Entrambe su Google Fonts, nessuna licenza da comprare. Aggiungo IBM Plex Mono per i dati, perché importi e orari incolonnati richiedono cifre a larghezza fissa: senza tabular-nums una colonna di euro non si legge.

Componenti

Base shadcn/ui su Base UI + Tailwind. shadcn non è una libreria ma un modello di distribuzione: il sorgente dei componenti vive nel nostro repo e si riscrive liberamente. Con Mantine o Ant Design passeremmo il tempo a combattere contro un tema di default che non è il nostro.

Pattern presi da prodotti reali

ProdottoCosa gli rubiamo
MangomintI requisiti di risorsa stanno sul servizio, non sull'appuntamento: il sistema alloca da sé. Scaldacera 1 e Scaldacera 2 sono due entità distinte in un gruppo, non una risorsa con quantità 2.
PhorestIl conflitto di risorsa è un avviso bloccante morbido: si può forzare, ma chi forza e quando resta tracciato.
FreshaBlocco orario inseribile in pochi secondi (pausa, formazione, manutenzione) e tempo extra di servizio oltre la durata — decisivo per cera e laser, quasi sempre dimenticato.
Nielsen NormanScheda cliente in pannello laterale non modale: il modale nasconde i dati di riferimento proprio mentre servono. Quantità con barre, mai torte o tachimetri.
LinearDensità dalla tipografia invece che dalla cornice, navigazione minima, palette comandi e scorciatoie per le tre azioni ad altissima frequenza: nuovo appuntamento, cerca cliente, incassa.
02

Stack definitivo

Verificato sul server reale, non assunto: PHP 8.4, Redis 6.2 attivo, Supervisor 4.2.5, 4 core e 15 GB di RAM. Horizon è praticabile.

AmbitoSceltaPerché
BackendLaravel 13 · PHP 8.4Major stabile con supporto sicurezza fino a marzo 2028. PHP 8.4 già disponibile nel pool Plesk
DatabaseMariaDB 10.5Quella installata. Fuori supporto da giugno 2025: aggiornamento da mettere in conto
CodeRedis + Horizon + SupervisorTutto già presente sul server. Code separate: default, notifiche, sync, report
AuthSanctum 4Cookie stateful per la SPA, token bearer per le app. La doc di Passport rimanda esplicitamente qui
Multi-tenanttrait BelongsToCentroGlobal scope su centro_id. Con 5-9 tenant e un solo database, i pacchetti dedicati aggiungono peso senza vantaggio
Permessispatie/laravel-permissionCon teams=true su centro_id: la stessa persona può avere ruoli diversi in centri diversi
Auditspatie/laravel-activitylogCopre anche eventi non-Eloquent: login, export, invio notifica
Contabilitàledger append-onlyIncassi, prima nota, Gentil Card e sedute come righe immutabili; gli storni sono righe negative. Nessun log di audit è fonte di verità contabile
FrontendReact 19 + ViteSPA statica dietro autenticazione: zero SEO, Next.js aggiungerebbe un runtime Node senza ritorno
App mobiliExpo SDK 57 + Expo RouterDue app, operatrici e cliente. EAS Build compila iOS anche senza Mac
Codice condivisomonorepo pnpm + TurborepoSi condivide logica, non interfaccia: schemi Zod, tipi, client API, regole di dominio
Stato serverTanStack QueryCache, deduplica e coda mutazioni offline già risolte. Zustand solo per lo stato locale
FormReact Hook Form + ZodUno schema solo: valida il web, valida il mobile, tipizza il payload, si rispecchia nelle FormRequest
CalendarioDayPilot LiteApache 2.0, gratuito, include sia lo scheduler a righe sia la vista a colonne per risorsa. Attribuzione obbligatoria; la validazione durante il trascinamento la fa il server, che è comunque l'unico arbitro valido
Test backendPest + MySQL realeMai SQLite: non riproduce il locking InnoDB e i test di concorrenza passerebbero falsamente
Test frontendVitest + PlaywrightUnitari e percorsi end-to-end reali sul browser
Decisione che va presa prima di scrivere l'autenticazione

Sanctum in modalità cookie richiede che SPA e API stiano sotto lo stesso dominio di secondo livello. Con gentiluomo.nubelab.it e backend.gentiluomo.nubelab.it la condizione è soddisfatta. Se in produzione si passa a gentiluomoestetica.it, vanno spostati entrambi insieme: separarli obbliga a riscrivere l'autenticazione.

03

Struttura del repository

Monorepo unico: un solo posto dove le regole di dominio esistono, tre applicazioni che le consumano.

gentiluomo/
├── apps/
│   ├── api/              Laravel 13 — backend, unica fonte di verità
│   ├── gestionale/       React + Vite — dashboard desktop del centro
│   ├── operatrici/       Expo — app staff: agenda, timbratura, incassi
│   └── cliente/          Expo — app cliente: prenota, storico, card
├── packages/
│   ├── core/             schemi Zod, tipi, regole di dominio condivise
│   ├── api-client/       client HTTP tipizzato, generato dal contratto
│   └── ui/               token di design e componenti web condivisi
├── mocks/               fake server dei servizi esterni
├── assets/brand/        loghi, icone, manifest d'uso
├── docs/                specifiche v2.0, piano, contratto API
└── infra/               deploy, systemd, nginx, backup
SottodominioCosa serve
gentiluomo.nubelab.itGestionale desktop (SPA)
backend.gentiluomo.nubelab.itAPI Laravel
docs.gentiluomo.nubelab.itDocumentazione — già online
mock.gentiluomo.nubelab.itFake server dei servizi esterni
04

Seed e fake server

Nessuna attesa sul cliente: si sviluppa su dati finti realistici e su un server che imita i servizi esterni. Il passaggio alla realtà sarà solo una variabile d'ambiente e una chiave.

Il seed

Dati di prova che riproducono la realtà del centro di Aosta: due centri (Aosta reale e un secondo fittizio, per provare l'isolamento), personale con turni e ferie, il listino completo dalle specifiche, clienti con storici diversi, Gentil Card a saldi vari, percorsi a stadi diversi di avanzamento.

La regola che rende il seed utile è che non deve contenere solo casi felici. Genera deliberatamente le situazioni che rompono il software:

  • due trattamenti a cera parzialmente sovrapposti, al limite dei due scaldacera;
  • una Gentil Card a saldo zero e una con residuo insufficiente per il trattamento prenotato;
  • un percorso all'ultima seduta e uno scaduto da sollecitare;
  • un'operatrice in ferie con appuntamenti già presi prima della richiesta;
  • un centro con una sola cabina, che satura subito;
  • lo stesso nome e cognome cliente in due centri diversi;
  • un cliente con no-show non regolarizzato che prova a riprenotare.

Faker in italiano con seme fisso, date ancorate a una data base costante e non a oggi: due esecuzioni del seed devono produrre lo stesso database, altrimenti i test diventano capricciosi.

Il fake server

Un solo processo che monta tutti i provider su prefissi distinti, mantenendo i path reali dopo il prefisso. Il passaggio mock → sandbox → produzione è solo SUMUP_BASE_URL e simili: zero if (env) nel codice di business.

ServizioCosa mocchiamoSandbox ufficiale
SumUpCheckout, storico transazioni, payout, rimborsi, lettore Solo, webhook di statoSì, stesso host. Mock per lavoro offline e CI
WhatsApp Cloud APIInvio template, stati sent/delivered/read/failed, webhook firmatiSolo numeri di test, non riflette limiti né costi
Skebby SMSLogin con sessione che scade, invio, polling statoNon documentata: mock indispensabile
Resend emailInvio e webhook firmati SvixNon verificata
SatispayFirma RSA, pagamenti, lista per riconciliazione, reportSì ma non self-service: si richiede via form
Scalapay · KlarnaOrdini, cattura, rimborsi, pagina di checkout finta, webhookSì, entrambi
Due regole non negoziabili sul mock

Deve firmare davvero i webhook. Se il mock manda payload non firmati, la verifica della firma non viene mai esercitata e va in produzione rotta.

Deve saper fallire. Importi che danno sempre errore, template non approvati, eventi fuori ordine, firme sbagliate, il nostro endpoint che risponde 500. Un mock che risponde sempre bene serve solo a farci credere che funzioni.

05

Checklist di chiusura, uguale per ogni SAL

Nessun SAL è chiuso finché non passa questi cinque punti. Sono l'ultimo task di ogni SAL, sempre gli stessi.

C1
Test automatici delle API sviluppate nel SAL Ogni endpoint nuovo: caso felice, dati non validi, permessi mancanti, tenant sbagliato, risorsa inesistente. Per l'agenda anche i test di concorrenza, con due connessioni reali sullo stesso slot: esattamente una deve vincere.
C2
Revisione del codice file per file Coerenza con le convenzioni già stabilite, vulnerabilità (injection, autorizzazioni mancanti, dati esposti, segreti nel codice), query inefficienti e problemi N+1, leggibilità, duplicazioni e codice morto. Ogni file toccato nel SAL, senza campionamento.
C3
Debug funzione per funzione Ogni funzione percorsa passo passo con dati reali del seed, compresi i casi limite: valore nullo, lista vuota, numero negativo, data nel passato, stringa lunghissima, doppia sottomissione.
C4
Collaudo come lo farebbe una persona Si percorre l'applicazione come un'operatrice reale: ogni link, ogni bottone, ogni campo di ogni form. Campi obbligatori lasciati vuoti, formati sbagliati, doppio clic sul salva, tasto indietro del browser, aggiornamento pagina a metà procedura, sessione scaduta, finestra stretta da telefono. Si verifica che ogni errore dica cosa è andato storto e come si rimedia.
C5
Deliverable online e collaudabile Il risultato del SAL è pubblicato sui sottodomini e provabile senza chiedere aiuto, con utenze di prova pronte e una nota di cosa guardare.
06

I sei SAL

Quaranta giorni lavorativi, dal lunedì 7 settembre al 31 ottobre. Ogni SAL chiude con qualcosa che puoi aprire e provare, e con la stessa checklist di verifica.

Come ci sta l'ambito pieno in otto settimane

Il settimo SAL non è stato tagliato: è stato ridistribuito. La migrazione da Treatwell entra nel SAL 1, dove l'import da CSV era già previsto. Le statistiche entrano nel SAL 3, dove i dati economici nascono. Accesso casa madre, provisioning e messa in produzione entrano nel SAL 5. Backup, monitoraggio e irrobustimento diventano parte della checklist di chiusura di ogni SAL invece di una fase finale.

Il margine è zero. Ogni imprevisto — la questione del macchinario NIR, l'export Treatwell, l'iter art. 4 — si mangia direttamente giorni di consegna. Lo scrivo una volta e poi lavoro.

SAL 0

Fondamenta e identità

7 → 11 set
  1. Monorepo pnpm + Turborepo, convenzioni, linting, formattazione, hook pre-commit.
  2. Design system in codice: token dei 12 grigi, stati semantici, tipografia, componenti base shadcn ritematizzati.
  3. Laravel 13 su PHP 8.4, database dedicato, Redis, Horizon sotto Supervisor.
  4. Sottodomini gentiluomo, backend.gentiluomo, mock.gentiluomo con certificati.
  5. Autenticazione Sanctum, login, logout, sessione, ruoli di base.
  6. Script di deploy ripetibile e primo rilascio automatico.
Cosa provi alla fine

Una guida di stile navigabile online con tutti i componenti nei loro stati, e il gestionale che ti fa entrare con utente e password. L'API risponde al controllo di salute.

SAL 1

Anagrafiche, dati e migrazione

14 → 18 set
  1. Schema completo secondo le specifiche v2.0, con centro_id ovunque e indici unici composti.
  2. Isolamento per centro, ruoli con ambito, registro di audit.
  3. Seed completo con tutti i casi difficili, non solo quelli felici.
  4. Anagrafica clienti: elenco, ricerca, scheda in pannello laterale, note, consensi.
  5. Personale, listino trattamenti, risorse fisiche con i requisiti sul servizio.
  6. Migrazione Treatwell: import CSV con anteprima, correzione errori e quadratura prima di scrivere.
Cosa provi alla fine

Carichi il CSV vero dei clienti e li vedi comparire. Cerchi un cliente, apri la scheda, la modifichi. Verifichi che un utente di Aosta non riesca a vedere i clienti dell'altro centro.

SAL 2

Agenda — il cuore del sistema

21 set → 2 ott
  1. Orari di apertura, turni mensili, ferie e assenze con causale che bloccano gli slot.
  2. Motore di disponibilità con occupazione risorse a segmenti: copre lo SkinGent che libera il macchinario al minuto 30 e lo scrub che occupa la doccia solo per la sua fase.
  3. Assegnazione del personale a intervalli: Combo Full Body con rilascio della seconda operatrice.
  4. Blocco transazionale contro la doppia prenotazione, con test di concorrenza reali.
  5. Vista a colonne per operatrice e vista a righe per macchinario su DayPilot Lite, spostamento con trascinamento validato dal server.
  6. Appuntamento a testata e righe, buffer di 10 minuti in coda al blocco, lista d'attesa con precedenza di 4 ore.
Cosa provi alla fine

Prenoti davvero. Provi a mettere due laser in contemporanea e il sistema te lo impedisce spiegando perché. Sposti un appuntamento trascinandolo. Metti un'operatrice in ferie e gli slot spariscono.

SAL 3

Denaro, cassa e statistiche

5 → 16 ott
  1. Gentil Card: fasce bonus, saldo unico, scalo automatico, storico movimenti.
  2. Percorsi con composizione a zone, avanzamento, stato «da sollecitare», bonus percorso separato.
  3. Consulenza con sconto a termine e avviso 24 ore prima della scadenza.
  4. Preventivo in PDF con il lockup del marchio, inviabile via email o WhatsApp.
  5. Incassi con i sei metodi, prima nota con uscite e versamenti, chiusura mensile.
  6. Fake server dei pagamenti e adattatori pronti per le chiavi reali.
  7. Statistiche del centro: venduto ed erogato separati, scontrino medio, upsell, fasce d'età, flussi tra card e percorsi.
Cosa provi alla fine

Vendi una Gentil Card da 800 € e vedi comparire i 200 € di bonus. Fai una seduta e guardi il saldo scalare. Chiudi la prima nota del mese ed esporti il PDF per la commercialista.

SAL 4

Personale, CRM e app operatrici

19 → 23 ott
  1. App operatrici in Expo: agenda del giorno, scheda cliente, incassi.
  2. Timbratura con QR a token rotante, dispositivo abbinato, prossimità e rete WiFi del centro.
  3. Riepilogo mensile ore e straordinari sul monte ore, esportabile per il consulente del lavoro.
  4. No-show con finestra di 48 ore, penale da confermare, blocco e sblocco.
  5. Omaggi, alert di inattività a 45 giorni, compleanni, sotto-scorta.
  6. Notifiche con consensi per canale e finalità, su fake server.
Cosa provi alla fine

Installi l'app su un telefono, inquadri il QR del centro e timbri. Vedi la timbratura nel gestionale e le ore accumularsi. Fai scattare un alert e ne guardi partire il messaggio.

SAL 5

App cliente, casa madre, produzione

26 → 31 ott
  1. App cliente in Expo: registrazione, verifica telefono, accettazione condizioni.
  2. Prenotazione autonoma sulla lista chiusa, il resto come richiesta da confermare.
  3. Storico, sedute residue, movimenti della card, disdetta con la regola delle 48 ore.
  4. Modalità offline degradata e notifiche push.
  5. Accesso casa madre in sola lettura, aggregati per centro, nominativi dietro interruttore tracciato.
  6. Provisioning di un nuovo centro per clonazione e messa in produzione con ripristino provato.
Cosa provi alla fine

Dal tuo telefono prenoti un massaggio e lo vedi comparire nell'agenda. Entri come casa madre e confronti i due centri. Cloni un centro nuovo in pochi minuti.

07

Decisioni prese

Prese il 4 settembre 2026. Da qui non si torna indietro senza un motivo nuovo.

QuestioneDecisioneConseguenza operativa
ScadenzaAmbito pieno entro ottobre. Niente MVP ridotto, niente proroga TreatwellSei SAL su quaranta giorni lavorativi, margine zero. Il settimo SAL ridistribuito negli altri, non tagliato
CalendarioDayPilot Lite, Apache 2.0, gratuitoNessuna spesa e nessuna attesa di licenza. L'attribuzione a daypilot.org va tenuta. Il passaggio a FullCalendar resta possibile in SAL 2 se la vista a risorse non regge
DominiStaging su nubelab.it, produzione dopogentiluomo.nubelab.it e backend.gentiluomo.nubelab.it: stesso dominio di secondo livello, Sanctum in modalità cookie funziona. Lo spostamento su gentiluomoestetica.it a fine progetto muove entrambi insieme
L'unica parte che non dipende da quanto lavoriamo

Tre pratiche hanno tempi burocratici che non si comprimono e vanno aperte questa settimana, altrimenti scadono fuori da ottobre a prescindere dal codice.

Iter art. 4 dello Statuto dei Lavoratori per le timbrature geolocalizzate: accordo sindacale o istanza all'Ispettorato. Senza, i dati raccolti sono inutilizzabili anche se il software funziona. Account sviluppatore Apple e Google come organizzazione: Apple richiede codice D-U-N-S ed entità legale; Google impone a certi account 14 giorni continuativi di test chiuso con 12 tester prima della pubblicazione — da solo questo mette la pubblicazione sugli store oltre ottobre. Le app saranno pronte e installabili per il collaudo, ma la presenza sugli store non è una scadenza che posso rispettare io. Verifica aziendale Meta per i messaggi WhatsApp.

08

Rischi tecnici e come li disinnesco

RischioMitigazione
Doppia prenotazione sulla risorsa condivisa. «Cerca conflitti, poi inserisci» è una corsa critica: due richieste leggono zero conflitti e inseriscono entrambeTransazione con blocco delle righe risorsa in ordine di id, controllo delle sovrapposizioni dentro la transazione, poi inserimento. Testato con connessioni reali concorrenti
Confini di intervallo sbagliati, che rendono l'agenda inutilizzabileIntervalli semiaperti: le 10-11 e le 11-12 non confliggono. Nessun BETWEEN
Contesto del centro perso nei lavori in coda: è il punto esatto dove i sistemi multi-centro si rompono in produzionecentro_id trasportato nel job e reimpostato all'esecuzione, più una guardia che fa fallire subito ogni salvataggio senza centro
Isolamento aggirato da query diverse da Eloquent, e vincoli unici non protettiTutti gli indici unici composti con centro_id. Query diverse da Eloquent vietate sui modelli con isolamento
Timbrature duplicate al recupero della coda offline: ore sbagliate e contenzioso sul cedolinoIdentificativo generato sul dispositivo con vincolo di unicità: il rinvio restituisce la timbratura esistente invece di crearne una seconda. Ora del server autorevole
Prenotazione creata offline: due operatrici prendono lo stesso laser e il conflitto si scopre col cliente già in negozioPrenotazioni, incassi e ricariche non vanno offline. Offline solo timbrature, note, consumo seduta e consultazione
Nessuna API SumUp per lo scontrino fiscale italianoIl gestionale non emette il documento commerciale: lo emette la cassa. Registra e riconcilia a posteriori sul codice transazione
Limite di messaggi WhatsApp condiviso fra tutti i centri: una campagna di uno brucia la quota e fa fallire i promemoria degli altriQuota per centro applicata prima della coda, priorità assoluta ai messaggi di servizio sui promozionali
Webhook duplicati dai provider di pagamento, che generano doppi movimenti in prima notaChiave di idempotenza sull'identificativo del provider, e stato sempre riletto con una chiamata diretta invece di fidarsi del payload
Seed che nasconde i bug di isolamento, perché ogni relazione crea un centro nuovoRiuso esplicito del centro nelle factory, seme fisso, date ancorate
09

Cosa serve da te

Il piano non si ferma in attesa di queste risposte — si sviluppa su dati finti. Ma prima del collaudo con dati veri servono.

Da avviare tu, questa settimana

  1. Iter art. 4 presso l'Ispettorato o accordo sindacale, per le timbrature geolocalizzate.
  2. Account sviluppatore Apple e Google intestati all'organizzazione: hanno lead time che non si comprime.
  3. Verifica aziendale Meta per l'invio dei messaggi WhatsApp.

Dati dal cliente

Rispetto ai nove di prima ne restano sette: il sito ufficiale ne ha già chiusi due.

#Cosa mancaBlocca
1SkinGent: durata della seduta in minuti e prezzo. Dal sito so già che è antiage viso con tecnologia NIR, 5 sedute settimanali, su viso, collo, mento e contorno occhiListino, agenda
2Conferma sul macchinario: il sito dice che Body Strategy usa il manipolo NIR e che SkinGent usa il NIR. Se è lo stesso apparecchio del laser, allora Laser, SkinGent e Body Strategy non possono mai convivere — e la capacità del centro è molto più bassa del previstoMotore agenda
3Inventario risorse per centro: quante cabine in tutto, quante con doccia, quanti scaldacera, quante frese, quanti lettiniMotore agenda
4«Cera brasiliana»: a quale voce del listino corrispondeRegole di parallelismo
5Treatwell: lo storico appuntamenti è esportabile? Serve un CSV di esempio reale e il tracciato dell'Excel dei pacchetti residuiMigrazione
6Testi legali: informativa privacy, condizioni con la penale del 50 %, regolamento Gentil Card. Chi li redigeApp cliente
7Conferma del commercialista che la Gentil Card è un buono monouso, con IVA alla ricarica e scontrino a zero sulle seduteModello fiscale
Trovato nel frattempo, non presente nelle specifiche

Il sito pubblicizza uno sconto del 10 % scegliendo tre o più servizi. Non compare nelle specifiche v1.0 né nelle risposte. Va confermato e aggiunto alle regole di sconto, altrimenti il gestionale calcolerà prezzi diversi da quelli promessi ai clienti.