Case study di architettura / Booka
Booka: cinque applicazioni, un solo modello dati.
Booka è una piattaforma multi-tenant per le attività che lavorano su appuntamento, a partire da saloni e barbieri. Non è un marketplace: nessuna attività viene mostrata accanto ai concorrenti. È il sistema su cui un'attività gestisce la giornata, con un sito pubblico dove i clienti prenotano, un gestionale web, una console superadmin e due app mobile, una per lo staff e una per i clienti.
- Il mio contributo
- Le tre applicazioni web e, insieme a Giulio, il database
- Proprietà
- Venture condivisa con Giulio
- Forma
- Turborepo con tre app Next.js e due Expo, repository separato per il database
- Stato
- In produzione
Il requisito architetturale
Le cinque applicazioni non hanno la stessa velocità né gli stessi utenti. Il sito pubblico cambia con il marketing e il lancio. Il gestionale segue le richieste dei saloni: agenda, clienti, staff, cassa, magazzino, report, campagne, abbonamento. La console superadmin cambia di rado e non deve mai rompersi. Le app mobile passano dalla revisione degli store, quindi un rilascio lì richiede giorni, non minuti.
Descrivono però tutte lo stesso mondo: la stessa attività, la stessa sede, lo stesso cliente, lo stesso appuntamento. Un cliente può appartenere a più sedi della stessa attività, le note sono per sede, i consensi per attività. Separare le applicazioni era necessario. Separare i dati avrebbe voluto dire cinque versioni di ogni regola.
L'obiettivo era quindi uno: lasciare che cinque prodotti evolvano con i loro tempi, mantenendo una sola verità su attività, persone e appuntamenti.
Le opzioni architetturali
Abbiamo confrontato tre configurazioni rispetto a indipendenza dei rilasci, coerenza dei dati, sicurezza e costo di manutenzione.
Architettura implementata
Un unico Turborepo contiene le tre applicazioni Next.js che ho costruito io, cioè sito pubblico, gestionale e console superadmin, e le due app Expo realizzate da Giulio. Condividono pacchetti per tipi di dominio, autenticazione, client API, design system, feature flag e traduzioni, così un concetto si definisce una volta e ogni app lo legge allo stesso modo.
Il database vive in un repository separato, che è la fonte canonica per migration, policy RLS, RPC, trigger ed Edge Function. L'abbiamo progettato insieme. È uno schema condiviso con l'identificativo dell'attività su ogni riga e le RLS sopra, e le operazioni più delicate non si fidano del client: creare e modificare un appuntamento passa da RPC, e lo staff raggiunge i dati dei clienti tramite funzioni operative che rispettano ruolo e sedi assegnate, mai con una lettura diretta della tabella.
Alcune parti sono pronte ma tenute volutamente fuori dalla promessa. I documenti fiscali, per esempio, esistono nello schema dietro un flag e restano fuori dall'MVP finché non sono validati.
Benefici operativi
Un rilascio web non aspetta la revisione degli store, e un rilascio mobile non si porta dietro il gestionale, perché sono unità di deploy diverse.
Una modifica allo schema si scrive una volta, in un solo repository, e i tipi generati arrivano a ogni app dallo stesso pacchetto. C'è un database, non cinque che vanno d'accordo nei giorni buoni.
Le regole su chi può vedere cosa sono applicate dove stanno i dati. Un'app con un bug può mostrare la schermata sbagliata, ma non può leggere un cliente che il database non le darebbe.
Serve una decisione architetturale simile?
Lavoro su prodotti che devono separare applicazioni, utenti o cicli di rilascio senza perdere coerenza nei dati e nella gestione operativa.
hello@robertodrago.dev