Come Ho Costruito Rollgate: da Side Project a SaaS di Feature Flags

Domenico Giordano15 min di lettura
saasgonextjsfeature-flagsarchitettura

Il percorso tecnico e le decisioni architetturali dietro Rollgate, una piattaforma SaaS di feature flags costruita con Go, Next.js e PostgreSQL come alternativa a LaunchDarkly.

Come Ho Costruito Rollgate: da Side Project a SaaS di Feature Flags

Nell'ultimo anno ho costruito Rollgate, una piattaforma SaaS per la gestione di feature flags. L'obiettivo era semplice: offrire le stesse funzionalità di LaunchDarkly — rollout graduali, targeting utenti, A/B testing, kill switch — senza il prezzo enterprise da $70k/anno.

In questo articolo racconto il percorso tecnico: le decisioni architetturali, tutte le funzionalità implementate, gli errori commessi, e i numeri reali di un SaaS costruito da solo.

Il Problema

Chiunque abbia lavorato in un team di sviluppo conosce la situazione: vuoi rilasciare una feature, ma non sei sicuro che funzioni per tutti gli utenti. Il deploy tradizionale è un evento binario — o la feature è live per tutti, o per nessuno.

I feature flags risolvono questo problema separando il deployment dal release. Puoi deployare codice in produzione e abilitarlo gradualmente: prima l'1% degli utenti, poi il 5%, poi il 25%, e così via. Se qualcosa va storto, spegni il flag in un secondo — nessun rollback, nessun hotfix, nessun downtime.

Strumenti come LaunchDarkly fanno esattamente questo, ma costano da $25k a $150k all'anno. Per una startup o un team medio, è proibitivo. Ho pensato: posso costruire qualcosa di equivalente con costi infrastrutturali minimi?

La Scelta dello Stack Tecnologico

La prima decisione fondamentale è stata lo stack. Avevo due requisiti non negoziabili: bassa latenza (i feature flags vengono valutati a ogni request) e costo infrastrutturale minimo (devo competere con il pricing enterprise).

Backend: Go

Ho scelto Go per il backend API per tre motivi:

  1. Performance — Un flag evaluation deve avvenire in microsecondi. Go compila in binario nativo, non ha garbage collection pause significative, e gestisce migliaia di connessioni concorrenti con goroutine.
  2. Deployment semplice — Un singolo binario statico. Niente runtime, niente dipendenze. L'immagine Docker finale pesa 20MB.
  3. Libreria standard eccellente — HTTP server, JSON encoding, crypto, testing — tutto nella stdlib. Meno dipendenze esterne significa meno surface area per bug e vulnerabilità.

Il router è Chi, leggero e compatibile con net/http. Niente framework pesanti come Gin — preferisco composizione su convention.

Frontend: Next.js

Per la dashboard ho scelto Next.js con React e Tailwind CSS. La dashboard è dove gli utenti gestiscono i loro flags, configurano targeting rules, vedono analytics. Non ha requisiti di performance estremi, ma deve essere reattiva e piacevole da usare.

Next.js offre SSR/SSG per le pagine marketing (SEO), API routes per proxy verso il backend, e un'esperienza di sviluppo fluida con hot reload.

Database: PostgreSQL + Redis

PostgreSQL è stato una scelta ovvia per la persistenza: affidabile, performante, con JSONB per i metadata, indici parziali, e LISTEN/NOTIFY per invalidazione cache. Il database contiene 29 tabelle, 67 indici e 29 foreign key.

Redis serve come cache layer per le valutazioni dei flags. Quando un SDK chiede "il flag X è attivo per l'utente Y?", la risposta deve arrivare in millisecondi. Redis tiene in memoria l'intero set di flags per ogni ambiente, aggiornato in tempo reale via pub/sub.

Le Feature di Rollgate

Rollgate non è un semplice toggle on/off. Ho implementato un set completo di funzionalità che coprono l'intero ciclo di vita di un rilascio software.

Feature Flags con Tipi Multipli

I flag supportano quattro tipi di valore:

  • Boolean — Il classico on/off. Perfetto per kill switch e feature toggle.
  • String — Restituisce un valore testuale. Ideale per A/B testing ("variant-a", "variant-b") o per configurare messaggi dinamici.
  • Number — Restituisce un valore numerico. Utile per configurare limiti, percentuali, o parametri di algoritmi.
  • JSON — Restituisce un oggetto strutturato. Per configurazioni complesse come layout, feature set per piano, o regole di business.

Rollout Graduali

Il percentage rollout permette di abilitare un flag per una percentuale specifica di utenti. La distribuzione usa consistent hashing (MurmurHash3) sull'user ID, quindi lo stesso utente ottiene sempre lo stesso risultato senza salvare stato:

hash = MurmurHash3(flagKey + userId) % 10000
isEnabled = hash < rolloutPercentage * 100

Precisione allo 0.01%. Puoi passare dall'1% al 5% al 25% al 100% gradualmente, monitorando le metriche a ogni step.

Targeting Utenti e Segmenti

Il targeting permette di abilitare flag per specifici gruppi di utenti basandosi su attributi:

  • Attributi utente — Email, piano, paese, versione app, qualsiasi attributo custom
  • Operatori — equals, contains, startsWith, endsWith, regex, in, greaterThan, lessThan
  • Segmenti riutilizzabili — Definisci "Beta Users" o "Enterprise Customers" una volta, usalo in tutti i flag
  • Regole combinate — AND/OR logic tra condizioni multiple

Esempio: abilita il nuovo checkout solo per utenti con piano "pro" in Italia che hanno più di 100 ordini.

Kill Switch

Il kill switch è la feature più critica in produzione. Quando qualcosa va storto — un bug, un problema di performance, un'integrazione esterna down — devi poter spegnere una feature istantaneamente.

In Rollgate, ogni flag ha un toggle on/off che prende effetto in secondi grazie alla propagazione SSE in tempo reale. Non serve un deploy, non serve accesso al server, non serve nemmeno essere un developer. Il product manager può spegnere una feature dalla dashboard dal suo telefono.

Ho visto team enterprise impiegare 30-45 minuti per un rollback tradizionale (revert commit, CI, deploy, verify). Con un kill switch sono 2 secondi. In un incidente di produzione, quei 30 minuti possono costare migliaia di euro in revenue persa.

Scheduled Changes

Le scheduled changes permettono di programmare modifiche ai flag per una data e ora specifiche. Casi d'uso reali:

  • Lancio coordinato — "Attiva la nuova feature venerdì alle 14:00 quando il marketing pubblica il blog post"
  • Promozioni temporanee — "Abilita il banner Black Friday da venerdì a lunedì"
  • Rollout progressivo automatico — "1% lunedì, 10% mercoledì, 50% venerdì, 100% lunedì prossimo"
  • Sunset feature — "Disabilita la vecchia API il 1 aprile"

Ogni scheduled change mostra nella timeline del flag, con stato pending/executed/cancelled. Un cron job server-side verifica ogni minuto se ci sono cambiamenti da applicare.

Rollback Istantaneo

Ogni modifica a un flag viene salvata nella history con timestamp, autore, e snapshot completo dello stato. Il rollback ripristina lo stato esatto del flag a un punto precedente — non solo il valore, ma anche targeting rules, percentuali, e scheduled changes.

È diverso da un semplice "undo": puoi tornare indietro di 5 modifiche, o a una specifica versione datata. L'audit log mantiene traccia di chi ha fatto cosa e quando.

A/B Testing

I flag con varianti string permettono A/B testing nativo. Invece di un semplice true/false, il flag restituisce una variante ("control", "variant-a", "variant-b") con distribuzione percentuale configurabile.

L'evaluation tracking registra quale variante è stata servita a ciascun utente, con timestamp e contesto. Questo permette di correlare le varianti con metriche di business (conversione, retention, revenue) nel tuo analytics tool preferito.

Non ho implementato (volutamente) un motore statistico integrato — preferisco che i team usino i loro strumenti di analytics esistenti piuttosto che creare un altro silo di dati.

Multi-Environment

Ogni progetto in Rollgate ha ambienti separati: development, staging, production (e quanti ne vuoi). I flag sono indipendenti per ambiente — puoi avere un flag attivo in staging ma spento in produzione.

Ogni ambiente ha le proprie API key (server e client), le proprie regole di targeting, e la propria history. Questo previene il classico errore di "ops, ho modificato il flag di produzione pensando fosse staging".

Audit Log

Ogni azione sulla piattaforma viene registrata in un audit log immutabile:

  • Chi ha creato/modificato/cancellato un flag
  • Cosa è cambiato (diff before/after)
  • Quando (timestamp preciso)
  • Da quale IP e user agent

La retention dell'audit log varia per piano: 3 giorni (Free), 14 giorni (Starter), 90 giorni (Pro), 1 anno (Growth). Per compliance e debugging, avere una traccia completa di chi ha modificato cosa è fondamentale.

Webhooks

I webhook notificano sistemi esterni quando un flag cambia. Ogni volta che un flag viene creato, aggiornato, o cancellato, Rollgate invia un POST HTTP all'URL configurato con il payload completo dell'evento.

Casi d'uso: notificare Slack quando un flag di produzione cambia, triggerare un deploy quando un feature flag viene attivato, aggiornare un sistema di monitoring, sincronizzare con tool di project management.

I webhook hanno retry automatico con backoff esponenziale e logging delle delivery per debugging.

Analytics e Usage Tracking

Rollgate tracka le evaluation dei flag in tempo reale: quante volte è stato valutato, quanti utenti unici, distribuzione true/false, trend nel tempo. Questo serve sia per monitoring (il flag sta funzionando?) sia per capacity planning (quanto traffico generano i flag?).

I limiti di utilizzo sono per piano: 500K richieste/mese (Free), 500K (Starter), 2M (Pro), 10M (Growth). Dashboard di usage integrata con alert quando ci si avvicina al limite.

13 SDK

Ho costruito 13 SDK per coprire tutti i principali linguaggi e framework:

  • JavaScript/TypeScript — sdk-core, sdk-node, sdk-browser, sdk-react, sdk-vue, sdk-angular, sdk-svelte
  • Mobile — sdk-react-native, sdk-flutter
  • Backend — sdk-go, sdk-java, sdk-python, sdk-dotnet

Tutti gli SDK condividono lo stesso set di feature: cache locale, circuit breaker, retry con backoff, event buffering, e aggiornamenti real-time via SSE. Se il server è down, gli SDK continuano a funzionare con i valori cached.

Architettura del Sistema

Client SDK → API Server (Go) → Redis Cache → PostgreSQL
              ↑
          SSE Connection (real-time updates)

Flag Evaluation Engine

Il cuore del sistema è l'engine di valutazione. Quando un SDK chiede se un flag è attivo, il server:

  1. Legge il flag dalla cache Redis (non dal DB)
  2. Valuta le targeting rules in ordine di priorità
  3. Applica il percentage rollout con consistent hashing
  4. Restituisce il valore con metadata (motivo della decisione)

Tutto in ~200μs. La latenza P99 è sotto il millisecondo.

Real-Time via SSE

Ho scelto Server-Sent Events invece di WebSocket perché il pattern è unidirezionale (server → client), SSE ha riconnessione automatica built-in, e funziona attraverso CDN e proxy senza configurazione. Il sistema supporta ~28.000 connessioni SSE simultanee su un singolo server CX33.

Le Sfide Tecniche

Race Condition sugli Aggiornamenti

Quando più utenti modificano lo stesso flag, servono garanzie di consistenza. Ho implementato optimistic locking con version counter — se qualcun altro ha modificato il flag nel frattempo, l'operazione restituisce 409 Conflict.

Circuit Breaker negli SDK

Se il server è down, gli SDK non devono crashare l'app host. Il circuit breaker ha tre stati (Closed, Open, Half-Open) con retry esponenziale e request deduplication. Gli SDK sono resilienti a failure transitorie senza sovraccaricare il server.

SEO per un'App SaaS

Ho separato marketing e dashboard con un domain split: rollgate.io per le pagine SEO (Server Components) e app.rollgate.io per la dashboard autenticata. Il middleware Next.js gestisce il routing basato sull'hostname.

Resilienza e Monitoring

Un SaaS di feature flags ha una responsabilità particolare: se il servizio è down, i flag dei clienti smettono di aggiornarsi. Per questo ho investito in:

  • Backup giornalieri — PostgreSQL dump ogni notte su server separato a Helsinki
  • Monitoring — Prometheus + Grafana + Alertmanager con alert su Discord
  • Health check — Uptime Kuma verifica API, Web, DB, Redis ogni 60 secondi
  • Disaster recovery — Script che ricostruisce lo stack su server pulito in ~20 minuti
  • SDK resilience — Cache locale + circuit breaker = funziona anche offline

I Numeri

MetricaValore
File Go (non-test)147
File TypeScript/TSX168
Endpoint API114
Tabelle DB29
Test totali~850
SDK pubblicati13
Score codebase7.86/10

Cosa Ho Imparato

1. La Semplicità Vince

Kubernetes in produzione? No, Docker Compose basta. Microservizi? No, un monolite modulare è più semplice. Event sourcing? No, un audit log è sufficiente. Ogni complessità ha un costo di manutenzione che per un progetto solo deve giustificare il suo peso.

2. I Test Salvano la Vita

Con ~850 test, posso refactorare con fiducia. Il CI esegue tutto su ogni PR e blocca il deploy se qualcosa fallisce. Senza questa rete, avrei rotto la produzione decine di volte.

3. Il Billing è Più Difficile del Prodotto

Paddle per i pagamenti è stato sorprendentemente complesso: webhook, subscription lifecycle, prorating, dunning, tax handling. Consiglio: usa un payment provider che gestisce tutto (Paddle, Lemon Squeezy) piuttosto che Stripe raw.

4. La SEO Richiede Attenzione Costante

Se Google non ti indicizza, nessuno ti troverà. Ho dedicato settimane a SSR, JSON-LD, sitemap, meta tags. È un lavoro continuo.

5. Costruire da Solo è Sostenibile (con Limiti)

Il codice è la parte facile — trovare utenti è la vera sfida. Marketing, supporto, crescita richiedono competenze diverse dallo sviluppo.

Cosa Viene Dopo

Rollgate è live su rollgate.io con un free tier generoso (500K richieste/mese). I prossimi passi: A/B testing avanzato con auto-winner, teams con SSO, versione self-hosted, e OpenAPI spec completa.

Il Mercato: Competitor e Posizionamento

Il mercato dei feature flags è dominato da pochi player con pricing enterprise aggressivo:

PiattaformaPricingPunti di forzaLimitazioni
LaunchDarklyDa $833/meseLeader di mercato, enterprise-ready, integrazioni vastissimePrezzo proibitivo per startup, complessità eccessiva per team piccoli
FlagsmithDa $45/meseSelf-hosted gratuito, API-firstUI meno curata, meno SDK, community piccola
UnleashDa $80/meseSelf-hosted maturo, buona documentazioneSetup complesso, UI datata
PostHogUsage-basedSuite completa (analytics + flags), open-sourceFeature flags non sono il focus, overhead
RollgateFree → €45/mesePricing accessibile, 13 SDK, setup in 5 minutiNuovo sul mercato, community in crescita

La Scelta del Pricing Model

Il pricing è stata una delle decisioni più difficili. Ho studiato ogni competitor e identificato tre approcci:

  1. Per-seat (LaunchDarkly) — Scala con il team, penalizza aziende grandi. $70k/anno per 50 developer non è insolito.
  2. Usage-based (PostHog) — Scala con il traffico, imprevedibile per budget. Può esplodere con picchi di traffico.
  3. Tier fissi (Rollgate) — Prezzo prevedibile, scala per feature e limiti. Il cliente sa esattamente quanto paga.

Ho scelto i tier fissi perché la prevedibilità del costo è fondamentale per startup e PMI. I quattro piani:

PianoMensileAnnualeRichieste/meseTeamTarget
Free€0€0500K3 membriSide project, MVP
Starter€45/mese€39/mese1M5 membriStartup early-stage
Pro€119/mese€99/mese3M15 membriTeam in crescita
Growth€349/mese€299/mese12M50 membriScale-up, alto traffico

Il free tier è generoso di proposito: 500K richieste/mese bastano per un'app con migliaia di utenti attivi. L'obiettivo è abbassare la barriera d'ingresso — se un developer prova Rollgate e funziona, il passaggio a Starter quando il progetto cresce è naturale.

Perché Non Open Source?

Ho valutato il modello open-core (core gratuito, feature enterprise a pagamento), ma richiede una community attiva per funzionare. Per un progetto solo, il rischio è offrire tutto gratis senza monetizzare. Ho optato per un modello SaaS con free tier generoso, con l'intenzione di rilasciare una versione self-hosted con licenza BSL (Business Source License) in futuro — lo stesso approccio di HashiCorp e Sentry.

Se stai cercando un'alternativa a LaunchDarkly che non costi quanto un dipendente, prova Rollgate. È gratuito per iniziare.