The Last of the Snacks
Trust no one. Season aggressively.
Producto de punta a punta: lobby, salas, servidor de juego autoritativo, mensajes validados, i18n (EN/ES) y despliegue tipo producción (nginx/Traefik, blue/green). Demuestra ownership full-stack más allá de APIs CRUD.
Resumen
Juego de cartas por turnos en el navegador con roles ocultos, para 4–8 jugadores. Cada partida vive en una sala con un bucle de juego en el servidor: configuración del lobby, temporizadores de turno, resolución de cartas, espectadores y bots opcionales. El frontend es una experiencia Next.js cuidada; el backend es un servidor autoritativo en Node para que el cliente nunca decida solo el resultado—el tipo de reparto que interesa en sistemas multijugador o tiempo real.
Arquitectura
Monorepo (npm workspaces): el paquete @last-of-snack/shared (tipos y constantes de dominio) se
compila primero y lo consumen ambas aplicaciones. El servidor de juego (Fastify + WebSocket) posee las salas y el estado en memoria. El
frontend (Next.js 14 App Router) gestiona la UI, el estado cliente (Zustand) y puede hacer proxy HTTP al servidor de juego para crear salas en desarrollo o detrás
de nginx en producción.
Flujo en tiempo real y validación
- Conexión: los clientes abren WebSocket al servidor de juego (
/ws); los mensajes cubren unirse, ajustes de lobby, chat, iniciar partida, jugar carta, reinicio, etc. - Estado autoritativo:
GameEngine, sistema de turnos, resolución de cartas y temporizadores corren en servidor; los broadcasts mantienen a todos sincronizados (incluidos espectadores). - Protocolo con esquemas: las entradas se validan con Zod antes de tocar la lógica de juego—menos abuso y contrato explícito para nuevas features o clientes móviles.
- Capa HTTP: la creación de sala puede ir por
/api/roomsen Next (proxy) o directo al servidor de juego según entorno—mismo patrón que muchos BFF en producción.
Diseño del sistema
flowchart TB
subgraph client [Browser]
UI[Next.js 14 App Router<br/>React + Zustand]
end
subgraph monorepo [npm workspaces monorepo]
SHARED["@last-of-snack/shared<br/>types, domain constants"]
FE[frontend]
GS[game-server]
SHARED --> FE
SHARED --> GS
end
UI -->|HTTP: pages, assets| FE
UI -->|HTTP: create room<br/>/api/rooms proxy| FE
FE -->|HTTP: rooms API| GS
UI -->|WebSocket /ws<br/>game messages| GS
subgraph gs_internal [game-server internals]
WS[Fastify + @fastify/websocket]
ZOD[Zod message validation]
RM[RoomManager / rooms]
GE[GameEngine, turns, timers, cards]
WS --> ZOD --> RM --> GE
end
GS --> WS Entrega y operaciones
Docker Compose levanta frontend + servidor de juego + nginx en local; en producción hay Traefik y un flujo documentado blue/green para actualizar sin cortes. Variables de entorno separan configuración pública del cliente de secretos de servidor—higiene habitual en producción.