Personal trainer — sito + agenda + FitLab
Prenotazioni che rispettano il calendario del trainer, più un'area clienti e un cockpit per la sua attività.
- Astro
- React
- React Three Fiber
- Cloudflare Workers
- Cloudflare D1
- Google Calendar API
- Resend
- Workers AI
- ≈45endpoint API per prenotazioni, admin, area clienti e cockpit
- 24migrazioni SQL su Cloudflare D1
- €0di hosting al mese: piani gratuiti di Cloudflare e Resend
Prenotazioni che si piegano al suo calendario
Un motore di prenotazione condiviso dal sito e da un worker cron, il suo Google Calendar come fonte degli impegni, un database D1, un'area clienti e un cockpit per l'attività.
Tocca un blocco per vedere cosa fa.
- Ingresso
- Persone
- Logica
- Dati
- Uscita
- Infrastruttura
Ingresso
Sito one-page
Astro SSR su Workers con isole React. Il wizard chiede al server gli slot liberi; il bilanciere 3D si carica solo su desktop e senza reduced motion.
- Astro
- React
- React Three Fiber
Passa a Motore prenotazioni

Ingresso
Calendario del trainer
Il suo Google Calendar è la fonte degli impegni, letto tramite service account o il feed privato. Niente OAuth e nessuna app nuova da imparare.
- Google Calendar API
- iCal
Passa a Motore prenotazioni
Persone
Cockpit del trainer
App da telefono per clienti, pacchetti e incassi. Un vocale va a Whisper, Claude lo trasforma in una bozza di movimenti e niente si salva finché lui non conferma.
- Workers AI
- Claude API
Passa a Cloudflare D1
Logica
Motore prenotazioni
Pacchetto condiviso: slot dagli orari meno gli impegni, UTC ovunque con un solo modulo di conversione, link di annullo firmati. Test sui due cambi d'ora.
- TypeScript
- Vitest
Riceve da Sito one-page, Calendario del trainerPassa a Cloudflare D1, Email brandizzate
Dati
Cloudflare D1
24 migrazioni: prenotazioni, clienti, programmi, workout, movimenti. Un solo insert NOT EXISTS evita le doppie prenotazioni.
- Cloudflare D1
- SQL
Riceve da Cockpit del trainer, Motore prenotazioniPassa a Area clienti, Worker cron
Uscita
Area clienti
App installabile: accesso con link email e codice a 6 cifre, anamnesi, misurazioni con grafici, programmi, workout con log delle serie, export PDF.
- React
- PWA
Riceve da Cloudflare D1
Infrastruttura
Worker cron
Worker separato ogni 15 minuti: promemoria e cancellazione dei dati personali dopo 24 mesi.
- Cron Worker
Riceve da Cloudflare D1Passa a Email brandizzate
Uscita
Email brandizzate
Conferma con file .ics, promemoria e annullamento, inviati con Resend dal dominio del cliente.
- Resend
- .ics
Riceve da Motore prenotazioni, Worker cron
Il problema
Un personal trainer prendeva gli appuntamenti a mano, tra messaggi e telefonate. Voleva un sistema di prenotazione suo, senza abbonamenti e senza un software nuovo da imparare: quando blocca un orario sul suo Google Calendar, quello slot sparisce dal sito.
Cosa ho costruito
- Ho diviso il codice in un monorepo pnpm: il sito, un worker cron e un motore di prenotazione condiviso da entrambi.
- Ho calcolato gli slot lato server dai suoi orari di lavoro meno gli impegni del calendario, salvato ogni orario in UTC e convertito in un solo modulo testato.
- Ho aggiunto un'area clienti con accesso tramite link email e codice a 6 cifre: anamnesi, misurazioni, programmi di allenamento, workout con log delle serie, programma in PDF.
- Ho costruito un cockpit per clienti, pacchetti e incassi, dove un vocale diventa una bozza di movimenti (Whisper, poi Claude) che lui conferma prima di salvare.
- Ho messo nell'hero un bilanciere 3D procedurale, scaricato solo su desktop quando il browser è inattivo; i telefoni ricevono un poster CSS.
La parte difficile
Evitare le doppie prenotazioni senza transazioni. Ogni prenotazione è un solo insert con guardia NOT EXISTS, che D1 esegue uno alla volta, e il calendario viene ricontrollato subito prima della scrittura. I cambi d'ora sono coperti da test su entrambi i passaggi dell'ora legale.
Risultato
In produzione sul dominio del cliente, sui piani gratuiti di Cloudflare e Resend. Lo stesso motore è diventato la base di due siti per clienti successivi.
Il mio ruolo
Progetto per un cliente, in solitaria. Ho raccolto i requisiti, scelto l'architettura, rivisto e collaudato ogni flusso con una checklist di go-live e configurato dominio, DNS e segreti; Claude Code ha scritto 219 dei 220 commit.