# 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 ```sh 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 ```sh docker compose up -d --build ``` - Landing + reservas: **http://localhost:8234** - Panel de administración EasyAppointments: **http://localhost:8888** ### 3. Primer arranque (importante) 1. Abre http://localhost:8888 2. Completa el asistente de instalación de EasyAppointments. 3. Crea un **usuario administrador**. 4. Ve a **Providers** → crea al menos un proveedor (ej. "May"). 5. Ve a **Services** → crea tus servicios (puedes usar la lista anterior de servicios como referencia). 6. Asigna los servicios al proveedor. 7. Configura el **Working Plan** del proveedor (horario). 8. **Anota el ID del Provider** (normalmente 1) y edita `static/index.html` → línea `const 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 ```sh 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). - Al reservar, el navegador envía la selección a `POST /api/book` y **el servidor**: - lee los servicios de EA (fuente de verdad de nombre y duración), - busca o crea el cliente por **email**, - 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á en `main.go` (`eaAllowedRoutes`); cualquier otra ruta/método recibe `404` **antes** 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 `serviceId` el 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 `notes` se guarda el detalle completo: ``` Nombre: ... Email: ... Teléfono: ... 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").