Documentación

Introducción

Restaurant Menu SaaS es una plataforma multi-tenant completa que permite a múltiples restaurantes gestionar todo su ciclo operativo digital: menús interactivos, gestión de pedidos en tiempo real, módulo de domiciliarios, chat en vivo, cupones, reseñas y analytics — todo desde un único sistema.

Multi-tenant

Un sistema, N restaurantes

Tiempo real

SSE para pedidos en vivo

Templates

Temas por restaurante

¿Qué es exactamente?

Cada restaurante registrado en la plataforma tiene su propio slug (ej. seven-burger) que actúa como identificador multi-tenant. El menú público es accesible en /[slug] y el panel admin en /dashboard (con sesión activa ligada al restaurantId).

La base de datos es compartida (shared DB) con discriminador por restaurantId. No hay bases de datos separadas por tenant.

Tech Stack

Next.js 14

FrameworkApp Router + Server Components

Prisma + SQLite

ORM / DBSQLite local, PostgreSQL en prod

NextAuth.js v4

AutenticaciónCredentials + JWT + Prisma adapter

Tailwind CSS

EstilosUtility-first, dark mode

Framer Motion

AnimacionesTransiciones, AnimatePresence

Lucide React

IconosIconos SVG por categoría y producto

SSE (EventSource)

Tiempo realServer-Sent Events nativos de Next.js

bcryptjs

SeguridadHash de contraseñas

Zod

ValidaciónSchemas de validación de formularios

React Hook Form

FormulariosCon resolvers de Zod

Misión y Visión

Misión

Democratizar la transformación digital de los restaurantes, poniendo en manos de cualquier negocio gastronómico — desde una pequeña hamburguesería de barrio hasta una cadena regional — las mismas herramientas de pedidos, marketing y análisis que solo las grandes franquicias podían costear.

Visión

Ser la plataforma SaaS de referencia en Latinoamérica para la gestión operativa de restaurantes, reconocida por su facilidad de uso, personalización sin límites y capacidad de escalar desde 1 hasta miles de locales sin cambiar de sistema.

Valores

Simplicidad radical

Cualquier restaurantero debe poder usar la plataforma sin capacitación técnica. Si algo es confuso, lo rediseñamos.

Velocidad operativa

Cada segundo importa en la cocina. El sistema está diseñado para reducir clics y maximizar eficiencia.

Confiabilidad

Los pedidos son el corazón del negocio. Cero pedidos perdidos, actualizaciones en tiempo real, sin fallos.

Acompañamiento real

No somos solo un software. Somos socios del negocio. Ayudamos a configurar, crecer y optimizar.

¿Para quién es esta plataforma?

🍔

Restaurantes y cafeterías

Negocios gastronómicos que quieren digitalizar su menú y gestionar pedidos sin depender de apps de terceros que cobran comisiones.

🛵

Servicios con delivery

Negocios con repartidores propios que necesitan asignar entregas, hacer seguimiento y coordinar en tiempo real.

💻

Desarrolladores y agencias

Equipos que quieren desplegar un SaaS de menú digital para sus clientes restauranteros, con personalización completa.

Precios y Membresías

La plataforma funciona bajo un modelo de suscripción mensual por restaurante. Cada restaurante elige su plan según su volumen de pedidos y las funcionalidades que necesita. No se cobra comisión por pedido — pagas una tarifa fija y todo lo que vendas es tuyo.

Planes disponibles

FREE
$0/ mes

Ideal para probar la plataforma o negocios muy pequeños con pocos pedidos.

Hasta 20 productos en el menú
Hasta 50 pedidos / mes
Menú digital con QR
1 usuario administrador
Sin módulo de domiciliarios
Sin analytics avanzado
Branding de la plataforma visible
Empezar gratis
BASIC
$29.900/ mes

Para restaurantes en crecimiento con pedidos frecuentes y un pequeño equipo de reparto.

Productos ilimitados
Pedidos ilimitados
Menú digital + QR personalizado
1 usuario administrador
Hasta 3 domiciliarios
Analytics básico (últimos 7 días)
Chat en vivo con clientes
Sin branding de la plataforma
Elegir Basic
MÁS POPULAR
PRO
$59.900/ mes

La opción más popular. Todo lo necesario para operar a pleno rendimiento.

Todo lo de Basic incluido
Domiciliarios ilimitados
Analytics completo (90 días)
Cupones y promociones
Sistema de reseñas de clientes
Push Notifications al navegador
Múltiples templates visuales
Soporte prioritario
✦ Elegir Pro
ENTERPRISE
A consultar

Para cadenas, franquicias y negocios con múltiples sucursales bajo una misma marca.

Todo lo de Pro incluido
Múltiples locales / sucursales
Dashboard centralizado multi-local
Analytics consolidado de toda la cadena
Dominio personalizado (tu-marca.com)
Integraciones a medida
SLA de disponibilidad garantizado
Onboarding y capacitación dedicada
Contactar ventas

Comparativa de funcionalidades

FuncionalidadFREEBASICPRO
Menú digital con QR
Pedidos ilimitados
Chat con clientes
Domiciliarios
3 máx.
Cupones de descuento
Reseñas de clientes
Analytics avanzado
Push Notifications
Templates visuales
1
1
Todos
Sin branding plataforma

¿Qué cambia en tu negocio al integrar la plataforma?

Cuando un restaurante se integra, experimenta cambios concretos en su operación diaria y en la percepción de sus clientes desde el primer día:

AntesMenú en papel o foto de WhatsApp
DespuésMenú digital interactivo con QR, iconos visuales y precios actualizados en tiempo real
AntesPedidos por llamada o mensaje de texto manual
DespuésFormulario de pedido digital con carrito, cupones, método de pago y confirmación automática
AntesGestión de entregas por WhatsApp o de palabra con el repartidor
DespuésMódulo de domiciliarios con asignación desde el dashboard y seguimiento de estado
AntesSin retroalimentación de clientes o solo en Google Maps
DespuésSistema integrado de reseñas 1–5 estrellas ligadas a cada pedido entregado
AntesSin datos de ventas o con hojas de cálculo manuales
DespuésDashboard de analytics con ventas del día, productos top, horas pico y tendencias
AntesEl administrador no sabe si llegó un pedido a menos que esté mirando el teléfono
DespuésPush notifications en el navegador y alertas en tiempo real al instante — sin importar dónde estés

Guía del Usuario

Esta sección explica cómo usar cada módulo de la plataforma desde el punto de vista del administrador del restaurante. No se requieren conocimientos técnicos.

Primeros pasos

1

Crea tu cuenta

Dirígete a /signup, ingresa el nombre de tu restaurante, elige un slug único (ej: mi-burger) y crea tu contraseña. Esto es lo único que necesitas para comenzar.

2

Configura tu restaurante

Desde Configuración, agrega tu teléfono, dirección, horarios de atención y si ofreces delivery, takeaway o servicio en mesa.

3

Crea tus categorías

Ve a Menú → Nueva categoría. Crea secciones como "Hamburguesas", "Bebidas", "Postres". Puedes elegir un ícono visual para cada una.

4

Agrega tus productos

Dentro de cada categoría, agrega tus productos con nombre, descripción, precio y un ícono representativo. Marca los más vendidos como "Popular".

5

Comparte tu menú

Desde la sección QR, descarga el código QR de tu menú y colócalo en tus mesas, en el empaque de delivery o compártelo por WhatsApp e Instagram.

Módulo: Gestionar el menú

El módulo de menú es el corazón de la plataforma. Desde aquí controlas todo lo que ven tus clientes cuando escanean el QR. Los cambios se reflejan al instante en el menú público sin necesidad de publicar ni aprobar nada.

Crear categoría: Botón "+ Nueva categoría". Dale nombre e ícono visual (Hamburguesa, Pizza, Bebida, Postre, etc.).
Crear producto: Dentro de una categoría, botón "+ Nuevo producto". Completa nombre, precio, descripción y elige un ícono. Puedes marcarlo como Popular o indicar stock disponible.
Editar / eliminar: Haz clic en cualquier producto o categoría para editar sus datos. El ícono de papelera elimina el ítem.
Ocultar temporalmente: Activa/desactiva el switch de disponibilidad en cada producto. El cliente no lo verá en el menú pero lo conservas para reactivarlo después.
Reordenar categorías: Arrastra las categorías para cambiar el orden en que aparecen en el menú del cliente.

Módulo: Gestionar pedidos

El dashboard de pedidos es el panel central de operaciones. Muestra todos los pedidos en tiempo real sin necesidad de recargar la página — suenan una alerta y aparecen automáticamente.

Nuevo pedido (azul): Aparece automáticamente con sonido y notificación. Muestra cliente, items y forma de pago. Presiona Confirmar para que el cliente sepa que lo viste.
En preparación (amarillo): El pedido está siendo preparado en cocina. El cliente puede ver este estado en su página de seguimiento.
Listo (verde): El plato está listo para recoger o para que salga a domicilio. Si es delivery, aparece el botón de asignar repartidor.
Entregado / Cancelado: Estado final del ciclo. Puedes cancelar con motivo. El historial queda guardado para los reportes de analytics.
Chat con el cliente: Cada pedido tiene un botón de chat. Envía mensajes directos al cliente, como "Tu pedido estará listo en 10 min" o "¿Aceptas sin cebolla?".

Módulo: Domiciliarios

Gestiona tu equipo de reparto desde un solo lugar. No se requiere app descargable — tus repartidores usan el navegador del celular con un enlace único.

Registrar domiciliario: Sección Domiciliarios → Nuevo. Ingresa nombre, teléfono y tipo de vehículo. El sistema genera un enlace único para ese repartidor.
Asignar pedido: Cuando un pedido está "Listo" y es tipo Delivery, aparece el botón "Asignar domiciliario". Elige uno disponible de la lista.
Vista del repartidor: El repartidor abre su enlace /delivery/[id] en el celular. Ve la dirección del cliente, el detalle del pedido y el botón para marcar como entregado.
Activar / desactivar: Puedes marcar un domiciliario como inactivo temporalmente sin eliminarlo del sistema. Útil para días libres.

Módulo: Cupones de descuento

Crea promociones y descuentos que tus clientes aplican en el checkout. Funciona como los cupones de las grandes apps de delivery, pero sin pagar comisiones a nadie.

Tipo porcentaje: Ej: código SUMMER20 → 20% de descuento en cualquier pedido mayor a $30.000.
Tipo monto fijo: Ej: código BIENVENIDO → $5.000 de descuento en el primer pedido.
Límite de usos: Define cuántas veces puede usarse el cupón en total. Deja vacío para uso ilimitado.
Fecha de expiración: El cupón se desactiva automáticamente después de la fecha que configures.
Pedido mínimo: Configura el valor mínimo del carrito para que el cupón sea válido.

Módulo: Reseñas

Las reseñas se generan automáticamente tras cada entrega. El cliente recibe el formulario en su pantalla de seguimiento sin necesidad de tener cuenta registrada.

Calificación automática: Al marcar un pedido como Entregado, la pantalla del cliente cambia a un formulario de reseña.
Estrellas 1–5: El cliente elige de 1 a 5 estrellas y puede agregar un comentario opcional.
Ver reseñas: En el módulo Reseñas del dashboard ves todas las valoraciones, puedes filtrar por estrella y leer comentarios.
Calificación promedio: El promedio se calcula y actualiza automáticamente con cada nueva reseña recibida.

Módulo: Analytics

El módulo de analytics te da visibilidad sobre el desempeño del restaurante: ventas, productos, horarios y tendencias. Todo en una sola pantalla, sin hojas de cálculo.

Resumen del día: Total de pedidos, ingresos del día, pedido promedio y comparativa con el día anterior.
Productos más vendidos: Ranking de los 5 productos con más pedidos en el período seleccionado. Útil para saber qué destacar.
Horas pico: Gráfica de barras por hora del día. Identifica cuándo necesitas más personal en cocina o más domiciliarios disponibles.
Historial por rango: Filtra por última semana, 30 días o 90 días. Útil para planificar compras, personal y promociones.

Módulo: Código QR

El QR es la puerta de entrada de los clientes al menú digital. Se genera automáticamente con el enlace único de tu restaurante desde el momento en que creas la cuenta.

QR listo de inmediato: No necesitas hacer nada extra. Ve a la sección QR del dashboard y ya está generado.
Descargar en alta resolución: Descarga el QR para imprimirlo en tus mesas, empaque de delivery, volantes o redes sociales.
Enlace directo del menú: El menú también es accesible desde una URL directa para compartir por WhatsApp o Instagram sin necesidad de QR.
Personalización incluida: El QR lleva al menú con los colores y template que hayas configurado para tu restaurante.

Módulo: Configuración del restaurante

Desde Configuración controlas todos los parámetros operativos que afectan la experiencia del cliente final.

Horarios de atención: Define días y horas. El cliente verá "Cerrado" automáticamente fuera del horario configurado.
Delivery / Takeaway: Activa o desactiva cada modalidad de pedido según tu operación del día (o temporada).
Costo de envío: Define el valor del domicilio o configura envío gratis a partir de un monto mínimo.
Colores del menú: Cambia el color principal y secundario de tu menú público para que coincida con tu identidad de marca.
Template visual: Cambia el diseño completo del menú público entre los temas disponibles: Burger, Pizza, Sushi, Default.
Notificaciones push: Activa las notificaciones del navegador para recibir alertas de nuevos pedidos aunque no estés mirando la pantalla del dashboard.
¿Necesitas ayuda con algo específico? Cada módulo tiene contexto visual en el propio dashboard. Si algo no está claro, revisa la sección técnica más abajo o contacta soporte desde el panel de administración.

Arquitectura

Multi-tenant

El multi-tenancy se implementa a nivel de aplicación, no de base de datos. Cada tabla tiene un campo restaurantId que filtra los datos. Las sesiones de NextAuth incluyen el restaurantId del usuario en el JWT, lo que permite filtrar automáticamente en cada endpoint.

typescript
// lib/restaurant-context.ts
// Patrón: siempre filtrar por restaurantId de la sesión
const session = await getServerSession(authOptions)
const { restaurantId } = session.user
const orders = await prisma.order.findMany({
where: { restaurantId }, // ← multi-tenant filter
orderBy: { createdAt: "desc" }
})

Estructura de carpetas

text
restaurant-menu-saas/
├── app/
│ ├── [domain]/ # Menú público del restaurante
│ │ ├── page.tsx # Menú por slug
│ │ └── pedido/ # Formulario de pedido
│ ├── dashboard/ # Panel admin (protegido)
│ │ ├── menu/ # Gestión de menú
│ │ ├── pedidos/ # Gestión de pedidos
│ │ ├── domiciliarios/ # Gestión de repartidores
│ │ ├── analytics/ # Métricas y reportes
│ │ ├── cupones/ # Cupones de descuento
│ │ ├── resenas/ # Reseñas de clientes
│ │ ├── templates/ # Selección de template
│ │ ├── qr/ # Generador de QR
│ │ └── configuracion/ # Config del restaurante
│ ├── admin/ # Super Admin panel
│ ├── api/ # API Routes (REST)
│ │ ├── auth/ # NextAuth handler
│ │ ├── orders/ # CRUD pedidos
│ │ ├── restaurants/ # CRUD restaurantes
│ │ ├── delivery/ # Domiciliarios
│ │ ├── chat/ # Mensajes chat
│ │ ├── coupons/ # Cupones
│ │ ├── reviews/ # Reseñas
│ │ ├── push/ # Web Push
│ │ └── sse/ # Server-Sent Events
│ ├── delivery/ # App repartidor
│ ├── login/ # Autenticación
│ ├── docs/ # Esta página
│ └── deploy/ # Guía de despliegue
├── components/ # Componentes reutilizables
├── hooks/ # Custom hooks
├── lib/ # Utilidades y config
├── prisma/ # Schema y seeds
└── public/ # Archivos estáticos

Routing con App Router

El slug del restaurante se captura con el segmento dinámico [domain]. Esto no requiere middleware de subdominios — sólo navegar a /seven-burger ya sirve el menú de ese restaurante.

typescript
// app/[domain]/page.tsx
export default async function PublicMenuPage({
params,
}: {
params: { domain: string }
}) {
const restaurant = await prisma.restaurant.findUnique({
where: { slug: params.domain },
include: { categories: true, products: true }
})
if (!restaurant) return notFound()
return <MenuClient restaurant={restaurant} />
}

Base de Datos (Prisma)

Modelos

ORM: Prisma · Proveedor: SQLite (dev) / PostgreSQL (prod) · Schema en prisma/schema.prisma
Restaurant
Tenant principal
idString (cuid)PK
nameString
slugString @uniqueIdentificador URL (ej: seven-burger)
primaryColorStringColor principal del tema
secondaryColorStringColor secundario
templateStringburger | pizza | default
lat / lngFloat?Geolocalización
isActiveBooleanPara desactivar desde super-admin
avgRatingFloatCalculado de Reviews
User
Usuarios del sistema
idString (cuid)PK
emailString @unique
passwordString?Hash bcrypt, null si OAuth
roleStringUSER | SUPER_ADMIN
restaurantIdString?FK → Restaurant (null para super admin)
Category
Categorías del menú
nameString
iconString?Nombre del ícono Lucide
orderIntPara ordenamiento
isActiveBoolean
restaurantIdStringFK multi-tenant
Product
Productos del menú
nameString
descriptionString?
priceFloat
iconString?Nombre del ícono Lucide
isPopularBooleanBadge 🔥 Popular
isAvailableBoolean
stockInt?null=ilimitado, 0=agotado
preparationTimeInt?Minutos
categoryIdStringFK → Category
restaurantIdStringFK multi-tenant
Order
Pedidos
orderNumberStringAuto-incremental por restaurante
customerNameString?
customerPhoneString
itemsString (JSON)[{id, name, price, qty}]
subtotal / tax / totalFloat
discountFloatDescuento de cupón
couponCodeString?Cupón usado
statusStringNEW|PREPARING|READY|DELIVERED|CANCELLED
typeStringTAKEAWAY|DELIVERY|DINE_IN
paymentMethodStringCASH|PSE
deliveryPersonIdString?FK → DeliveryPerson
addressString?JSON con dirección
DeliveryPerson
Repartidores
name / phoneString
vehicleStringMoto | Bicicleta | Auto | A pie
isActive / isAvailableBoolean
restaurantIdStringFK multi-tenant
Subscription
Suscripciones de restaurantes
planStringFREE|BASIC|PRO|ENTERPRISE
statusStringTRIAL|ACTIVE|SUSPENDED|EXPIRED
endDateDateTimePróximo cobro
monthlyPriceFloat
notified7d / notified1dBooleanControl de emails de aviso
Coupon
Cupones de descuento
codeStringÚnico por restaurante
typeStringPERCENTAGE | FIXED
valueFloat% o monto fijo
minOrderFloatPedido mínimo para aplicar
maxUsesInt?null = ilimitado
expiresAtDateTime?
Review
Reseñas de pedidos
orderIdString @unique1 reseña por orden
ratingInt1–5 estrellas
commentString?
customerName / phoneString
ChatMessage
Chat por pedido
orderIdStringFK → Order
senderStringCUSTOMER | RESTAURANT
senderNameString
messageString
isReadBoolean

Diagrama de relaciones

text
Restaurant (1) ──┬── (*) User
├── (*) Category ── (*) Product
├── (*) Order ──── (*) ChatMessage
│ └─── (1?) DeliveryPerson
├── (*) DeliveryPerson
├── (*) Coupon
├── (*) Review
├── (1?) RestaurantConfig
├── (1?) Subscription
└── (1?) OrderCounter

Autenticación

Implementada con NextAuth.js v4 usando el provider CredentialsProvider y el adapter de Prisma. Las contraseñas se hashean con bcryptjs.

Sistema de roles

SUPER_ADMIN

Acceso total a todos los restaurantes. Gestiona suscripciones, activa/desactiva tenants y ve estadísticas globales. Panel en /admin.

USER

Admin del restaurante. Gestiona su menú, pedidos, domiciliarios, cupones, reseñas y configuración. Panel en /dashboard.

Sesión y JWT

typescript
// lib/auth.ts — callbacks
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id
token.role = user.role
token.restaurantId = user.restaurantId
}
return token
},
async session({ session, token }) {
session.user.id = token.id
session.user.role = token.role
session.user.restaurantId = token.restaurantId
return session
}
}
Las rutas del dashboard están protegidas por el layout app/dashboard/layout.tsx que redirige a /login si no hay sesión activa.

API Reference

Todas las rutas de dashboard requieren sesión autenticada (getServerSession). Las rutas públicas (/api/public/*) no requieren autenticación.

Pedidos

/api/orders
GET
/api/orders

Lista pedidos del restaurante en sesión (paginado)

Sesión
POST
/api/orders

Crear nuevo pedido (desde menú público)

GET
/api/orders/[id]

Obtener detalle del pedido

Sesión
PATCH
/api/orders/[id]

Actualizar estado del pedido o datos

Sesión
DELETE
/api/orders/[id]

Cancelar / eliminar pedido

Sesión

Menú público

/api/public
GET
/api/public/[slug]

Info del restaurante por slug (nombre, colores, template)

GET
/api/public/[slug]/menu

Categorías y productos disponibles

POST
/api/coupons/validate

Validar y aplicar cupón

POST
/api/reviews

Enviar reseña del pedido

GET
/api/customer/orders

Historial de pedidos del cliente por teléfono

Dashboard

/api/dashboard
GET
/api/dashboard/stats

Estadísticas del día (total, pendientes, ingresos, pedidos/hora)

Sesión
GET
/api/analytics/[range]

Análisis histórico: ventas, productos top, horas pico

Sesión
GET
/api/restaurants/[id]/config

Configuración completa del restaurante

Sesión
PUT
/api/restaurants/[id]/config

Actualizar configuración (horarios, delivery, WhatsApp)

Sesión
GET
/api/restaurants/[id]/categories

Lista categorías del restaurante

Sesión
POST
/api/restaurants/[id]/categories

Crear categoría

Sesión
GET
/api/restaurants/[id]/products

Lista productos

Sesión
POST
/api/restaurants/[id]/products

Crear producto

Sesión
PATCH
/api/restaurants/[id]/products/[pid]

Editar producto (precio, stock, disponibilidad)

Sesión
DELETE
/api/restaurants/[id]/products/[pid]

Eliminar producto

Sesión

Domiciliarios

/api/delivery
GET
/api/delivery

Lista domiciliarios del restaurante

Sesión
POST
/api/delivery

Registrar nuevo domiciliario

Sesión
PATCH
/api/delivery/[id]

Actualizar datos o estado del domiciliario

Sesión
DELETE
/api/delivery/[id]

Eliminar domiciliario

Sesión
POST
/api/orders/[id]/assign

Asignar domiciliario a un pedido

Sesión

Dashboard Admin

Funcionalidades

Pedidos en tiempo real

Vista Kanban con SSE. Los pedidos aparecen sin refrescar.

Gestión de menú

CRUD completo de categorías y productos con íconos Lucide.

Domiciliarios

Registro, asignación de pedidos y seguimiento de estado.

Cupones

Crear cupones de porcentaje o monto fijo con expiración.

Reseñas

Listado de valoraciones con filtro por estrella.

Chat en vivo

Mensajes bidireccionales por pedido vía SSE.

Analytics

Ventas, productos top, horas pico, resumen semanal.

QR del menú

Generación y descarga del QR del menú público.

Templates

Selección del tema visual del restaurante.

Push Notifications

Suscripción web push para nuevos pedidos.

Rutas del dashboard

/dashboardResumen y pedidos activos en tiempo real
/dashboard/pedidosHistorial completo de pedidos con búsqueda
/dashboard/menuGestión de categorías y productos
/dashboard/domiciliariosCRUD de repartidores
/dashboard/analyticsMétricas y gráficas de ventas
/dashboard/cuponesGestión de cupones de descuento
/dashboard/resenasReseñas recibidas de clientes
/dashboard/templatesCambiar el tema visual del menú público
/dashboard/qrGenerar QR del menú
/dashboard/configuracionHorarios, delivery fee, WhatsApp, impresora

Menú Público

El menú público es la cara del restaurante hacia los clientes. Es un Server Component que carga el restaurante y su menú en el servidor, y entrega un Client Component interactivo para el carrito y los pedidos.

Carrito de compras

Estado global con Zustand (useCartStore). Persistido en localStorage.

Filtro por categorías

Pills animadas para filtrar productos por categoría.

Búsqueda de productos

Filtro en tiempo real por nombre.

Cupón de descuento

Campo para aplicar cupón antes del checkout.

Validación de cupón

API call a /api/coupons/validate con el código y total.

Pedido completo

Formulario con nombre, teléfono, dirección y método de pago.

Seguimiento

Página /track/[phone] para ver el estado del pedido.

Chat con restaurante

Chat en vivo con el restaurante desde el pedido activo.

Reseña post-entrega

Formulario de valoración 1-5 estrellas al recibir el pedido.

Template dinámico

El diseño cambia según el template configurado (burger, pizza…).

Tiempo Real con SSE

En lugar de WebSockets (que requieren servidor persistente), el proyecto usa Server-Sent Events (SSE) nativos de Next.js. Esto es compatible con Vercel Edge, Railway y cualquier plataforma serverless.

typescript
// app/api/sse/route.ts — Servidor
export async function GET(req: Request) {
const encoder = new TextEncoder()
const stream = new ReadableStream({
start(controller) {
// Registrar cliente en el store
const id = sseStore.addClient(restaurantId, controller)
req.signal.addEventListener("abort", () => {
sseStore.removeClient(restaurantId, id)
})
}
})
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
})
}
// lib/sse-store.ts — Emitir evento
sseStore.emit(restaurantId, {
type: "NEW_ORDER",
payload: order
})
typescript
// hooks/useSSE.ts — Cliente
export function useSSE(restaurantId: string) {
useEffect(() => {
const es = new EventSource(`/api/sse?restaurantId=${restaurantId}`)
es.onmessage = (e) => {
const { type, payload } = JSON.parse(e.data)
if (type === "NEW_ORDER") {
addOrder(payload) // Zustand store
playSound() // Sonido de alerta
showToast(payload) // Toast notification
}
}
return () => es.close()
}, [restaurantId])
}
Los eventos SSE se emiten al crear/actualizar pedidos y al enviar mensajes de chat. El dashboard del restaurant y la app de delivery reciben actualizaciones en tiempo real sin polling.

Sistema de Templates

Cada restaurante puede seleccionar un template visual desde el dashboard. El template se guarda en Restaurant.template y se aplica dinámicamente al menú público.

Default

Verde oscuro clásico

Burger

Amarillo cálido

Pizza

Rojo tomate

Sushi

Negro minimalista

typescript
// hooks/useTemplate.ts
export function useTemplate(template: string) {
return TEMPLATES[template] ?? TEMPLATES.default
}
// lib/templates.ts
export const TEMPLATES = {
default: { primaryColor: "#06C167", fontFamily: "sans-serif" },
burger: { primaryColor: "#F59E0B", fontFamily: "serif" },
pizza: { primaryColor: "#EF4444", fontFamily: "sans-serif" },
sushi: { primaryColor: "#1F2937", fontFamily: "mono" },
}

Módulo de Domiciliarios

El módulo de domiciliarios permite gestionar el ciclo completo de entrega: registrar repartidores, asignar pedidos y hacer seguimiento.

1

Registrar domiciliario

Desde /dashboard/domiciliarios: nombre, teléfono y tipo de vehículo. Queda asociado al restaurantId.

2

Pedido listo → Asignar

Cuando el pedido pasa a estado READY y es tipo DELIVERY, aparece el botón "Asignar domiciliario".

3

Vista del repartidor

El repartidor ve sus pedidos asignados en /delivery (sin login requerido, solo por enlace compartido).

4

Confirmación de entrega

El repartidor marca el pedido como entregado, actualizando el estado a DELIVERED.

Módulos Extra

Chat en vivo

Cada pedido tiene un canal de chat bidireccional entre el cliente y el restaurante. Los mensajes se entregan vía SSE en tiempo real. El modelo ChatMessage almacena cada mensaje con el campo sender (CUSTOMER|RESTAURANT).

Cupones de descuento

Los cupones pueden ser de tipo PERCENTAGE (ej: 15%) o FIXED (ej: $5000 de descuento). Soportan pedido mínimo, límite de usos y fecha de expiración. Se validan en el checkout del menú público.

Reseñas

Cuando un pedido se entrega (DELIVERED), el cliente recibe un enlace para calificar su experiencia de 1 a 5 estrellas. Las calificaciones se promedian y se actualizan en Restaurant.avgRating.

Push Notifications

Implementadas con la Web Push API. El admin puede suscribirse desde el dashboard y recibir notificaciones del navegador cuando llega un nuevo pedido, incluso con la pestaña cerrada. La suscripción se guarda en la base de datos.

typescript
// hooks/usePushNotifications.ts
const { subscribe, isSubscribed } = usePushNotifications()
// Suscribir al usuario
await subscribe() // Llama a /api/push/subscribe
// Al crear un pedido, el servidor emite:
// lib/webpush.ts
await sendPushNotification(restaurantId, {
title: "🛎️ Nuevo pedido #1042",
body: "Juan García · $45.000 · DELIVERY"
})

Suscripciones SaaS

El modelo Subscription gestiona el estado de cada restaurante: TRIAL (gratuito por tiempo limitado), ACTIVE, SUSPENDED o EXPIRED. Un cron job (/api/cron/check-subscriptions) revisa diariamente las suscripciones próximas a vencer y envía emails de aviso.

FREE
BASIC
PRO
ENTERPRISE

Custom Hooks

useSSE(restaurantId)hooks/useSSE.ts

Conecta al stream SSE del restaurante. Dispara callbacks cuando llegan nuevos pedidos o mensajes de chat.

useCurrentRestaurant()hooks/useCurrentRestaurant.ts

Lee el restaurantId de la sesión y fetch la info del restaurante actual. Útil en componentes del dashboard.

useTemplate(template)hooks/useTemplate.ts

Retorna la config de colores y fuente del template seleccionado. Usado en el menú público.

useRestaurantAuth()hooks/useRestaurantAuth.ts

Verifica sesión y redirige a /login si no está autenticado. Wrapper de useSession.

usePushNotifications()hooks/usePushNotifications.ts

Gestiona la suscripción a Web Push: subscribe, unsubscribe e isSubscribed.

Variables de Entorno

Crea el archivo .env en la raíz del proyecto. Nunca lo subas a git (está en .gitignore).
DATABASE_URLRequerida

URL de conexión a la base de datos.

# file:./prisma/dev.db ← SQLite local# postgresql://user:pass@host:5432/db ← Producción
NEXTAUTH_SECRETRequerida

Clave secreta para firmar tokens JWT. Mínimo 32 caracteres.

# openssl rand -base64 32 ← Genera una
NEXTAUTH_URLRequerida

URL base de la app (sin slash final).

# http://localhost:3000 ← Dev# https://mi-app.railway.app ← Prod
NEXT_PUBLIC_VAPID_PUBLIC_KEYOpcional

Clave pública VAPID para Web Push Notifications.

# Genera con: npx web-push generate-vapid-keys
VAPID_PRIVATE_KEYOpcional

Clave privada VAPID (server-side only).

# Del mismo comando anterior
VAPID_EMAILOpcional

Email de contacto para VAPID.

# mailto:admin@tudominio.com

Flujo Completo de Pedidos

Desde que el cliente abre el menú hasta que el repartidor confirma la entrega:

MenúCliente

Cliente accede a /[slug], navega el menú y agrega productos al carrito.

CheckoutCliente

Completa el formulario (nombre, teléfono, dirección, método de pago). Aplica cupón si tiene.

NEWSistema

POST /api/orders crea el pedido en BD y emite evento SSE al dashboard del restaurante.

PREPARINGRestaurante

El cocinero acepta y cambia el estado. Se emite nuevo SSE y el cliente ve el update en /track.

READYRestaurante

Plato listo. Si es DELIVERY, aparece el botón "Asignar domiciliario" en el dashboard.

ASSIGNEDRestaurante

Se selecciona un repartidor disponible. El pedido aparece en su app /delivery.

DELIVEREDRepartidor

El repartidor confirma la entrega. El cliente recibe el enlace para dejar reseña.

Restaurant Menu SaaS · Documentación técnica completa