
Giugno 2023, prima settimana di setup ambiente per un cliente nuovo. Apro il composer.json di un repo Laravel vuoto e mi accorgo che, su settanta pacchetti require, ne sto includendo una sessantina di muscle memory: gli stessi che usavo da CTO nella software house del territorio pisano dove ero per gli ultimi otto anni. Lo stack di Romiltec che mi sono portato dietro è una scelta deliberata: non per pigrizia, ma perché otto anni di produzione su quei tool mi hanno dato un grado di confidenza che non ho su nessuna alternativa moderna. In questo post, parte degli articoli di Production, spiego cosa ho preso nello stack di Romiltec, cosa ho lasciato e cosa ho cambiato.
Il contesto: cosa significava CTO di una software house pisana
Per otto anni ho gestito l’infrastruttura di una software house italiana dove ero CTO. Niente nomi: la regola editoriale di Romiltec è non citarli. Quello che è importante per questo post è il profilo dei sistemi che gestivamo: applicazioni Laravel multi-tenant in produzione su cluster MariaDB con read replica, traffico medio (decine di migliaia di utenti registrati, picchi serali su catalogo prodotti), search via MeiliSearch, deploy via GitLab CI su VM Linux gestite tramite control panel, monitoring Grafana + Prometheus.
Da quel contesto ho assorbito uno stack di default che oggi, nei primi mesi di Romiltec, sto riproponendo come fondamenta. Lo elenco per livello.
Il backend: Laravel, e non se ne discute
Tenuto: Laravel 10. A maggio 2023 Laravel è alla versione 10, PHP minimo 8.1. Nello stack di Romiltec è la scelta di default per ogni progetto cliente che ha un backend HTTP: API REST, dashboard interne, webhook receiver, worker background.
Il motivo non è ideologico. Negli otto anni precedenti ho scritto Laravel su progetti che andavano da CRUD molto semplici a piattaforme con eventi real-time, queue Horizon, Eloquent Global Scope per multi-tenancy, integrazioni OAuth2 via Passport. Conosco i bordi taglienti del framework (la magia di Eloquent quando si scala male, il costo dei with aggressivi sui controller, la N+1 nascosta nei resource transformer). Ho letto la sua codebase per capire come funziona internamente la pipeline di middleware. Su nessun altro framework PHP ho lo stesso livello di confidenza.
Cambiato: la struttura interna delle app Laravel. Nella software house precedente i controller erano spesso “fat controller”, con logica di business inline. In Romiltec sto adottando da subito il pattern Action-DTO-Policy (Actions in app/Actions/, DTO con Spatie Laravel Data, Policies dedicate) che ho visto sostenere meglio progetti che durano oltre i 18 mesi. Controller thin che delegano alle Actions, business logic estraibile e testabile, niente service container come discarica.
Buttato: Lumen. Negli ultimi anni di CTO avevo iniziato a sperimentare microservizi con Lumen per certi endpoint ad alto throughput. Esperimento finito male: la divergenza fra Lumen e Laravel principale comportava costi di manutenzione doppi senza il guadagno di performance promesso. In Romiltec parto direttamente con monolite Laravel per l’API; se serve un microservizio AI/analytics, lo scrivo in FastAPI Python (ne parlo sotto).
Il database: MariaDB cluster con MaxScale, anche per progetti piccoli
Tenuto: MariaDB 10.x in cluster con MaxScale come database proxy. Anche per i clienti piccoli, da subito.
Questa è la scelta che ricevo più obiezioni. Ma non è troppa infrastruttura per un cliente che fa 50 ordini al giorno? Sì, all’inizio sì. Ma negli otto anni precedenti ho visto cosa succede quando si parte con un MySQL stand-alone per “risparmiare”, e poi al primo picco serio bisogna fare la migrazione a cluster sotto pressione: settimane di lavoro fra schema check, replica catch-up, riconfigurazione client. Costo enorme, in un momento di stress.
In Romiltec setto subito il template con due nodi MariaDB in replica circolare e MaxScale davanti. Il costo extra di setup è qualche giornata, marginale sul costo del progetto. Il guadagno è che il giorno del primo picco non devo cambiare niente: aggiungo un read replica e MaxScale lo bilancia da solo.
Cambiato: la topologia di replica. Nella società precedente avevamo replica master-slave classica, con il problema noto della latenza in catch-up sotto carico. Per i progetti più seri di Romiltec sto pianificando una topologia circolare fra due nodi (entrambi master uno per l’altro), idealmente nominata in modo memorabile (nei runbook interni i due nodi del cluster di riferimento li chiamiamo internamente james e jason, nomi-codice di squadra, perché i nomi delle macchine si ricordano molto meglio dei numeri di IP). MaxScale su un terzo nodo gestisce il routing dei read sui replica e dei write sul nodo attivo. Failover non automatico, ma con runbook scritto, perché ho imparato a non fidarmi dei failover automatici quando ci sono di mezzo le scritture (un automatic failover sbagliato è peggio di un downtime di trenta minuti gestito a mano).
Buttato: MySQL stand-alone. Per progetti nuovi non lo uso più. Resta in eredità solo sui pochi clienti dove era già installato.
Search: MeiliSearch oggi, ma con un occhio a Typesense
Tenuto: MeiliSearch + Laravel Scout. Negli ultimi due anni in azienda l’avevo introdotto per ricerca su catalogo prodotti, con buona soddisfazione. È leggero, l’integrazione con Scout è pulita, l’indicizzazione full-rebuild su qualche centinaio di migliaia di record dura minuti, non ore.
Tenendo d’occhio Typesense. Sul mio radar tecnico c’è Typesense, che sembra avere caratteristiche più solide per i casi multi-tenant (filtri per tenant_id come predicato di ricerca, schema con vector search nativo). Per i progetti Romiltec del 2023 resto su MeiliSearch, ma se mi capita un cliente con esigenze di scaling più serie, valuterò Typesense da subito. (Update onesto: nei prossimi mesi è possibile che cambi idea; questo post è scritto a giugno 2023 e riflette quello che ho in produzione adesso.)
Sistemista: Hestia Control Panel + Nginx, niente Kubernetes
Tenuto: Hestia Control Panel su VM Debian. Nella società precedente avevamo migrato da cPanel a Hestia un paio di anni fa, e da allora gestisco con piacere ambienti multi-tenant Linux con quattro siti per VM. Hestia mi dà un’astrazione gestibile su Nginx + PHP-FPM + MariaDB + MTA, con quote disco per utente e backup integrati.
Per Romiltec questo significa che ogni cliente ha un’utenza dedicata su una VM gestita centralmente, con il suo dominio, il suo pool PHP-FPM, la sua quota. Nessun docker-in-docker, nessun Kubernetes, nessun service mesh. È una scelta di scala: con cinque dev e meno di venti VM in produzione, l’overhead operativo di Kubernetes non si ripaga.
Cambiato: la documentazione runbook. In azienda i runbook erano in un wiki interno che pochi leggevano. In Romiltec li tengo in un repo Git dedicato, in markdown, con stesso flow di pull request del codice. Niente knowledge in testa, tutto in deploys/<host>-runbook.md. Lezione imparata da Will Larson sul valore della documentazione come asset di team.
Buttato: cPanel. Stop. Per le poche VM ancora su cPanel della società precedente Romiltec non eredita nulla.
Frontend: Vue 3 + Vuetify, e non React, almeno per ora
Tenuto: Vue 3 + Vuetify 3 come default. Negli ultimi due anni in azienda ho costruito tre dashboard amministrative su questo stack, e mi piace per due motivi: la Composition API con <script setup> è meno rumorosa di JSX/React, e Vuetify mi dà un set di componenti Material Design già pronti che riducono il tempo di delivery sulle dashboard interne. Per Romiltec, dove i clienti pagano un prezzo fisso al mese e devo controllare il delivery, partire con un component library già completa è una scelta pratica.
Tenendo aperta la porta a React. Riconosco che React 18 e Next.js sono più diffusi nel mercato, e che per i prossimi prodotti consumer-facing potrei valutarli. Per le dashboard B2B che sto facendo adesso, Vue 3 + Vuetify è il mio default. Non è una crociata, è una scelta operativa.
Cambiato: il bundler. Nei progetti precedenti usavamo ancora Webpack/Mix in alcuni repo legacy. In Romiltec parto solo con Vite. La differenza nel feedback loop dello sviluppo (hot reload sotto il secondo) è troppo grossa per ignorarla.
Il pezzo nuovo: FastAPI Python per i job AI
Aggiunto: FastAPI + Python 3.11 per il calcolo AI/analytics. Questo non l’avevo da CTO precedente, è la novità del 2023.
I primi clienti di Romiltec stanno chiedendo automazioni AI sopra alle bozze editoriali. OpenAI ha rilasciato gpt-3.5-turbo a marzo 2023 con un pricing per token che lo rende usabile in produzione, e Anthropic ha appena annunciato Claude in beta (la GA per le API arriverà nei mesi successivi). Per gestire questi workload in modo disaccoppiato dal monolite Laravel, sto disegnando un microservizio FastAPI con queue Redis, callback verso Laravel via webhook firmato, deploy via Docker.
Perché non scrivere tutto in Laravel? Perché ecosistema. Le librerie di stilometria, di tokenizzazione, di analisi NLP sono in Python: spostare quella roba in PHP sarebbe un fork di codebase che non posso permettermi.
La tabella sintetica
| Layer | Tenuto | Cambiato | Buttato |
|---|---|---|---|
| Backend | Laravel 10, struttura Action-DTO-Policy | Pattern interno (no fat controller) | Lumen |
| DB | MariaDB cluster + MaxScale | Replica circolare invece di master-slave | MySQL stand-alone, cPanel |
| Search | MeiliSearch + Laravel Scout | (da valutare Typesense in futuro) | nessuno |
| Sistemista | Hestia Control Panel + Nginx | Runbook in repo Git | Knowledge tribale interna |
| Frontend | Vue 3 + Vuetify 3 | Solo Vite, no Webpack/Mix | nessuno |
| AI/Analytics | (nuovo) FastAPI Python | nuovo | nessuno |
Cosa porto a casa da questa scelta di stack
Tre punti di metodo, prima del codice.
Uno. Lo stack di Romiltec, come qualunque stack di una società appena fondata, è la area di confidenza tecnica del founder tecnico. È quello su cui sai dove sono i bordi taglienti, perché ce li hai sbattuto le dita per anni. Cambiare stack appena fondi una società è, secondo me, un autosabotaggio: ti privi del tuo unico vantaggio competitivo iniziale, che è la velocità con cui sai consegnare codice sicuro su tool conosciuti. La differenza la fai sui pattern d’uso, non sulle tecnologie.
Due. Le scelte sistemistiche pesano più delle scelte di linguaggio. Aver scelto MariaDB cluster + MaxScale + Hestia da subito significa che, a un anno, non avrò la migrazione di infrastruttura da fare sotto pressione. È un costo iniziale pagato per una tranquillità futura.
Tre. L’unica cosa veramente nuova dello stack 2023 è l’AI. Tutto il resto è una rifinitura di ciò che avevo già. La novità è il microservizio FastAPI che integra OpenAI/Anthropic, ed è la prima volta in dodici anni che metto un componente in produzione su una tecnologia che il giorno prima non controllavo nei dettagli. Per riferimento, Simon Willison sta documentando bene questo passaggio dell’industria su provider LLM in produzione: lo sto seguendo con attenzione.
Tornando al composer.json da cui sono partito: i sessanta pacchetti che mi sono ritrovato a includere di muscle memory non erano un problema. Erano il segnale che la mia continuità tecnica fra le due vite, da CTO dipendente a founder di Romiltec, era già scritta sul codice prima ancora che sulla S.r.l.
