Dots and Boxes Online

Realtime Multiplayer Platform for playing Dots and Boxes

Gameplay image of Dots and Boxes.

Dots and Boxes

A real-time multiplayer platform for playing Dots and Boxes, featuring WebSocket-based gameplay, lobby system, and live chat. Built as a learning project to explore distributed systems architecture, event sourcing patterns, and production deployment strategies.

View on GitHub Try Live Demo

Overview

I created this project to practice implementing a distributed system with real-time communication while having something fun and testable to share with friends and family. What started as a simple game implementation evolved into a sophisticated platform showcasing modern backend architecture and full-stack development practices.

Tech Stack

Backend

Frontend

Infrastructure

Key Features

Real-Time Multiplayer

Architecture Highlights

Development Journey

This project went through significant architectural evolution. I started with a simple service oriented architecture approach and refactored to a proper Domain-Driven Design architecture with an event bus, which provided valuable experience with:

The most challenging aspects were trying to figure out the boundaries between packages. For example I was struggling figuring out how to separate my WebSocket from being coupled with everything else in the system.

What I Learned

Docker Containerization with Docker Compose Deployment

Containerized the application using Docker with Docker Compose orchestration. This eliminated environment-specific issues and made the project immediately runnable on any machine, whether my local development setup or production infrastructure. Deployment became as simple as cloning the repo and running docker compose up.

CI/CD with GitHub Actions

Every push to main triggers an automated deployment pipeline. The workflow SSHes into my Proxmox homelab VM, pulls the latest code, and rebuilds the containers with docker compose up -d --build , with zero manual steps required.

The interesting challenge here was that my homelab isn’t publicly exposed. Rather than opening an SSH port to the internet, the pipeline connects through a Cloudflare Tunnel using cloudflared as an SSH proxy command. This keeps the server completely off the public internet while still allowing GitHub Actions’ runners to reach it securely using short-lived Cloudflare Access service tokens stored as repository secrets.

Importance of Separation of Concerns

I structured the codebase around single responsibility principles, ensuring each service and function served one clear purpose. This architectural decision proved invaluable during refactoring. Changes to individual components remained isolated, allowing me to evolve the system confidently without cascading side effects.

Event Sourcing for Game Replays

I reached for event sourcing specifically to make game replays easy to implement. Rather than storing just the current game state, every action is appended to an immutable event log , so replaying a game is as simple as reading the log back from the beginning. It worked exactly as I hoped, and the implementation was surprisingly straightforward once the event schema was in place. What I didn’t anticipate was the tradeoff that comes with immutability. When a guest account is upgraded to a registered user, the historical event log still references the old guest identity, because those events were written at a point in time and don’t retroactively update. It’s a small bug but it was a good reminder that you still have to think carefully about identity changes when your event log is immutable.

Future Enhancements

I plan on adding a smarter bot that would use the minimax algorithm with alpha-beta pruning rather than if conditionals.