π Google Calendar Integration - Soluzione Robusta β
Documentazione completa dell'integrazione Google Calendar bidirezionale per Blade CRM.
π― FUNZIONALITΓ β
1. SINCRONIZZAZIONE BIDIREZIONALE β
Google β Blade (Blocca Slot Occupati) β
- Legge eventi da Google Calendar
- Filtra slot occupati in booking page
- Aggiornamento ogni 5 minuti (cache)
- Filtri avanzati (eventi cancelled, free, declined)
Blade β Google (Crea Eventi) β
- Crea evento quando ospite prenota
- Titolo personalizzato
- Google Meet link automatico
- Invita ospite via email
- Descrizione con dettagli appuntamento
ποΈ ARCHITETTURA β
API Google Usata: Events.list + Events.insert β
NON usiamo:
- β FreeBusy API (troppo limitata)
- β Sync Tokens (troppo complesso)
- β Package Spatie (vogliamo controllo totale)
Usiamo:
- β
Google API Client ufficiale (
google/apiclient) - β
Events.listper lettura - β
Events.insertper scrittura - β Cache 5 minuti per performance
π CODICE CORE β
1. Lettura Eventi (Google β Blade) β
php
// app/Services/GoogleCalendar/GoogleCalendarService.php
public function getEventsForDay(UserCalendar $calendar, Carbon $startOfDay, Carbon $endOfDay): array
{
$client = $this->getClientForCalendar($calendar);
$service = new GoogleCalendar($client);
// Lista eventi per il giorno
$events = $service->events->listEvents($calendar->google_calendar_id, [
'timeMin' => $startOfDay->toRfc3339String(),
'timeMax' => $endOfDay->toRfc3339String(),
'singleEvents' => true, // Espande ricorrenti
'orderBy' => 'startTime',
'maxResults' => 100,
]);
// Estrai busy times con filtri avanzati
return $this->extractBusyTimesFromEvents($events->getItems(), $startOfDay, $endOfDay);
}Filtri applicati:
- β
Eventi
cancelledβ Ignorati - β
Eventi
transparency: transparentβ Ignorati (non bloccano calendario) - β
Eventi
declinedβ Ignorati - β Eventi all-day β Corretti (no +1 giorno)
- β Timezone β Rispettato
2. Scrittura Eventi (Blade β Google) β
php
// app/Jobs/CreateGoogleCalendarEventJob.php
$eventData = [
'summary' => 'Meeting con Mario Rossi', // Titolo personalizzato
'description' => 'Note: ...\nTelefono: ...', // Descrizione completa
'start' => [
'dateTime' => '2025-11-04T10:00:00+01:00',
'timeZone' => 'Europe/Rome',
],
'end' => [
'dateTime' => '2025-11-04T10:30:00+01:00',
'timeZone' => 'Europe/Rome',
],
'attendees' => [
['email' => 'ospite@example.com'], // Invita ospite
],
'conferenceData' => [ // Google Meet
'createRequest' => [
'requestId' => 'appointment-123',
'conferenceSolutionKey' => ['type' => 'hangoutsMeet'],
],
],
];
$event = $googleCalendar->createEventOnCalendar($calendar, $eventData);
$meetLink = $event->getHangoutLink(); // Link Google MeetFeature supportate:
- β Titolo personalizzato con nome ospite e company
- β Google Meet link automatico
- β Inviti via email agli attendees
- β Descrizione con note ospite e telefono
- β Location (in-person, phone, video)
- β Reminders personalizzati
βοΈ CONFIGURAZIONE β
1. OAuth Google Calendar β
File: config/services.php
php
'google_calendar' => [
'client_id' => env('GOOGLE_CALENDAR_CLIENT_ID'),
'client_secret' => env('GOOGLE_CALENDAR_CLIENT_SECRET'),
'redirect_uri' => env('GOOGLE_CALENDAR_REDIRECT_URI'),
'scopes' => [
'https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events',
],
'calendar_id' => env('GOOGLE_CALENDAR_ID', 'primary'),
],2. Variabili .env β
env
GOOGLE_CALENDAR_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CALENDAR_CLIENT_SECRET=xxx
GOOGLE_CALENDAR_REDIRECT_URI=https://tuodominio.com/oauth/google-calendar/callback
GOOGLE_CALENDAR_ID=primaryπ FLUSSO COMPLETO β
1. Connessione Google Calendar β
User β Dashboard β Google Calendar β Connetti
β
OAuth redirect a Google
β
User autorizza
β
Callback salva tokens (encrypted)
β
UserCalendar creato con:
- access_token (encrypted)
- refresh_token (encrypted)
- expires_at2. Prenotazione Ospite β
Ospite β Booking Page β Seleziona slot
β
Frontend controlla isDayAvailable (weekly_hours)
β
Backend:
1. Genera slot teorici (weekly_hours)
2. Filtra appuntamenti locali
3. Chiama getEventsForDay() β busy times Google
4. Filtra slot occupati
5. Ritorna slot disponibili
β
Ospite seleziona slot e compila form
β
Backend:
1. Verifica slot disponibile
2. Crea Appointment
3. Dispatch CreateGoogleCalendarEventJob
β
Job:
1. Crea evento su Google Calendar
2. Ottiene Google Meet link
3. Aggiorna Appointment con google_event_id e meet_link
β
Ospite riceve email con Meet link3. Lettura Google Calendar (ogni richiesta slot) β
Frontend richiede slot β /booking/qw/slots?date=2025-11-04
β
Backend BookingController
β
BookingAvailabilityService:
1. Genera slot teorici
2. Filtra locali
3. Per ogni calendario associato:
- Controlla cache (5 min TTL)
- Se cache miss: getEventsForDay()
- Estrae busy times
- Filtra slot
β
Ritorna slot disponibili (senza occupati Google)π§ͺ TESTING β
Test 1: Lettura Google Calendar β
bash
# 1. Crea evento in Google Calendar
# Titolo: "Test Busy"
# Data: Domani 10:00-11:00
# 2. Aspetta 5 min (o clear cache)
php artisan cache:clear
# 3. Test API
php artisan google:test-busy qw {domani}
# Output atteso:
# β API call successful
# Busy periods found: 1
# β’ 10:00 - 11:00 (Test Busy)Test 2: Scrittura su Google β
bash
# 1. Prenota da booking page
# https://blade.laravel.cloud/booking/qw
# Slot: Domani 14:00
# 2. Verifica job processato
php artisan booking:check-last
# Output atteso:
# β Google Event ID: abc123
# β Meet Link: https://meet.google.com/xxx-yyy-zzz
# 3. Verifica Google Calendar
# https://calendar.google.com
# Evento "Meeting con..." presente β
Test 3: Filtri Avanzati β
bash
# 1. Crea evento "Free" in Google (Show as: Free)
# 2. Booking page β slot DISPONIBILE β
(non bloccato)
# 3. Crea evento normale in Google
# 4. Booking page β slot OCCUPATO β (bloccato)π PERFORMANCE β
| Operazione | Tempo | Cache | Note |
|---|---|---|---|
| Lettura eventi | ~100-200ms | 5 min | Con GZIP compression |
| Cache hit | ~5ms | - | Nessuna API call |
| Creazione evento | ~200-400ms | - | Include Meet link |
| Cambio mese | ~100-300ms | - | Loading indicator |
π§ COMANDI UTILI β
bash
# Test busy times
php artisan google:test-busy qw 2025-11-04
# Analisi timezone
php artisan google:analyze-timezone qw 2025-11-04
# Diagnosi backend
php artisan booking:diagnose-backend qw 2025-11-04
# Check ultimo appointment
php artisan booking:check-last
# Clear cache Google
php artisan cache:clearβ CHECKLIST FUNZIONAMENTO β
- [ ] Google Calendar connesso (/user-calendars)
- [ ] Token presente (access + refresh)
- [ ] Calendario associato a booking page
- [ ] Weekly hours configurati (Lun-Ven 09:00-17:00)
- [ ] Test
google:test-busyβ mostra eventi Google - [ ] Booking page mostra slot disponibili
- [ ] Slot occupati Google NON visibili in booking page
- [ ] Prenotazione crea evento in Google Calendar
- [ ] Google Meet link generato
- [ ] Ospite riceve invito email
π CONCLUSIONE β
Sistema finale:
- β Semplice (50 righe vs 250)
- β Robusto (Google API ufficiale)
- β Completo (tutte feature richieste)
- β Performante (GZIP + cache 5 min)
- β Manutenibile (codice pulito, logging dettagliato)
Zero dipendenze esterne (solo google/apiclient giΓ installato).
Pronto per produzione! π