MAY Studio — Landing Page + EasyAppointments
Landing page bonita para MAY Studio (Horta, Barcelona) con reservas gestionadas por EasyAppointments.
El frontend (HTML/JS puro) sigue siendo el de la landing, pero las reservas, clientes y servicios se gestionan completamente con EasyAppointments.
Stack actual
- Web (estático): Go + proxy reverso a EasyAppointments API
- Gestión de citas, clientes y servicios: EasyAppointments (PHP + MySQL)
- Base de datos: MySQL (para EA)
- Docker Compose: todo junto (web + easyappointments + mysql)
Cómo ejecutar (Desarrollo y Producción)
1. Configurar secretos
cp .env.example .env
# Edita .env: pon tu EA_API_KEY y una MYSQL_ROOT_PASSWORD fuerte.
.env está en .gitignore y nunca se sube al repositorio.
2. Levantar todo
docker compose up -d --build
- Landing + reservas: http://localhost:8234
- Panel de administración EasyAppointments: http://localhost:8888
3. Primer arranque (importante)
- Abre http://localhost:8888
- Completa el asistente de instalación de EasyAppointments.
- Crea un usuario administrador.
- Ve a Providers → crea al menos un proveedor (ej. "May").
- Ve a Services → crea tus servicios (puedes usar la lista anterior de servicios como referencia).
- Asigna los servicios al proveedor.
- Configura el Working Plan del proveedor (horario).
- Anota el ID del Provider (normalmente 1) y edita
static/index.html→ líneaconst PROVIDER_ID = 1;
Variables (en .env)
EA_API_KEY— token de API de EasyAppointments (Settings → API en el panel).MYSQL_ROOT_PASSWORD— contraseña de la base de datos.EA_BASE_URL— URL pública del panel de EA (cámbiala en producción).
Actualizar
git pull
docker compose up -d --build
Notas sobre la integración
EasyAppointments es la única fuente de verdad. El servidor Go no guarda nada: ni clientes, ni citas, ni servicios. Todo se lee y se escribe contra la API de EA.
- Los servicios y la disponibilidad los lee el frontend de EA (a través del proxy de solo lectura).
- El calendario deshabilita los días sin ningún hueco vía
GET /api/month-availability(agregado server-side día a día contra EA, con caché de 10 min por mes+servicio). - Al reservar, el navegador envía la selección a
POST /api/booky el servidor:- lee los servicios de EA (fuente de verdad de nombre y duración),
- busca o crea el cliente por teléfono (identifica al cliente; el email es opcional),
- crea una cita con el servicio de mayor duración y el bloque total en las notas.
- La gestión completa (clientes, servicios, citas, proveedores, etc.) se hace desde http://localhost:8888
Seguridad del proxy
El servidor Go no expone la API de EasyAppointments tal cual:
- El proxy
/ea-api/solo deja pasar lecturas no sensibles (categorías, servicios, proveedor, disponibilidad), añadiendo la auth admin en el servidor. La lista blanca está enmain.go(eaAllowedRoutes); cualquier otra ruta/método recibe404antes de inyectar credenciales. - Las escrituras y la búsqueda de clientes no pasan por el proxy: se orquestan
server-side en
POST /api/book. Así el navegador nunca puede listar/borrar/modificar clientes ni citas, ni volcar datos personales de EA.
Comportamiento multiservicio
El formulario permite seleccionar varios servicios (multi-checkbox).
Cómo funciona actualmente con EasyAppointments:
- UI: Puedes seleccionar múltiples servicios. Se muestra el resumen con nombres unidos por "+" y la duración total sumada.
- Comprobación de disponibilidad: Se consulta el endpoint de EA usando el servicio de mayor duración de los seleccionados. Luego se filtra client-side para exigir un bloque contiguo de la duración total (suma de todos).
- Ejemplo: servicios de 45min + 30min → total 75 min. Solo se ofrecen horas de inicio desde las que quepan 75 min seguidos sin solape.
- Al crear la reserva:
- Se crea una sola cita en EasyAppointments.
- Se usa como
serviceIdel servicio de mayor duración (para que coincida con la disponibilidad consultada). - Se calcula la hora de fin sumando la duración total de todos los servicios seleccionados y se envía explícitamente el campo
end. Así EA bloquea el tiempo completo en el calendario de la empleada. - Solo una empleada (May) por ahora → el bloque queda reservado y no se puede reservar otra cosa en ese intervalo.
- En el campo
notesse guarda el detalle completo:Nombre: ... Teléfono: ... Email: ... (solo si el cliente lo dio) Servicios: Corte + Tinte + ... Duración total: 120 min Mensaje: ...
Limitación: EasyAppointments modela una cita = un servicio principal. Los servicios adicionales quedan documentados en las notas del cliente y de la cita. No se crean múltiples registros de cita.
Recomendación: Si usas combinaciones frecuentes, crea "servicios combinados" directamente en EasyAppointments (ej. "Corte + Tinte Señora - 120min").