AgendaCore: come modelliamo le disponibilità
Regole, durate, buffer, eccezioni e appuntamenti determinano ogni slot che AgendaCore propone al cliente.
Lunedì, ore 10:00. Il professionista lavora, il calendario mostra spazio e il cliente vuole prenotare. Il servizio dura cinquanta minuti, richiede dieci minuti di buffer e alle 10:45 comincia un impegno importato da un altro calendario. Quello spazio non può diventare un appuntamento.
AgendaCore mostra nel link pubblico solo gli orari che il cliente può prenotare. Per produrre quell’elenco, il motore combina disponibilità settimanali, durata del servizio, buffer, blocchi manuali e impegni già presenti. Ogni elemento modifica l’intervallo utile.
Prima di disegnare il calendario sullo schermo dobbiamo definire il modello che produce gli slot.
La disponibilità comincia da una regola
Una regola descrive un periodo nel quale possiamo cercare slot. Può dire, per esempio, che il lunedì il professionista riceve dalle 09:00 alle 13:00 e dalle 15:00 alle 18:00. AgendaCore permette di configurare giorni, finestre orarie, durata e buffer.
La regola ricorrente conserva l’intenzione dell’utente. Non conviene duplicare subito mesi di righe nel database: una modifica all’orario settimanale costringerebbe a capire quali occorrenze aggiornare e quali preservare. Il motore legge la regola e genera le occorrenze necessarie per il periodo richiesto.
Lo standard iCalendar RFC 5545 mostra quanto può diventare ricca una ricorrenza: frequenza, intervallo, giorni della settimana, data finale ed esclusioni. AgendaCore può usare un modello più vicino al lavoro degli studi, ma quello standard resta un riferimento utile per nomi e casi limite. La RFC 7953 estende lo stesso ecosistema con un formato dedicato alla disponibilità.
Uno slot è il risultato di un calcolo
Una regola genera candidati. Il motore deve ancora dimostrare che ciascun candidato può contenere il servizio richiesto.
Prendiamo una finestra dalle 09:00 alle 13:00. Un servizio da cinquanta minuti con dieci minuti di buffer occupa un’ora nel calcolo, anche se il cliente vede soltanto la durata dell’appuntamento. Un inizio alle 12:20 porterebbe l’intervallo operativo oltre le 13:00, quindi il motore lo esclude.
La durata appartiene al servizio. Il buffer può dipendere dal lavoro che lo circonda: preparare una stanza, compilare una scheda o evitare che due clienti si incrocino. Nel calcolo usiamo l’intervallo occupato; l’interfaccia mostra l’orario utile al cliente.
Con un solo calcolo evitiamo di spargere formule diverse tra calendario pubblico, dashboard e API. Tutti chiedono gli slot allo stesso motore e ricevono lo stesso risultato.
Le eccezioni tagliano il calendario
Una settimana ricorrente descrive la normalità. Il lavoro quotidiano aggiunge ferie, chiusure, pause e blocchi inseriti a mano. AgendaCore applica questi intervalli sopra la regola di base.
Il calcolo segue una priorità leggibile:
- la regola apre una finestra;
- chiusure e blocchi sottraggono tempo;
- appuntamenti e calendari collegati occupano ciò che resta;
- durata e buffer decidono quali partenze sono ancora valide.
Una chiusura dalle 11:30 alle 12:30 non richiede di riscrivere la regola del lunedì. Il motore conserva entrambe le informazioni e applica l’eccezione alla data interessata. In questo modo possiamo spiegare perché uno slot è sparito e possiamo rimuovere il blocco senza ricostruire l’orario settimanale.
I confini decidono se due appuntamenti si toccano
Gli intervalli hanno bisogno di una convenzione. Adottiamo la forma [inizio, fine): l’inizio appartiene all’intervallo, la fine resta esclusa. Un secondo appuntamento può quindi cominciare alle 11:00 dopo uno che termina alla stessa ora, se il servizio non richiede buffer.
La documentazione PostgreSQL sui range temporali descrive la stessa convenzione e gli operatori per verificare contenimento, adiacenza e sovrapposizione. Una regola coerente sui confini evita correzioni sparse come “sottrai un secondo” o “aggiungi un millisecondo”, che prima o poi producono un buco.
Il fuso orario fa parte del dato
Le 09:00 esistono dentro un fuso orario. Il cambio tra ora solare e ora legale può creare un’ora doppia oppure saltarne una. Salvare soltanto una data e un orario locale toglie al motore l’informazione necessaria per ricostruire l’istante.
Il modello deve conservare il fuso scelto dallo studio e trasformare gli orari in istanti quando confronta appuntamenti e calendari esterni. I nomi come Europe/Rome arrivano dal Time Zone Database di IANA, aggiornato quando governi e autorità cambiano le regole. La RFC 3339 offre un formato interoperabile per rappresentare timestamp e offset nelle API.
Il fuso dello studio governa la regola settimanale. Il browser del cliente governa la presentazione, se il prodotto decide di convertire l’orario. Mescolare i due passaggi rende i bug stagionali difficili da riprodurre.
I calendari esterni diventano intervalli occupati
AgendaCore può lavorare con Google Calendar e calendari sorgente. Il motore non deve importare il significato di ogni evento per calcolare uno slot; gli basta sapere quale intervallo risulta occupato.
Google Calendar espone una richiesta freeBusy che restituisce gli intervalli impegnati per uno o più calendari. iCalendar definisce a sua volta le informazioni FREEBUSY. Questi formati diversi possono entrare nello stesso passaggio del calcolo dopo la normalizzazione di data, fuso e confini.
Una fonte esterna può arrivare in ritardo o non rispondere. Il prodotto deve dichiarare la strategia adottata: usare l’ultima sincronizzazione valida, bloccare la prenotazione o chiedere conferma manuale. Nascondere questa decisione dietro un generico errore di calendario sposta il problema sul professionista.
Due clienti possono scegliere lo stesso orario
La pagina pubblica calcola gli slot per una fotografia del calendario. Tra la risposta e il clic del cliente possono passare secondi. In quel tempo un’altra persona può scegliere lo stesso orario.
Il server deve ripetere la verifica quando registra la prenotazione. Il database deve poi impedire che due scritture concorrenti occupino lo stesso intervallo. Una sequenza “leggi, controlla, inserisci” eseguita senza protezioni lascia spazio a una race condition.
PostgreSQL documenta i livelli di isolamento delle transazioni e offre vincoli di esclusione capaci di rifiutare range sovrapposti. L’estensione btree_gist permette di combinare l’intervallo con un identificatore, come il calendario o la risorsa interessata. La regola di integrità resta così vicina ai dati che protegge.
Il controllo applicativo serve ancora per restituire un messaggio comprensibile. Il vincolo nel database chiude l’ultima finestra di concorrenza.
Un motore utile sa spiegare il risultato
Un elenco vuoto non basta per capire se il problema nasce dalla regola settimanale, da un blocco o dalla durata del servizio. Durante lo sviluppo ci serve osservare i passaggi del calcolo e associare ogni esclusione a una causa.
Usiamo questa traccia nei test e nel supporto. Possiamo costruire casi con una finestra nota, aggiungere un solo vincolo e verificare quali candidati scompaiono. Quando un professionista segnala un orario inatteso, possiamo ricostruire la stessa giornata invece di indovinare.
I test più utili si concentrano sui bordi: servizio che termina alla chiusura, blocco che comincia alla fine di un appuntamento, cambio dell’ora e due richieste concorrenti. Il percorso ordinario richiede pochi casi; le regole sui confini coprono gran parte del lavoro.
Dal modello al link di prenotazione
Il cliente deve vedere una scelta breve: giorno, ora e servizio. AgendaCore si prende il resto del calcolo. Il professionista configura disponibilità e blocchi; il motore genera candidati, sottrae gli intervalli occupati e verifica la prenotazione al momento della scrittura.
Il motore restituisce un elenco di orari prenotabili dopo aver applicato tutte le regole. Se nessuno slot resta, la lista d’attesa di AgendaCore può raccogliere la richiesta e rimetterla in gioco quando si libera spazio.
Il cliente vede una casella libera. Noi conserviamo le decisioni che l’hanno prodotta per poterle verificare, spiegare e correggere.
Riferimenti per andare sotto il cofano
- AgendaCore: booking, disponibilità, buffer e calendari collegati
- RFC 5545: iCalendar e regole di ricorrenza
- RFC 7953: Calendar Availability
- IANA Time Zone Database
- Google Calendar API: Freebusy query
- PostgreSQL: range e multirange
- PostgreSQL: operatori sugli intervalli
- PostgreSQL: isolamento delle transazioni
- PostgreSQL: vincoli di esclusione
- PostgreSQL: estensione btree_gist