La sala y la cocina, en el mismo pase.
Carta QR, comandas, pase de cocina, seguimiento del cliente e impresión térmica
en una sola herramienta para restaurantes, bares y hoteles.
MVP funcional · PostgreSQL local con RLS · sin dependencias cloud para arrancar
En muchos bares la comanda sigue siendo un papel que corre de la mesa a la cocina. Pase lleva ese recorrido a una pantalla compartida: el cliente consulta la carta desde el QR de su mesa, sala registra la comanda, cocina trabaja por estaciones y el cliente sigue el estado de sus platos sin preguntar.
No es un TPV completo ni un sustituto del criterio del equipo. Es la capa que conecta sala, cocina y cliente con información actualizada en tiempo real.
Qué cambia: menos desplazamientos, menos tickets perdidos y una estimación de tiempo que se explica sola: capacidad de cada estación, cola real y platos ya en marcha.
La idea · Qué incluye · Capturas · Cómo funciona · Arranque · Pruebas · Arquitectura
| Módulo | Qué hace |
|---|---|
| Carta digital | Carta pública por restaurante y mesa, con precios, alérgenos, disponibilidad y fotografías. Sin instalar nada. |
| Sala | Mapa de mesas, apertura de servicio, comandas con notas, cuentas y seguimiento de lo que falta por salir. |
| Pase de cocina | Una pantalla por estación, ordenada por antigüedad. Empezar, listo, incidencia, entrega y reimpresión. |
| Seguimiento | El cliente abre un enlace privado y ve el estado de su comanda y un intervalo de tiempo estimado. |
| Administración | CRUD de carta, mesas, QR, estaciones, impresoras, equipo, estadísticas y auditoría. |
| Plataforma | Alta de restaurantes, suspensión y gestión de suscripciones desde un panel de superadmin. |
| Impresión | Cola persistente y agente local para impresoras térmicas ESC/POS por red o USB. |
flowchart LR
Q["Cliente<br/>QR de mesa"] -->|carta y seguimiento| N["Next.js 15<br/>App Router"]
S["Equipo<br/>sala y cocina"] -->|comandas| N
N -->|SQL con RLS| DB[("PostgreSQL 16")]
DB -->|LISTEN / NOTIFY| N
N -.->|SSE| S
N -.->|SSE| Q
A["Agente de impresión"] -->|reclama trabajos| DB
A -->|ESC/POS| P["Impresora térmica"]
P -.->|confirma| A
classDef app fill:#1E211C,color:#F5F2EA,stroke:none;
classDef data fill:#3E4A33,color:#F5F2EA,stroke:none;
classDef edge fill:#A24A2B,color:#F5F2EA,stroke:none;
class N app;
class DB data;
class A edge;
- Una sola base de datos, varias capas de acceso. Las consultas de staff fijan
app.user_iden la transacción; PostgreSQL aplica RLS por restaurante. La carta y el seguimiento pasan por funcionesSECURITY DEFINERmínimas. - Tiempo real sin WebSocket.
LISTEN/NOTIFYalimenta dos flujos SSE: uno para el personal y otro por token de seguimiento. - Impresión desacoplada. La aplicación solo encola; el agente reclama trabajos, imprime y confirma. Si la impresora falla, hay reintentos con espera creciente.
- Idempotencia de verdad. Las comandas y sus líneas llevan claves de idempotencia para que un doble envío no duplique platos ni tickets.
Requisitos: Node.js 20.11+, Docker con Compose y Chromium para las pruebas E2E.
# Clona el repositorio y entra en la carpeta
cp .env.example .env.local
npm install
npm run db:up
npm run db:migrate
npm run db:seed
npm run devLa aplicación queda en http://localhost:3010. PostgreSQL se publica solo en 127.0.0.1:5435.
Si tu usuario no está en el grupo
docker, ejecuta los comandos de Compose consg docker -c "...".
Contraseña común: PaseDemo2026!
| Correo | Rol | Restaurante |
|---|---|---|
owner@casa-aurelio.es |
Propietario | Casa Aurelio |
encargada@casa-aurelio.es |
Encargada | Casa Aurelio |
sala@casa-aurelio.es |
Sala | Casa Aurelio |
cocina@casa-aurelio.es |
Cocina | Casa Aurelio |
owner@lachispa.es |
Propietario | La Chispa |
admin@pase.app |
Superadmin | Plataforma |
Rutas principales
| Ruta | Uso |
|---|---|
/carta/<slug>?mesa=<token> |
Carta pública de la mesa |
/seguimiento/<token> |
Seguimiento privado de una comanda |
/admin |
Resumen del servicio |
/admin/carta |
Categorías, platos, precios y alérgenos |
/admin/mesas |
Mesas, zonas y QR en SVG/PNG |
/admin/estaciones |
Partidas de cocina y capacidad |
/admin/impresion |
Impresoras, agentes y cola de trabajos |
/admin/estadisticas |
Actividad y tiempos reales |
/admin/auditoria |
Registro de acciones |
/admin/equipo |
Altas, roles y bajas del personal |
/plataforma |
Alta y suspensión de restaurantes |
/sala, /sala/mesa/<id> |
Mapa de mesas y comandas |
/cocina |
Pase de cocina por estación |
/sala/cuentas |
Solicitudes de cuenta |
El navegador nunca habla directamente con la impresora. La cola vive en PostgreSQL y un agente local reclama trabajos con un token propio; así la impresora puede quedarse en la red del restaurante sin abrir puertos a internet.
# Un solo ciclo, útil para probar
npm run print:agent -- --token pase_dev_agent_casa_aurelio --once
# Agente permanente, consultando cada 3 segundos
PRINT_AGENT_TOKEN=pase_dev_agent_casa_aurelio npm run print:agent| Tipo | Comportamiento |
|---|---|
test |
Escribe un ticket de texto en agent/out/. Es el modo de las impresoras demo. |
network |
Envía ESC/POS por TCP al destino host:puerto (habitualmente 9100). |
usb_agent |
Escribe ESC/POS en la ruta del dispositivo indicada. |
Los tickets de prueba se generan desde /admin/impresion. Los tokens de agente se muestran una sola vez al crearlos; en la base de datos solo queda su hash SHA-256.
npm run typecheck # TypeScript estricto
npm test # 29 pruebas de unidad
npm run test:integration # 11 pruebas contra PostgreSQL real
npm run test:e2e # 4 recorridos de Playwright
npm run build # compilación de producciónLas pruebas cubren el estimador de tiempos, las transiciones de estado, las capacidades por rol, los precios, la API pública, RLS, el alta de personal, el agente de impresión y los flujos principales de la interfaz.
PostgreSQL local en vez de Supabase
El proyecto se ha construido para ser reproducible y verificable sin credenciales externas. La seguridad no se simula: RLS está forzada en todas las tablas de negocio y las operaciones públicas pasan por funciones SECURITY DEFINER mínimas.
La migración a Supabase consiste en reapuntar DATABASE_URL y DATABASE_APP_URL, trasladar las migraciones y sustituir la sesión propia por Supabase Auth. El esquema y las políticas ya están preparados.
Sesión propia y aislamiento por restaurante
Cookie opaca pase_session, guardada como HMAC-SHA256 en auth_sessions, con caducidad de 12 horas. El token nunca se guarda en claro.
Cada consulta de staff fija app.user_id dentro de la transacción; las políticas RLS comprueban la pertenencia. El restaurante activo se guarda en pase_restaurant y se valida contra las pertenencias.
Tiempos explicables
El estimador es puro y testeable: capacidad por estación, cola de otras mesas y tiempo restante de lo que ya está en marcha. No promete precisión: muestra un intervalo, el momento estimado y un aviso.
.
├── app/
│ ├── (public)/ # carta, login y seguimiento
│ ├── (staff)/ # sala, cocina y administración
│ ├── api/ # QR, SSE y solicitud de cuenta
│ └── plataforma/ # panel de superadmin
├── components/ # shell, staff, admin, platform, public y ui
├── features/ # dominio: orders, menu, tables, printing, staff...
├── db/
│ ├── migrations/ # esquema, RLS, API y agente
│ └── seed.sql # datos de demostración
├── agent/ # agente local de impresión
├── lib/ # db, sesión, mensajes, dinero, tiempo, SSE
├── tests/ # unit, integration y e2e
└── docs/screenshots/ # capturas de este README
Cubierto: carta, comandas, cocina, cuentas, seguimiento, estimación, QR, CRUD de carta/mesas/estaciones/equipo, impresión con agente, panel de plataforma, auditoría, estadísticas y pruebas.
Pendiente para producción: cobro online real, almacenamiento de imágenes en un servicio externo, SSE multiinstancia, autenticación de dos factores y despliegue con TLS. La impresión ESC/POS translitera acentos porque cada fabricante usa una página de códigos distinta.
Fotografías de demostración procedentes de Wikimedia Commons · créditos y licencias
Hecho con Next.js, PostgreSQL y bastante servicio de sala.






