Elena Bonciarelli
Sito e prenotazioni per uno studio di psicologia
Sito vetrina e sistema di prenotazione online per lo studio di psicologia Il Giardino di Psiche, ad Ardea. Un'unica app Next.js serve pagine e API: i pazienti prenotano un colloquio scegliendo modalità, sede e orario, e ogni appuntamento crea un evento sul Google Calendar dello specialista con relative email di conferma. Include un'area di amministrazione con login OTP per gestire disponibilità e avvisi.
- Anno
- 2026
- Ruolo
- Sviluppo full-stack
- Stato
- In produzione
- Committente
- Il Giardino di Psiche
Panoramica
Un'unica applicazione Next.js serve sia le pagine pubbliche dello studio (presentazione, team, servizi, sedi, FAQ) sia le API di prenotazione, più un'area di amministrazione riservata. In produzione una prenotazione crea un evento reale sul Google Calendar dello specialista e invia email a paziente e studio.
Problema
Lo studio doveva permettere ai pazienti di prenotare un colloquio online senza rischio di doppie prenotazioni, tenendo l'agenda sincronizzata con lo strumento che gli specialisti già usano — Google Calendar — e senza aggiungere un backend separato o un gestionale complesso da imparare per una persona non tecnica.
Architettura
Monorepo pnpm: l'app web Next.js (App Router, React, TypeScript strict) e un pacchetto di schemi Zod condivisi fra client e server, così le regole di validazione si scrivono una volta sola. Sito e API girano nello stesso processo: nessun servizio separato, nessun CORS.
Il server è a tre strati — controller (validazione + errori HTTP), servizi, repository. La persistenza è su SQLite (better-sqlite3, WAL) su un volume Docker.
Browser ──► Next.js (pagine + /api)
│
controller ─► service ─► repository ─► SQLite
│
├─► Google Calendar API (1 service account, N calendari)
└─► SMTP (Nodemailer)
Implementazione
I contenuti dello studio sono file JSON versionati, unica fonte di verità, esposti in sola lettura via API. La prenotazione è a step (modalità → sede → giorno/ora → contatti): la disponibilità viene calcolata combinando eventi Google Calendar, prenotazioni locali e blocchi manuali dell'admin.
POST /api/bookings applica un rate limit per IP, ri-valida lo slot, salva su SQLite, poi crea l'evento Calendar e invia le email in modo non bloccante: se queste ultime falliscono la prenotazione resta valida e l'errore va solo nei log.
Scelta di progetto
Un indice unico parziale su (psy_id, date, time, mode) WHERE status='active' rende la doppia prenotazione impossibile a livello di database, senza lock applicativi.
L'area admin non ha password: login con OTP a 6 cifre via email, whitelist di indirizzi gestita dall'interfaccia stessa, sessione cookie di 30 giorni. Il gestore della disponibilità è un calendario settimanale in cui ogni azione si applica subito via API, senza pulsante "Salva" — pensato per un'utente non tecnica.
Difficoltà
- Concorrenza sullo stesso slot: risolta con un vincolo di unicità nel DB anziché con lock.
- Dipendenza da un servizio esterno inaffidabile: fallback della disponibilità alle sole prenotazioni locali quando Google Calendar non risponde.
- Webhook Calendar senza scheduler: i canali Google scadono in circa una settimana, quindi vengono rinnovati "pigramente", innescati dal traffico, più un endpoint manuale protetto.
Risultati
Sito online su elenabonciarelli.com, servito da Next.js dietro Cloudflare. Prenotazione end-to-end funzionante, con sincronizzazione bidirezionale sul calendario dello specialista e notifiche email. Deploy riproducibile con un solo docker compose up -d --build.
Cosa ho imparato
Spingere le invarianti nel database invece che nel codice applicativo, progettare le integrazioni esterne come best-effort e adattare l'interfaccia di amministrazione al livello tecnico reale di chi la usa: feedback immediato, nessun "Salva", stesso linguaggio visivo del sito pubblico.