Agendamelo: un SaaS multi-tenant que se indexa sin contenido vacío
Una mini-web con agenda online que cualquier negocio en Chile publica en cinco minutos.
- Tipo
- Producto SaaS
- Año
- 2026
- Rol
- Founder / Product Engineer
- Stack
- Next.js · TypeScript · Supabase · Vercel
- Estado
- En producción

Por Jorge CortésPublicado el
Resumen
Diseñé Agendamelo, un SaaS multi-tenant para profesionales independientes en Chile. Cada negocio publica una mini-web con agenda online en cinco minutos. El sistema genera un directorio de 19 rubros por 69 comunas —unas 1.400 URLs— con copy único y fichas reales, no plantillas vacías. La comisión por reserva es cero.
Problema
Los profesionales independientes en Chile operan la agenda por WhatsApp. El cliente escribe. El profesional responde. Un cambio de hora reabre el hilo. Una inasistencia no deja un registro que se pueda consultar. Al día siguiente, el mismo ciclo.
Esa conversación no es un objeto público. No hay horario publicado. No hay precios que un buscador lea. No hay una URL que el cliente reenvíe sin copiar un chat. La presencia web, cuando existe, es un link en la bio de Instagram que no se indexa.
El oficio agrava el hueco. Una psicopedagoga, una fonoaudióloga, un profesor particular o un psicólogo no venden una hora suelta. Venden un tratamiento de 8 a 12 sesiones, casi siempre el mismo día de la semana. En WhatsApp eso es una cadena de mensajes. En un motor que solo conoce slots sueltos, es una tabla que falta.
Construí Agendamelo para sacar esa operación de la bandeja y dejarla en una URL. El tenant vive en agendamelo.cl/tu-negocio. El H1 del producto es una restricción: sitio y agenda online en cinco minutos. Los clientes reservan solos. Este caso cubre el territorio de un SaaS multi-tenant que se indexa —el mismo enfoque que ofrezco en productos digitales. Lo diseñé y lo opero como Jorge Cortés, ingeniero de producto en Santiago.
Restricciones
La restricción que manda es de tiempo percibido. Si el onboarding dura más de cinco minutos, el profesional vuelve a WhatsApp. Nombre, servicios con precios y horarios tienen que bastar para publicar. Galería, reseñas, equipo, FAQs y promociones llegan después.
El dinero es CLP. La unidad geográfica es la comuna, no un “city” genérico. El idioma de demanda es español. En el sitio hay una tabla que compara Agendamelo con WhatsApp y con Booksy. No la cito como venta. La leo como lista de lo que el producto tiene que resolver en Chile: pesos, comunas con nombre propio, y queries como “barbería en Providencia”.
No hay pasarela de pago para el cliente final. Reserva en línea, paga en el local. La plataforma cobra suscripción. Comisión por reserva: 0%. Eso evita Mercado Pago y la seña remota. El producto responde las inasistencias con recordatorios y reagendamiento autoservicio. No publico una tasa de no-show. No tengo una que pueda defender.
El trial es de 7 días, sin tarjeta. Después existe “Perfil Gratis”: la página sigue publicada y sigue en Google y en los directorios; se apagan el motor de reservas, los recordatorios, la lista de espera y las sesiones recurrentes. El cliente escribe por WhatsApp. Indexar un tenant que ya no reserva es una decisión de producto.
Agendamelo no vende dominios. En Web Pro el negocio conecta un dominio que ya tiene. Si no, usa el slug. El sitio bajo slug tiene que ser de primera clase, no un fallback.
Arquitectura que diseñé
Una sola app Next.js. El tenant se identifica por slug. El sitio público es una lectura acotada a ese tenant. El panel es escritura acotada al dueño. Los cinco nodos son el orden en que el sistema produce un objeto público y después lo hace encontrable.
Tenancy
Postgres en Supabase. Cada fila de negocio, servicio, horario, reserva y reseña lleva un tenant_id —o el equivalente del esquema. Las políticas RLS tienen que impedir que un proyecto lea las horas de otro. Un leak de agenda entre dos peluquerías es un incidente de producto.
El path /tu-negocio es la clave que ve el cliente. Por detrás puede haber un UUID. El directorio no lista ids internos: lista slug, comuna, rubro, servicios y precios. El dueño entra al panel. El cliente no crea cuenta para reservar: deja contacto, recibe correo, y usa un enlace único para cambiar o anular.
Onboarding y esquema
Nombre. Servicios con precio. Horario semanal. Con eso el render público ya tiene H1, precios y calendario. Si falta una de las tres, no se publica. Galería, reseñas, equipo, FAQs y promociones se agregan sin migrar.
El equipo —foto, especialidad, certificaciones— está en Estándar y en Web Pro. Pro suma un segundo profesional con horarios y servicios propios. El cliente elige a quién ve. Es otra fila en la relación profesional–servicio–slot, con el mismo tenant_id.
Las sesiones recurrentes entran el día uno. El landing apunta a pacientes semanales. El motor modela una serie: N sesiones, un día, un rango, y la capacidad de mover una instancia sin romper las demás. Un slot suelto no representa un tratamiento de 8 a 12 semanas.
Directorio
19 rubros × 69 comunas ≈ 1.400 URLs. Next.js las materializa con generateStaticParams. El FAQ del producto afirma schema, sitemap y las etiquetas que Google espera. La inferencia razonable es SSG o ISR sobre ese set: el recuento en vivo de negocios no puede esperar un deploy.
Rubros observados: /barberias, /peluquerias, /psicologos, más manicuristas, estética, tatuadores, dentistas, veterinarias, spas y masajes. URLs rubro × comuna en Title Case (/barberias/Santiago, /barberias/Providencia). Ñuñoa → Nunoa; Peñalolén → Penalolen.
El FAQ dice que el producto funciona en todo Chile. El directorio cubre Santiago más Viña del Mar, Concepción, Valparaíso, Temuco, Antofagasta y La Serena, y 287 comunas más a pedido. 19 × 69 es la matriz generada. No afirmo que las 287 extra ya estén materializadas.
Lo que impide el contenido vacío es la composición, no el volumen. La página de rubro tiene copy del oficio, FAQ con rangos de precio en Chile, y fichas vivas con servicios y precios reales. La de comuna tiene intro geográfica distinta —Santiago Centro nombra Plaza de Armas, La Moneda, Metro, tráfico diurno de trabajadores y estudiantes—, tenants filtrados, y FAQ con recuento en vivo (“Actualmente hay 1 barbería en Santiago Centro”). Boilerplate compartido y bloques únicos, a la vez.
Una comuna vacía sigue necesitando página útil: contexto, cómo reservar, FAQ. Recuento 0 es un dato. “No hay resultados” es contenido vacío.
Recordatorios
El correo es automático: confirmación al reservar, 24 h antes, 1 h antes. El dueño recibe correo cuando entra una reserva. Cada mensaje lleva un enlace único para reagendar o anular. El slot se libera al instante.
WhatsApp sale del panel, un clic. Está en los dos planes. Web Pro no tiene tope mensual. El Estándar sí; el número no está publicado. El cliente tiene que autorizar el canal. No invento el BSP, el costo por conversación, ni qué pasa cuando Meta no entrega.
Automatizar WhatsApp el día uno habría atado el margen del plan de $12.990 a plantillas, ventanas de 24 horas y un proveedor que este texto no puede nombrar. El correo carga la confiabilidad. WhatsApp carga la conversión en Chile, donde el cliente sí abre el mensaje.
Stack y por qué
Next.js para las dos caras: el sitio del tenant y el directorio. App Router, params estáticos, metadata por URL, sitemap. Un framework de páginas es el lugar correcto para ~1.400 rutas que tienen que existir como HTML.
TypeScript en el borde entre onboarding y esquema. Si servicios, precios y horarios son el contrato mínimo, el tipo tiene que decirlo. Un JSON suelto deja publicar un tenant sin horas.
Supabase porque el tenancy es un problema de filas. Postgres, Auth y RLS en un proyecto. A este tamaño, un segundo runtime solo duplica deploys. El aislamiento se juega en políticas.
Vercel para el borde: preview por pull request, TLS, HTML cacheable. El directorio es muchas URLs estables. Los recordatorios viven detrás de ese borde; el caso describe el comportamiento, no la factura.
Decisiones técnicas
Un app y slug en el path, no subdominios por negocio. negocio.agendamelo.cl pide DNS, certificados y un onboarding más largo. /tu-negocio se publica en el acto. Web Pro conecta un dominio propio después, para quien ya lo tiene.
Páginas de directorio como composición, no como Mad Libs. Un template “Mejores [rubro] en [comuna]” por 1.400 combinaciones es contenido vacío. El FAQ de precios y las fichas vivas van en el rubro. La intro geográfica y el recuento van en la comuna. El query de tenants es el bloque que más cambia. Si devuelve cero, el resto de la página todavía tiene que servir.
Serie en el motor, no un cron que clona slots. Clonar revienta con feriados, con una hora movida y con anular una instancia. Cabecera más instancias entra en el esquema porque el landing ya promete tratamientos de 8 a 12 sesiones.
Correo automático, WhatsApp con gesto. El tope diferencia Estándar de Web Pro: pricing de infraestructura.
Perfil Gratis después del trial. Se apaga el motor y queda la URL. Google no pierde la página. El incentivo a pagar es la agenda, no la existencia del sitio. El directorio no se pudre el día 8.
Cero comisión. Integrar pagos habría sido otro producto. El SaaS cobra el software. El local cobra el oficio. El equipo (foto, especialidad) está en los dos planes; Pro vende la segunda agenda y el dominio.
Problemas que aparecieron
1.400 URLs con el mismo esqueleto se parecen demasiado. Si la única diferencia es el nombre de la comuna en el H1, la página no merece índice. El riesgo no era dejar de generarlas. Era generarlas huecas.
El onboarding de cinco minutos produce sitios flacos el día uno. Nombre, tres servicios y un horario no llenan una galería. Si el directorio solo muestra tenants “completos”, se queda sin fichas. Si muestra cualquiera, las fichas se ven pobres. Hay que decidir qué es publicable y qué es “próximamente”.
La matriz 19 × 69 no espera una barbería en cada celda. Una página vacía pura es contenido vacío. Una que miente un listado es peor. El recuento en vivo tiene que poder ser cero sin romper la utilidad.
Las series chocan con el calendario de slots: mover el martes de la semana 3, anular una instancia, no cruzar dos profesionales en Web Pro. El modelo de hora suelta que sirve a una barbería no sirve a una fonoaudióloga. El mismo motor atiende los dos oficios.
WhatsApp es el canal que el cliente lee y es costo variable. Automatizarlo sin proveedor ni reintentos confirmados habría sido inventar un SLA. El Perfil Gratis, además, deja páginas indexadas cuyo botón ya no reserva. Si el directorio las trata como agenda viva, el SEO trabaja contra el producto.
Cómo los resolví
- 01/Partí el directorio en bloques con distinta fuente de unicidad. Copy de rubro y FAQ de precios en la página de oficio. Intro geográfica y FAQ con recuento en la de comuna. Query viva de tenants en las dos. El boilerplate cubre navegación, CTAs y schema. No cubre el cuerpo.
- 02/Bajé el umbral de publicación al esquema mínimo. Un tenant con nombre, servicios y horarios entra al índice. Galería y reseñas mejoran la ficha; no la habilitan. “Próximamente” queda para quien aún no abre agenda.
- 03/Traté la comuna vacía como página de oficio local, no como search vacío. Recuento 0 es un dato. El primer tenant que publique en esa celda enciende la ficha sin regenerar a mano las 1.400 rutas.
- 04/Metí la serie en el esquema: cabecera de tratamiento, instancias semanales, enlace único por correo para mover o anular una instancia. El slot se libera al instante. El 24/7 y el tratamiento de 8 a 12 sesiones comparten la misma tabla de disponibilidad.
- 05/Dejé el correo en automático y WhatsApp en un clic del panel. El canal caro queda bajo gesto del dueño. El tope de WhatsApp diferencia los planes sin publicar un número que el sitio no publica.
Resultado
- Páginas indexables
- ~1.400
- Rubros × comunas
- 19×69
- Comisión por reserva
- 0%
- Prueba sin tarjeta
- 7 días
El producto está en producción. Estándar: $12.990 CLP al mes, o $64.000 al año —doce meses por el equivalente de unos cinco. Web Pro: $19.990 CLP al mes, dos profesionales, dominio propio, WhatsApp sin tope, prioridad con quien lo construyó, y lugar destacado en el directorio. Siete días gratis, sin tarjeta. Después, Perfil Gratis: la URL sigue; la agenda de pago se apaga.
Cero comisión por reserva. El cliente reserva en línea y paga en el local. No publico negocios de pago, ingresos ni tráfico: no están en las fuentes de este caso. El resultado de ingeniería es el directorio que no es la misma oración con el nombre cambiado, y un onboarding que no pide más entidades de las que caben en cinco minutos.
Evidencia
Capturas del producto en vivo, 2 de septiembre de 2026.



El producto en vivo está en agendamelo.cl.
Qué haría distinto
Publicaría el tope de WhatsApp del Estándar. Hoy Pro es “sin tope” y Estándar queda con un número invisible: difícil de soportar y de citar.
Separaría “publicado” de “reserva activa” en el directorio. El Perfil Gratis es correcto como producto; como índice mezcla tenants con motor y sin motor. Un badge y un filtro por agenda viva habrían dejado el recuento honesto.
Haría del copy geográfico un dataset de producto —hitos, Metro, tipo de tráfico— no texto suelto en cada página. Mediría no-shows con y sin correo, mismo oficio, sin inventar un porcentaje. Documentaría RLS y el proveedor de WhatsApp: hoy van como TODO porque el sitio no los nombra.