Crear un evento de principio a fin
Cada evento publicado involucra tres sistemas en orden estricto. Saltarse alguno rompe el flujo de reservación o de visualización.
Supabase → Cloudinary → Sanity Studio → Frontend
(DB) (imagen) (contenido) (automático)Paso 1 — Supabase: registrar el evento en la base de datos
El worker consulta la tabla events para validar slugs, obtener precios y vincular reservaciones. El evento debe existir en Supabase antes de que alguien pueda reservar.
Esquema de la tabla events
Si la tabla aún no existe, créala en el SQL Editor de Supabase:
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
event_date TIMESTAMPTZ,
price_amount NUMERIC(10, 2) NOT NULL DEFAULT 0,
capacity INT NOT NULL DEFAULT 30,
capacity_used INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
capacity_usedse incrementa automáticamente cuando un usuario crea una reservación. Sicapacity_used >= capacity, el worker rechaza nuevas reservaciones con el errorEVENT_FULL. Configura el trigger correspondiente según tu lógica de negocio.
Insertar un nuevo evento
INSERT INTO events (slug, title, event_date, price_amount, capacity)
VALUES (
'yoga-restaurativo-mayo-2025',
'Yoga Restaurativo',
'2025-05-17T11:00:00-06:00',
300.00,
30
);El
sluges el vínculo entre Supabase y Sanity. Debe ser idéntico en ambos sistemas. Define el slug aquí primero y úsalo al crear el documento en Studio.
Paso 2 — Cloudinary: subir la imagen del evento
Todas las imágenes del sitio se sirven desde Cloudinary. Sanity no almacena la imagen directamente; guarda únicamente el Public ID de Cloudinary.
Consulta la guía completa en Cloudinary → Gestión de imágenes.
Lo que necesitas de ese paso: el Public ID de la imagen subida (ej. eventos/yoga-restaurativo-mayo).
Paso 3 — Sanity Studio: crear el documento del evento
Abre el Studio en http://localhost:3333 y crea un nuevo documento de tipo Evento.
Campos obligatorios
| Campo | Dónde usarlo | Ejemplo |
|---|---|---|
title | Título principal de la tarjeta y página | Yoga Restaurativo |
slug | Debe coincidir exactamente con el slug de Supabase | yoga-restaurativo-mayo-2025 |
eventDate | Fecha/hora exacta para ordenamiento y filtros | 2025-05-17T11:00:00 |
priceAmount | Precio numérico — lo usa el worker para crear la orden de PayPal | 300 |
Campos de visualización
| Campo | Descripción | Ejemplo |
|---|---|---|
eyebrow | Etiqueta pequeña sobre el título | EVENTO DE PRIMAVERA |
date | Fecha formateada para la UI | 17 de mayo, 11:00 am |
dateShort | Versión compacta para tarjetas | MAY 17 |
timeRange | Duración del evento | 11:00 am – 1:10 pm |
price | Precio formateado para mostrar | MXN $300.00 |
description | Texto corto para tarjetas (2-3 líneas) | — |
longDescription | Descripción completa en la página del evento | — |
Imagen (Cloudinary)
| Campo | Descripción |
|---|---|
imagePublicId | El Public ID copiado de Cloudinary (ver Paso 2) |
imageAlt | Texto alternativo descriptivo para accesibilidad |
Ubicación
| Campo | Ejemplo |
|---|---|
location | Centro Holístico Zen |
city | Ciudad de México |
stateOrProvince | CDMX |
mapsEmbedUrl | URL del iframe de Google Maps |
mapsDirectionsUrl | URL de “Cómo llegar” de Google Maps |
Itinerario
El campo itinerary es un arreglo de bloques con dos campos cada uno:
{ time: "11:00 am", activity: "Bienvenida y respiración inicial" }
{ time: "11:20 am", activity: "Secuencia de apertura de caderas" }
{ time: "1:00 pm", activity: "Savasana y cierre" }Opciones adicionales
comingSoon— actívalo para publicar el evento sin mostrar precio ni formulario de reservación. Útil para anunciar con anticipación.reservationUrl— si el botón de reservación apunta a un link externo en lugar del modal.seo— metaTítulo, metaDescripción e imagen OG para redes sociales.
Publicar
Una vez rellenos todos los campos, haz clic en Publish en la esquina superior derecha del Studio. El evento queda disponible para el frontend inmediatamente (la web hace fetch de Sanity en tiempo de carga).
Paso 4 — Frontend: cómo se visualiza
El frontend consume los eventos a través de queries GROQ. No requiere ninguna acción manual — basta con que el evento esté publicado en Sanity.
Query de lista (eventos futuros)
*[_type == "event" && (eventDate >= now() || !defined(eventDate))]
| order(eventDate asc) {
title, slug, eyebrow, description,
date, dateShort, timeRange,
price, priceAmount,
imagePublicId, imageAlt,
comingSoon
}Query de detalle (por slug)
*[_type == "event" && slug.current == $slug][0] {
title, slug, eyebrow, description, longDescription,
date, dateShort, timeRange, price, priceAmount,
imagePublicId, imageAlt, comingSoon,
itinerary, location, city, stateOrProvince,
mapsEmbedUrl, mapsDirectionsUrl, seo
}Flujo de reservación
Cuando el usuario hace clic en Reservar:
ReservationModalllama aGET /api/reservations/check?slug=<slug>— verifica si ya tiene reservación activa- Si no tiene: llama a
POST /api/reservationscon{ eventSlug, fullName, email } - El worker busca el evento en Supabase por
slug— por eso el slug debe coincidir - Si hay cupo: crea la reservación en estado
pending - El modal abre el flujo de PayPal para completar el pago
Checklist de verificación
Antes de anunciar el evento, confirma cada punto:
| Sistema | Qué verificar |
|---|---|
| Supabase | El registro existe con el slug correcto y price_amount = precio real |
| Cloudinary | La imagen está subida y el Public ID es el correcto |
| Sanity | El documento está publicado (no en borrador), slug coincide con Supabase |
| Frontend | La tarjeta del evento aparece en la página de inicio |
| Reservación | El modal de reservación abre y el check de cupo responde correctamente |
| PayPal | En sandbox: se puede completar el flujo de pago end-to-end |