Apps
Mecateo
POS Restaurante
Sistema POS multi-tenant. Pedidos en tiempo real, pagos, cocina (KDS), menú público y dashboard.
Stack
| Capa | Tech |
|---|---|
| Monorepo | Turborepo + PNPM workspaces |
| Backend | NestJS 11, Prisma 7, PostgreSQL 16, Socket.IO |
| Frontend | Next.js 16, React 19, TanStack Query v5, Tailwind v4 |
| Auth | Better Auth (cookie session httpOnly) |
| Realtime | Socket.IO (path /api/socket.io, namespace /ws) |
Contrato /api
Un solo contrato para todo el backend. El cliente del navegador siempre habla con el mismo origen del frontend:
| Path | Sirve |
|---|---|
/api/v1/* |
REST (orders, products, menu, ...) |
/api/auth/* |
Better Auth (login, sign-in, ...) |
/api/socket.io/* |
WebSocket handshake + polling |
/static/* |
Uploads (imágenes, PDFs) |
- Dev: Next.js rewrites
/api/*y/static/*→INTERNAL_API_URL(Nest interno). - Prod: Dokploy/Traefik rutea
/api/*y/static/*→ servicioapi, resto → servicioweb. No hay Nginx en el compose. - Server-side (RSC): un único helper
getApiBase()(enapps/web/lib/api-base.ts) elige entre/api(browser) yINTERNAL_API_URL + /api(server). Sin URLs hardcoded.
Desarrollo local
Requisitos
- Node.js ≥ 20
- PNPM ≥ 9 —
npm i -g pnpm@9 - Docker (para PostgreSQL)
Primera vez
pnpm install
cp .env.example .env # ajusta secretos si quieres
pnpm db:up # tú decides cuándo levantar la DB
pnpm --filter @repo/db db:migrate:dev # nombra la primera migración "init"
pnpm db:seedEl seed crea organización demo, usuario admin y datos de prueba.
Día a día
pnpm db:up # si la DB no está corriendo
pnpm dev # Next.js + NestJS en paralelo| Servicio | URL |
|---|---|
| Web | http://localhost:3000 |
| API (vía web) | http://localhost:3000/api/v1/health |
| API (directo) | http://localhost:3001/api/v1/health |
| Prisma Studio | pnpm db:studio → http://localhost:5555 |
El navegador siempre va por
/api(mismo origen, cookies same-origin). El acceso directo a:3001existe solo para debug.
Comandos útiles
pnpm --filter api dev # solo API
pnpm --filter web dev # solo Next
pnpm build # build de todo
pnpm start # corre el build (web + api)
pnpm check-types # tsc --noEmit en todos
pnpm lint
pnpm --filter api testProducción (Dokploy)
Arquitectura
Internet → Dokploy/Traefik (TLS, dominio)
├── /api/* → api (NestJS :3001)
├── /static/* → api (NestJS :3001)
└── /* → web (Next.js :3000)
└── SSR/RSC → http://api:3001 (red interna)
Setup
-
Crear el VPS con Dokploy. Conecta este repo de GitHub.
-
Crear Compose Application apuntando a
infra/docker-compose.prod.yml. -
Variables de entorno en Dokploy (no commiteadas):
# Conexion a tu DB externa (Dokploy service de Postgres, RDS, Supabase, etc.) DATABASE_URL=postgresql://USER:PASS@HOST:5432/DBNAME NODE_ENV=production PORT=3001 BETTER_AUTH_SECRET=<openssl rand -base64 32> BETTER_AUTH_URL=https://tudominio.com CORS_ORIGINS=https://tudominio.com UPLOADS_DIR=/var/app/uploads PUBLIC_STATIC_URL=https://tudominio.com/static LOG_LEVEL=infoEl compose no levanta Postgres. Apunta
DATABASE_URLa la DB que prefieras (otro servicio en Dokploy, RDS, Neon, Supabase, etc.). -
Configurar dominios en Dokploy (Traefik labels o UI):
webrecibe el dominio raíz/.apirecibe los path-prefixes/apiy/staticdel mismo dominio.
-
Migraciones (manual la primera vez):
docker compose -f infra/docker-compose.prod.yml --profile tools run --rm migrate docker compose -f infra/docker-compose.prod.yml --profile tools run --rm seed # opcional -
Deploys — push a
main→ Dokploy webhook → rebuild automático.
Build / start manual (sin Dokploy)
pnpm build
pnpm startO via Docker:
docker compose -f infra/docker-compose.prod.yml up -d --buildSin reverse proxy externo, el navegador necesita llegar a
weby este rewritea/api→apipor la red interna de Docker. Expón el puerto del servicioweben el host si vas a probar así.
Estructura del monorepo
restaurant-system/
├── apps/
│ ├── api/ # NestJS — modules en src/modules/
│ └── web/ # Next.js 16 App Router
├── packages/
│ ├── db/ # Prisma schema + migrations + seed
│ ├── shared/ # Zod schemas compartidos
│ ├── auth/ # Better Auth config compartida
│ ├── ui/ # shadcn/ui primitivos
│ └── typescript-config/
└── infra/
└── docker-compose.{yml,prod.yml}
Roles
| Rol | Acceso |
|---|---|
ADMIN |
Dashboard, productos, categorías, pagos, settings, pedidos |
WAITER |
Pedidos (crear/editar/entregar), cocina, cobrar |
superAdmin |
/admin global + cualquier /{slug}/... |
Solución de problemas
| Error | Causa | Solución |
|---|---|---|
ECONNREFUSED al arrancar el API |
Postgres no corre | pnpm db:up |
Llamadas XHR caen en :3001 directo |
URL hardcoded en lugar de helper | Usar getApiBase() o ruta relativa /api/... |
| WS no conecta | Path Socket.IO desincronizado | Cliente y server deben usar path: '/api/socket.io' |
Cannot find module '@prisma/client' |
Prisma client no generado | pnpm --filter @repo/db db:generate |
Invalid env |
Falta BETTER_AUTH_SECRET (32+) |
Verifica .env y BETTER_AUTH_SECRET |