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/rooms en 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.

Stack técnico

Next.js 14 (App Router) React 18 TypeScript (strict) Zustand Fastify WebSockets (@fastify/websocket) Zod npm workspaces Docker / Docker Compose nginx / Traefik Blue/green deploy i18n (EN/ES) CSS Modules