Esta etapa se completó en tres relevos de trabajo. El resultado: la demo pública corre sobre el motor real, los dashboards muestran números verdaderos, el dinero cuadra al centavo, y todo está publicado y probado. Este documento explica cada cambio sin tecnicismos — y con la profundidad completa disponible para quien quiera abrirla.
El trabajo se organizó como una carrera de relevos: tres personas, tres capas. Cada quien construyó su parte, la probó a fondo, y le entregó al siguiente un documento de traspaso con todo verificado. Nadie tocó producción hasta el final.
En una frase por relevo:
La disciplina del método se nota en un solo dato: la cantidad de pruebas automáticas solo creció de relevo en relevo — 477 → 604 → 672. Nadie rompió lo del anterior.
Cada link de esta tabla abre una pieza funcionando en producción, ahora mismo, desde cualquier celular. Nada es un video ni una maqueta.
| Qué es | Link |
|---|---|
| 🏠 Central de accesos (índice de todo) | mesitademo-two.vercel.app/accesos |
| 📱 App del cliente — Mesa 12 demo pública | mesitademo-two.vercel.app/pay/demo |
| 🖥️ POS (simulador de la caja) | mesita-pos.vercel.app/index.html |
| 📊 Dashboard del dueño — Panel | …/dashboard/owner/panel |
| 📈 Dashboard — Estadísticas | …/dashboard/owner/estadisticas |
| 🪑 Dashboard — Mesas (QRs) | …/dashboard/owner/mesas |
| 🍽️ Dashboard — Menú | …/dashboard/owner/menu |
| 👥 Dashboard — Personal | …/dashboard/owner/personal |
| ↩️ Dashboard — Reembolsos | …/dashboard/owner/reembolsos |
| ⚙️ Dashboard — Configuración | …/dashboard/owner/configuracion |
| 🛡️ Admin de plataforma (super-admin) | mesitademo-two.vercel.app/admin |
| 🖨️ Póster QR de la Mesa 12 | …/pay/demo/qr |
| 📰 Bitácora pública de cambios | mesitademo-two.vercel.app/cambios |
| 💻 Código de la app | github.com/manuelmmontufarm-dev/mesita-app |
| 💻 Código del POS | github.com/manuelmmontufarm-dev/pos-mesita-demo |
mesitademo-two.vercel.app y mesita-app.vercel.app apuntan al
mismo proyecto de producción en Vercel. mesita-app.vercel.app es el
origen canónico que se imprime en los QRs físicos (configurado en la variable
NEXT_PUBLIC_APP_URL). El POS vive en su propio proyecto:
mesita-pos.vercel.app.
El objetivo de este relevo fue que el dinero y los datos sean incorruptibles, y que la conexión con el sistema de caja del restaurante quede resuelta desde el diseño.
MESITA_TABLE:<id>). Está protegido por 19 pruebas automáticas: si
alguien cambia algo que rompe el acuerdo, las pruebas fallan al instante. El simulador
del POS implementa ese contrato idéntico, así que pasar al Contífico real es solo
cambiar dos datos de configuración (la dirección y la llave de acceso) — cero
código nuevo.El objetivo: que solo las personas correctas puedan hacer las cosas correctas, y que los números que ve el dueño sean siempre verdaderos.
ADMIN_SECRET) y el
dueño/manager de cada restaurante (con login propio, limitado a su restaurante).
El rol de mesero quedó fuera de este release a propósito: cualquier intento recibe
"acceso denegado". La tabla completa de "quién puede hacer qué" está fijada con pruebas
automáticas — si un cambio futuro afloja un permiso por accidente, una prueba truena.El cambio más importante de esta etapa: lo que se prueba en la Mesa 12 ya no es una maqueta — es el producto. La demo usa exactamente el mismo motor que usarán las mesas de los restaurantes reales.
/pay/demo) funcionaba
con una memoria temporal aparte, montada solo para demostraciones. Ahora corre sobre el
mismo motor y la misma base de datos que las mesas reales: sesiones, reclamos de platos y
pagos de verdad. Las mesas de utilería 1–4 se cerraron en producción (dan 404).Una historia corta que muestra el nivel de rigor con el que se trabajó — y por qué "casi exacto" no sirve cuando se trata de dinero.
Cuando una cuenta impar se divide entre varias personas, aparece un medio centavo que no existe en el mundo real. Ejemplo: $10.01 entre dos son $5.005 cada uno — y nadie puede pagar medio centavo. Si la app redondea sin cuidado, ambos pagan $5.01 (sobra un centavo) o ambos pagan $5.00 (falta uno)… y la última persona queda atascada frente a una cuenta que dice "te falta $0.01" imposible de saldar.
Este mismo error apareció disfrazado tres veces: en el modo "Todo", en propinas que generaban medio centavo, y en el pago "por plato". Las tres variantes se reprodujeron contra el sistema real del entorno de pruebas, se corrigieron, y se verificaron en vivo. La solución no fue cosmética sino de fondo: toda la aritmética de dinero se hace ahora en centavos enteros (nunca en decimales que puedan generar fracciones), y el pago que cierra la mesa cobra exactamente el resto autorizado por el guardián de saldos. El resultado no depende de la suerte — está garantizado por construcción.
El sistema no corre en servidores propios: se apoya en servicios especializados, cada uno con un rol claro. Aquí está cada pieza y qué hace, sin tecnicismos:
Cada vez que el código cambia, Vercel construye una copia nueva de la app y la publica. Mantiene dos ambientes: los de ensayo (preview) — cada línea de trabajo recibe su propia copia con dirección propia, donde se prueba todo — y el de producción, que es lo que ven los clientes. Si algo sale mal, se regresa a la versión anterior con un clic.
Guarda cada versión que ha existido. Cada cambio queda registrado con autor, fecha y
explicación (un "commit"). Las ramas son borradores de trabajo; la rama main
es la versión oficial que alimenta producción. Nada llega a los clientes sin pasar por
este registro.
Guarda restaurantes, mesas, cuentas, comensales, reclamos de platos y pagos. Es la única fuente de verdad: si una pantalla y la base no coinciden, gana la base. La app se conecta a través de un repartidor de conexiones ("pooler"), necesario porque Vercel abre muchas conexiones pequeñas a la vez.
El código y la base de datos hablan idiomas distintos. Prisma traduce entre los dos, define la estructura de la base (qué tablas existen y qué guarda cada una) y administra las "migraciones": los cambios de estructura sin perder datos.
Se usa solo para el demo antiguo y para límites de tasa (impedir que alguien haga miles de peticiones por segundo). Nada importante vive ahí.
Si algo se rompe en producción, Sentry lo captura con todo su contexto y un ID de rastreo que conecta lo que vio el usuario con los registros del servidor. Los problemas se detectan por la alarma, no porque un cliente se queje.
El POS es el dueño de las órdenes y de la factura electrónica — eso no cambia. Hoy la app habla con un simulador que implementa el contrato idéntico al real; conectar el Contífico verdadero es cambiar dos datos de configuración.
Sigamos a un pago de principio a fin, por dentro del sistema:
clientToken único por cuenta — refrescar la página nunca crea un "comensal
fantasma".FOR UPDATE en Postgres): dos personas
tocando el mismo plato al mismo tiempo terminan con un solo dueño, siempre.Entre socios nos debemos claridad, no marketing. Esta es la fotografía honesta de hoy:
Son la configuración que cambia entre local, preview y producción sin tocar el código. Nunca se muestran sus valores reales aquí: esta tabla explica su función y si debe tratarse como secreto.
NEXT_PUBLIC_ llega al navegador y puede ser visto por
cualquiera. Las llaves, contraseñas y tokens nunca llevan ese prefijo y se guardan solo en
Vercel o en .env.local. La app y el POS son proyectos separados: cada uno tiene
su propio juego de variables.
| Variable | Para qué sirve | Tratamiento |
|---|---|---|
DATABASE_URL | Conexión de ejecución a Supabase/Postgres; en Vercel usa el pool de transacciones. | Secreta |
DIRECT_URL | Conexión directa que Prisma usa para migraciones y mantenimiento, no para tráfico normal. | Secreta |
SEED_MODE | Elige si la carga inicial crea datos demo completos o el mínimo seguro de producción. | Operativa |
NEXTAUTH_SECRET / AUTH_SECRET | Firma las sesiones de dueños y managers; rotarla obliga a volver a iniciar sesión. | Secreta |
NEXTAUTH_URL | Dirección base usada por Auth.js para callbacks de login. | Operativa |
ADMIN_SECRET | Clave maestra del super-admin para entrar a /admin y autorizar sus APIs. | Secreta |
ENCRYPTION_KEY | Cifra las credenciales de POS y pagos guardadas en la base. No se rota sin volver a guardar esas credenciales. | Secreta crítica |
PAYMENT_PROVIDER | Selecciona el motor de pagos: STUB para demo o el proveedor real habilitado. | Operativa |
OWNER_READONLY | Activa del lado servidor las restricciones de edición del panel del dueño. | Operativa |
NEXT_PUBLIC_OWNER_READONLY | Hace que la interfaz oculte o deshabilite controles de edición; debe coincidir con la regla del servidor. | Pública |
NEXT_PUBLIC_DEMO_PANEL | Indica al navegador que la experiencia demo del panel está disponible. | Pública |
ENABLE_DEV_LOGIN | Habilita el acceso automático local solo en desarrollo. Debe quedar vacío en cualquier deploy. | Solo local |
CRON_SECRET | Protege las tareas automáticas y la sincronización programada. | Secreta |
VERCEL_ENV | La define Vercel para distinguir development, preview y production; la app la usa para cerrar rutas demo. | Automática |
| Variable | Para qué sirve | Tratamiento |
|---|---|---|
NEXT_PUBLIC_APP_URL | Origen canónico que se imprime en los QR físicos. | Pública |
NEXT_PUBLIC_DEMO_PAY_URL | Link directo a la mesa de demostración. | Pública |
NEXT_PUBLIC_SUPABASE_URL | URL pública del proyecto Supabase, reservada para clientes que lo necesiten. | Pública |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Llave anónima de Supabase; solo es segura con políticas RLS correctas. | Pública controlada |
UPSTASH_REDIS_REST_URL | Dirección de Redis usada para límites de solicitudes distribuidos. | Operativa |
UPSTASH_REDIS_REST_TOKEN | Autoriza a la app a usar Redis para proteger pagos, login y APIs contra abuso. | Secreta |
RESEND_API_KEY | Permite enviar por correo los contactos recibidos desde la web. | Secreta |
CONTACT_EMAIL | Dirección interna que recibe los mensajes de contacto. | Privada |
NEXT_PUBLIC_SENTRY_DSN | Envía errores del navegador al proyecto correcto de Sentry; no concede lectura. | Pública |
SENTRY_AUTH_TOKEN | Sube mapas de código durante el build para que los errores sean legibles. | Secreta |
SENTRY_ORG | Organización de Sentry que recibe los reportes. | Operativa |
SENTRY_PROJECT | Proyecto de Sentry correspondiente a esta app y ambiente. | Operativa |
| Variable | Para qué sirve | Tratamiento |
|---|---|---|
POS_MESITA_API_URL | Dirección del POS simulador usada por la experiencia demo y sus pruebas. | Operativa |
POS_MESITA_API_KEY | Clave que permite a la app hablar con el API protegido del POS simulador. | Secreta |
CONTIFICO_BASE_URL | Cambia entre el simulador /sistema/api/v2 y Contífico real sin cambiar código. | Operativa |
CONTIFICO_API_KEY | Credencial usada por las pruebas de conexión con Contífico. | Secreta |
CONTIFICO_TABLE_FIELD | Campo del documento que guarda la identidad de mesa; por defecto adicional1. | Operativa |
CONTIFICO_ATTACH_CLIENTE | Activa experimentalmente la creación/asociación de cliente; queda apagada hasta validarla. | Bandera |
CONTIFICO_PREVIEW_BYPASS_SECRET | Permite que una preview protegida llame al simulador durante QA. | Secreta temporal |
POS_SYNC_FRESHNESS_MS | Tiempo mínimo entre consultas reales al POS; evita saturarlo cuando muchos comensales miran la mesa. | Operativa |
| Variable | Para qué sirve | Tratamiento |
|---|---|---|
DATABASE_URL | Base de datos del POS y de sus tenants. | Secreta |
NODE_ENV | Distingue pruebas, desarrollo y producción; cambia validaciones y mensajes de error. | Operativa |
PORT | Puerto local/Railway; Vercel administra el suyo automáticamente. | Operativa |
APP_BASE_URL | Dirección pública usada en callbacks y enlaces QR del POS. | Operativa |
API_KEY | Protege el API v1 del POS; debe coincidir con POS_MESITA_API_KEY de la app. | Secreta crítica |
MESITAQR_BASE_URL | Dirección del servicio MesitaQR/Paga Ya al que el POS solicita sesiones. | Operativa |
MESITAQR_API_KEY | Autoriza al POS ante ese servicio; vacía significa modo simulado. | Secreta |
MESITAQR_WEBHOOK_SECRET | Verifica que una confirmación de pago entrante sea auténtica. | Secreta crítica |
MESITAQR_QR_EXPIRY_MINUTES | Minutos de vigencia de una sesión QR pendiente. | Operativa |
CONTIFICO_ENABLED | Activa o desactiva el reenvío de documentos hacia Contífico. | Bandera |
CONTIFICO_BASE_URL | Dirección del API de Contífico usada por el POS. | Operativa |
CONTIFICO_TOKEN | Credencial del POS para enviar documentos al Contífico real. | Secreta |
PLATFORM_BOOTSTRAPPED | Evita repetir creación de esquemas/tablas en cada arranque cuando el despliegue ya está preparado. | Operativa |
RUN_PLATFORM_BOOTSTRAP | Ordena al proceso de despliegue ejecutar explícitamente la preparación inicial de plataforma. | Operativa temporal |
RESTAURANT_RUC | RUC mostrado en documentos demo del restaurante predeterminado. | Dato fiscal |
RESTAURANT_RAZON_SOCIAL | Razón social predeterminada para documentos demo. | Dato fiscal |
RESTAURANT_DIRECCION | Dirección predeterminada que aparece en el encabezado del comprobante demo. | Dato fiscal |
Nada aparece "de repente" frente a los clientes. Cada cambio recorre siempre el mismo camino, con puertas de control en cada paso:
Además, la bitácora pública de cambios
(/cambios) se actualiza sola leyendo el historial oficial del código:
cualquiera — incluidos ustedes — puede ver qué cambió y cuándo, sin pedir permiso ni saber
programar.
Se entra con el login de dueño (las credenciales demo las tiene Manuel — nunca se pegan en documentos). Qué ver: Panel = el pulso del día (ingresos, mesas activas, ticket promedio, propinas, actividad por hora). Estadísticas = ocupación y estado por mesa. Mesas = la lista con el QR imprimible de cada una (solo si está habilitado). Reembolsos = revertir un pago completo. Configuración = datos fiscales e integración con el POS.
Tip para la demo: paguen primero en la Mesa 12 desde el celular y luego abran el Panel — verán los números del día moverse con ese pago.
mesitademo-two.vercel.app/admin con la
clave de plataforma (ADMIN_SECRET; la tiene Manuel). Aquí se crean restaurantes
y mesas, y es el único lugar donde se puede apagar o prender el QR de una
mesa — con diálogo de confirmación y registro de quién y cuándo.
mesita-pos.vercel.app/index.html simula la caja del restaurante (órdenes, documentos, cobros). Sirve para demostrar el flujo completo de punta a punta: orden creada en el POS → aparece en el celular del comensal → pago en MesitaQR → el POS lo registra.
Estas son las 11 capturas que dan vida a la presentación. Cada tarjeta indica el link exacto y qué debe verse — se toman en unos 15 minutos siguiendo este orden:
Lo que falta, dicho sin rodeos: pagos reales (Diners/Datafast) y la validación contra el Contífico verdadero. Todo lo demás — motor, dashboards, seguridad, QRs, proceso de publicación — ya existe y está probado.
Siguientes pasos sugeridos: