Diario

Come si costruisce una piattaforma con l’AI dentro

· 5 min di lettura · piattaforme, supabase, rls, ai

Cosa intende il laboratorio per piattaforma su misura, e la base comune da cui parte: accessi, notifiche, telemetria, tetti di spesa AI, sicurezza a livello di riga, deploy. Con i guasti che l’hanno cambiata.

Dal 21 agosto 2026 alle 14:53, per cinque giorni, la tabella della telemetria del backend comune, site_events, non ha registrato un evento. Le pagine funzionavano. Nel database c’erano due funzioni rs_track con gli stessi argomenti in ordine diverso. Per Postgres sono due funzioni distinte, e un create or replace con i parametri scambiati ne aggiunge una invece di sostituirla. PostgREST rispondeva HTTP 300, perché non sapeva quale chiamare.

Il client non se ne accorgeva. Quando la chiamata fallisce, supabase.rpc restituisce un oggetto con l’errore, senza sollevare eccezioni. Il catch vuoto, scritto perché la telemetria non disturbasse mai la pagina, non avrebbe visto niente comunque. Il pannello mostrava zero visite, un numero credibile.

La migration del 26 agosto toglie la firma vecchia. Il client adesso rilancia l’errore e lo segnala una volta nella console. E nel workflow ws-uptime.yml una sonda, ogni mezz’ora, manda a rs_track una lista vuota di eventi, che non scrive niente, e si aspetta la risposta 204.

Cosa vuol dire su misura

La telemetria è uno dei pezzi della base comune da cui partono le piattaforme del laboratorio. Per il laboratorio una piattaforma su misura è software in cloud modellato sul lavoro di chi lo usa. L’AI sta dentro il prodotto, con tetti di spesa, ripieghi dichiarati e una persona sulle decisioni che contano. La stessa installazione serve più organizzazioni, con i dati separati riga per riga. E la si costruisce e la si mantiene con il metodo del laboratorio, Ratchet Agentic Engineering.

Oggi questa capacità si vede in due posti. Seantral, online su seantral.com, è il dimostratore pubblico del metodo: un’app sul mare, con un backend suo. E c’è una piattaforma per strutture di cura, in prova chiusa, con dati inventati.

La base comune

Una piattaforma nuova parte da una base che esiste già. In Cockpit by RiftSeed, lo strumento in cui il laboratorio applica il metodo, un progetto nuovo nasce dal modello templates/riftseed-base. Dentro ci sono Vite, React e TypeScript, un client Supabase che legge indirizzo e chiave dall’ambiente e l’accesso con un link via email. Ci sono anche una tabella d’esempio con le sue regole di accesso, un test a cricchetto con due tetti d’esempio, una sonda Playwright a 390 e a 1440 pixel di larghezza e i workflow di CI e di deploy. Il deploy del modello parte solo dall’approvazione di una persona in Cockpit, mai da un push.

Le app del laboratorio condividono il resto. Gli account stanno su Supabase Auth, per anonimi e registrati, e il ruolo di amministratore lo controlla una funzione del database. Una notifica è prima di tutto una riga nella tabella notifications, che fa da casella in arrivo; un trigger chiama la funzione send-notification, che manda un push cifrato a ogni dispositivo del destinatario che lo accetta e toglie gli indirizzi morti.

La telemetria è propria, senza strumenti di terzi: un identificativo di sessione casuale per ogni scheda del browser, il paese letto da un’intestazione di Cloudflare, nessun indirizzo IP salvato, novanta giorni di conservazione. Il frontend va su Cloudflare Pages dalla CI, dopo il cancello.

L’AI dentro il prodotto

Le funzioni AI del sito hanno ciascuna un modello e una catena di ripiego, nella tabella ai_tool_config. Il generatore di brief prova i modelli in ordine. Se nessuno restituisce un risultato leggibile, costruisce una risposta di riserva marcata _fallback: true, e l’interfaccia la tratta come tale. Il ripiego resta scritto nel dato.

I tetti si controllano prima di chiamare il modello. L’assistente di Seantral conta i messaggi di una persona nell’ultimo minuto e nelle ultime ventiquattro ore, e quelli di tutti nelle ultime ventiquattro ore; sopra un limite risponde che il limite è raggiunto, e il modello non viene chiamato. Cockpit riserva la spesa prima della chiamata. Sotto un blocco per proprietario somma la spesa del giorno, le riserve aperte e quella nuova, e ammette la chiamata solo se il totale resta sotto i tetti per brief e per giorno. Dopo la chiamata salda la riserva con il costo riportato da OpenRouter.

Una persona resta sulle decisioni che contano. Nel generatore di brief l’AI propone i requisiti e chi scrive il brief li conferma. Il brief finale cita solo requisiti confermati: ogni identificativo citato dal modello si confronta con quelli inviati nella richiesta, e gli orfani si tolgono. In Cockpit un tetto sale solo con la decisione di una persona.

Dati separati riga per riga

Ogni tabella creata nelle migration di questo repository ha la sicurezza a livello di riga accesa. Quando la stessa installazione serve più organizzazioni, ogni riga porta l’organizzazione a cui appartiene. Nella piattaforma per strutture di cura ogni riga ha la sua struttura, e ogni policy chiede al database che ruolo ha in quella struttura la persona collegata. Chi lavora in una struttura non legge le righe di un’altra.

Le regole si controllano senza database. Nel modello, il test tests/rls.test.ts legge le migration e fallisce se una tabella non ha la RLS, se una policy è per il ruolo anonimo o se un confronto con auth.uid() sta fuori da coalesce(..., false).

L’ultima regola viene dal 6 luglio 2026. In un prototipo di inviti a eventi, una prova avversaria di diciannove controlli ha trovato che auth.uid() = host_id, senza nessuno collegato, vale NULL, e dentro un controllo di autorizzazione quel NULL lasciava passare la chiamata. Da allora lo stesso controllo statico gira nei test di accesso di Cockpit, in quelli della piattaforma per strutture di cura e nel modello da cui parte ogni progetto nuovo.

Scritto come nasce ogni cosa in questo lab: con l’AI, poi riletto e approvato da una persona.

Tutto il diario