marketing

Booking call / videocall

Prenotazione pubblica call/videocall con calendario slot, conferma admin accept/reject, generazione Google Meet automatica e .ics in mail. Riuso del modulo /book già attivo su Footility.com.

Cosa fa questo modulo

Modulo «Booking call / videocall»: pagina pubblica di prenotazione (route `/book` generica oppure `/{projectSlug}/book` per progetto specifico) dove un visitatore sceglie data+ora+durata tra slot disponibili, compila i propri dati (nome, email, telefono, messaggio, eventuali invitati aggiuntivi via tagify multi-email) e invia richiesta che diventa una `Activity` in stato `booked` (`is_call=true`) collegata o no a un Project; admin riceve mail con CTA accept/reject; su accept l'attività passa a `confirmed`, viene creato l'evento Google Calendar con link Meet automatico e inviata mail conferma al cliente con allegato .ics scaricabile; su reject viene inviata mail di cortesia con motivazione opzionale. Riuso 1:1 del modulo `/book` **già implementato e in produzione su Footility.com** — questa scheda inventario serve a tracciare il riuso del modulo come prodotto offerto ai clienti del workspace (ogni cliente ha bisogno di una pagina «Prenota una call con noi» professionale per qualificare lead senza ping-pong mail). Componenti del codice riusati: `routes/web.php` (Route GET/POST `/book` e `/{projectSlug}/book` + admin accept/reject/cancel `/admin/book/{activity}/...` + `booking/calendar-invite/{activity}` signed per .ics), `App\Http\Controllers\PublicBookingController` (metodi `createGeneric`/`storeGeneric`/`createForProjectSlug`/`storeForProjectSlug`/`confirm`/`calendarInvite`/`adminAccept`/`adminReject`/`adminCancel` + helper privati `createInternal`/`storeInternal`/`findProjectBySlugOrFail`/`icsEscape`), `App\Services\Booking\BookingAvailabilityService` (`buildAvailability` con start/end date + durate possibili + timezone + projectId + clientEmail, `getOccupiedBlocksByDate` per render disabilitazione slot occupati, `isSlotAvailable` validazione server-side anti-doppia-prenotazione), `App\Services\Booking\GoogleCalendarBookingService` (`createEventForBooking` con generazione automatica `hangoutLink` Meet via Calendar API `conferenceData.createRequest`, `updateEventForBooking` su accept/reject, `deleteEvent` su cancel), `App\Models\Activity` con campi `is_call` bool, `call_accepted_at` datetime, `google_meet_link` string, `google_event_id` per sync, `start_date`/`end_date` slot, `status` (`booked`/`confirmed`/`cancelled`/`rejected`), `App\Models\ActivityCallInvitee` (multi-invitee con `order` 0=primary, email + nome, FK activity), mail Markdown `App\Mail\CallBookingPendingMail` (al cliente: «richiesta ricevuta in attesa di conferma» + dettagli slot), `CallBookingAcceptedMail` (al cliente: «confermata» + link Meet + .ics allegato + tasto «Aggiungi al calendario»), `CallBookingRejectedMail` (motivazione opzionale), `CallBookingCancelledMail` (in caso di cancellazione admin), view Blade `resources/views/public/book/create.blade.php` (form pubblico con calendario interattivo e selezione slot), `schedule.blade.php` (componente calendario slot), `confirm.blade.php`+`confirm-pending.blade.php` (landing post-submit), `admin-result.blade.php`+`admin-reject.blade.php` (UI admin accept/reject con motivazione). Flusso utente pubblico: 1) cliente apre `/book` o `/{slug}/book`, sceglie durata (15/30/45/60 min configurabile), il calendario mostra giorni navigabili con slot orari liberi (filtrati per occupazione Activity esistenti e business hours configurabili), 2) seleziona slot, compila nome+email+telefono+messaggio (e opzionalmente altre email partecipanti via tagify), accetta privacy, 3) POST genera `Activity` is_call=true status=booked con `start_date`+`end_date` calcolati da slot+durata, crea record `ActivityCallInvitee` primary + secondari, invia mail pending al cliente + notifica admin Footility, 4) cliente atterra su pagina conferma «richiesta inviata», 5) admin clicca link accept nella mail → `adminAccept` aggiorna a confirmed, chiama `GoogleCalendarBookingService` che crea evento Google Calendar dell'utente admin (OAuth token salvato) con guest list = tutti gli invitee, `conferenceData.createRequest` con `requestId` random+`type=hangoutsMeet` genera link Meet definitivo, mail accepted parte verso primary+secondari con link Meet e .ics signed URL per add-to-calendar Outlook/Apple, 6) admin può rifiutare con motivazione free-text (mail rejected al cliente) o cancellare post-confirmed (mail cancelled). Tecnologie e dipendenze: Laravel routing + Eloquent + Mail + OAuth Google Calendar API (`google/apiclient` + `GoogleSyncService` workspace-wide per token management), tagify JS per multi-email, calendar UI custom o FullCalendar embed (vedi `fullcalendar-global.js`), signed URL middleware per `/booking/calendar-invite/{activity}.ics` no-auth ma TTL-limited, ICS RFC 5545 generato inline (BEGIN:VCALENDAR/VEVENT con UID+DTSTAMP+DTSTART/DTEND UTC+SUMMARY+DESCRIPTION escaped, embed link Meet in DESCRIPTION). Differenze e relazioni con altri moduli inventario: **#8323 calendario-disponibilita-slot** è il building block generico «calendario slot con regole disponibilità riusabile» — questo modulo /book lo specializza per il caso d'uso «prenota call con team Footility/cliente» (UI form contatti dedicata, integrazione Google Meet auto, multi-invitee, mail flow accept/reject); **#8324 prenotazione-caparra-stripe** aggiunge layer pagamento caparra Stripe pre-conferma — booking-call invece è no-pay, conferma manuale admin; **#8316 lead-capture-multi-step** è form lead multi-step generico — booking-call si concentra su slot+slot e dati minimi per call, può integrarsi come ultimo step di lead-capture («qualificato → prenota subito call discovery»); **#8104 form-contatti-lead** form generico contatti — booking-call ha in più il calendario slot e la sync Google. Casi d'uso workspace: Footility (la pagina `/book` di Footility.com è il caso d'uso primo: clienti workspace prenotano consulenza Paolo Mistretta con auto-Meet, evita ping-pong mail per fissare slot), Holiday Self Drive (pagina «Parla con il nostro tour operator» pre-prenotazione veicolo, qualifica lead alto valore), Klabhouse (consulenza orientamento corsi con coach esperto, slot 30 min videocall genitori-studente-coach), gestionali B2B (Casarile/Altramusica/LB advisory: pagina «Demo gestionale» discovery call 45 min con sales prima di proposta commerciale), the-body-code/realpilates (call introduttiva con personal trainer per definire obiettivi prima di iscrizione corso, integrato con #8323 calendario disponibilità trainer multi-orario), mscarichi (consulenza pre-preventivo per servizi grandi volumi b2b, sopralluogo virtuale via Meet con condivisione schermo cliente), prontointervento (call urgente «valutazione gravità» con tecnico prima di dispatching sopralluogo fisico — pre-screening telefonico/video evita uscite a vuoto). Aspetti chiave UX: calendario mobile-first con swipe giorno/settimana, slot tap-friendly grandi, fuso orario auto-rilevato dal browser + mostrato esplicitamente in mail («2026-05-20 14:30 Europe/Rome (CET)»), buffer time configurabile tra slot per pause admin (es. 15 min tra una call e la successiva), max-advance-booking configurabile (es. solo fino a 60 gg avanti per evitare prenotazioni speculative), min-notice configurabile (es. min 2 ore prima dello slot per dare tempo admin di prepararsi), business hours per giorno settimana (es. lun-ven 9-18, sab 9-13, dom chiuso) configurabili in DB o config, blackout dates per ferie admin (importate da Google Calendar admin via `getOccupiedBlocksByDate` che già legge eventi calendar esistenti come «occupato»), reminder automatici (cron `php artisan booking:send-reminders` 24h+1h prima slot con mail/SMS richiama no-show), no-show tracking (admin marca attività come no-show post-slot, statistiche cliente in dashboard per evitare offrire slot a chi disdice troppo). Estensioni in roadmap: round-robin assegnazione automatica tra più admin team (oggi è singolo admin Paolo, ma per team sales serve dispatcher), buffer per categoria call (demo 60min con prep 30min, support 15min senza prep), durate diverse per progetto (consulenza Footility 45min, Holiday Self Drive 30min, demo gestionali 60min con tour guidato), recap mail post-call con prossimi passi (con #8316 lead-capture-multi-step può precompilare step «riepilogo discovery»), AI transcript+summary call Meet (via #8337 trascrizione AI: download recording Meet → Whisper transcribe → LLM summary action items → mail recap automatica), rebooking smart (cliente clicca «Sposta» in mail conferma → calendario con slot alternativi, no nuovo flusso completo), waitlist (se slot pieno utente in coda, notifica auto se libera), CRM sync (oltre a Google, push Activity in HubSpot/Pipedrive come deal+activity tipo «discovery call»), embeddable iframe `<iframe src="https://footility.com/{slug}/book?embed=1">` per clienti workspace che vogliono integrare booking nel proprio sito senza redirect (white-label brand cliente), API REST `POST /api/booking/availability` per integrazione mobile app cliente, multi-lingua (oggi italiano, aggiungere EN per clienti internazionali come Holiday Self Drive English market). GDPR: privacy consent obbligatorio pre-submit (link policy in modal/nuova tab), email+telefono cliente storicizzati in `Activity` + `ActivityCallInvitee` con `created_at`, retention configurabile (es. attività cancellate purge dopo 24 mesi), diritto oblio via cancellazione admin Activity + invitee record. Anti-spam/abuse: rate limit per IP (max 3 prenotazioni/ora stesso IP), validazione email DNS MX, validazione telefono libphonenumber opzionale, blacklist email disposable, captcha invisible Cloudflare Turnstile su submit (opt-in via config), honeypot field nascosto. Performance: query availability cached per giorno+timezone (TTL breve 5 min per non servire slot ormai occupati), prefetch slot successivo+precedente al render calendario, lazy-load mese successivo solo su scroll, Core Web Vitals LCP <1.5s su `/book`. Comandi artisan: `php artisan booking:send-reminders {--hours=24,1}` (cron), `php artisan booking:purge-old {--older-than-days=730}` (GDPR retention), `php artisan booking:sync-google-calendars {--user=}` (forza re-sync token OAuth scaduti), `php artisan booking:report-stats {--month=}` (report mensile: # prenotate, # confermate, # rifiutate, # no-show, conversion rate, durata media, top progetti). Per nuovo cliente del workspace: 1) config slug progetto (es. `holiday-self-drive`) → URL `/holiday-self-drive/book` attivo, 2) config business hours + durate slot in settings progetto (UI admin dedicata o seeder), 3) admin del progetto connette Google Calendar OAuth via flusso GoogleSyncService (per leggere occupato + creare evento Meet su suo calendar), 4) personalizza copy mail (subject, signature, branding logo/colore via #6870 sistema multitenant Footility), 5) eventualmente embed iframe `<iframe src=".../book?embed=1">` nel sito cliente. Costo riuso (modulo già esistente, lavoro = adattamento per nuovo cliente): 0.25 giorno config nuovo progetto (slug, durate, business hours), 0.25 giorno OAuth Google admin progetto + test creazione evento Meet, 0.25 giorno custom copy mail + branding logo+colori cliente, 0.25 giorno test E2E end-to-end (apri /slug/book → prenota → admin accept → verifica Meet+ics+mail accepted ricevuti), 0.5 giorno opzionale embed iframe nel sito cliente + tracking conversione, 0.5 giorno opzionale estensioni custom (round-robin multi-admin, rebooking smart, durate per categoria), 0.5 giorno testing flussi edge (slot al limite business hours, prenotazione ultimo minuto, double-booking concorrente, OAuth token scaduto admin, Google Calendar down fallback). Costo dev nuove feature roadmap (oltre riuso): 1 giorno round-robin team multi-admin, 1 giorno waitlist+rebooking smart, 1.5 giorno AI transcript+summary post-call con #8337, 0.5 giorno API REST headless, 1 giorno multi-lingua EN+altre. Dipendenze: Laravel Mail markdown, Google API client + workspace `GoogleSyncService` OAuth, tagify JS per multi-email invitee, calendario UI custom o FullCalendar (presente in `resources/js/fullcalendar-global.js`), signed URL middleware per .ics no-auth, opz. Cloudflare Turnstile captcha, opz. libphonenumber telefono, opz. #8323 calendario-disponibilita-slot come building block sottostante per business hours/blackout/buffer, opz. #8331 mailer per template mail custom branding, opz. #8316 lead-capture-multi-step come pre-step qualificazione, opz. #8337 trascrizione AI per recap automatici post-call, opz. CRM esterno HubSpot/Pipedrive per sync deal.

Esempi d'uso

  • marketing

Demo correlate