🏗️ Architecture • 💻 Tech Stack • ⚙️ Setup
A real-time multiplayer game where players challenge each other using Pokémon in a "Top Trumps" showdown.
Full-stack TypeScript • Stateful sessions • 100+ unit tests • CI/CD pipeline
This is a portfolio project designed to showcase my abilites as a full stack developer.
- Full-stack TypeScript, WebSocket architecture, stateful sessions, 100+ unit tests with CI/CD pipeline.
- Stateful Session Management: UUID-based client identification enables automatic reconnection with full state restoration, supporting mid-game disconnections without data loss.
- Headless Bot API: RESTful endpoint spawns autonomous opponents, connecting to the server socket interface as regular clients.
- Monorepo Architecture: npm workspaces manage shared TypeScript type aliases, constants, and validation logic across client/server, eliminating API contract bugs.
Design Patterns:
- Mediator Pattern: Central
Orchestratorclass coordinates between services - Observer Pattern: Event-driven state propagation via Node.js EventEmitter
- Command Pattern: Game actions encapsulated as command objects processed by the core
Gamemodel
SOLID Principles:
- Single Responsibility: Each class has one clearly defined purpose
- Dependency Injection: Pure DI of services via constructor injection
- Interface Segregation: Clients depend only on methods they use
Key Features:
- Stateful room and session lifecycle management
- RESTful bot API for headless opponents
- Graceful handling of disconnects/reconnects
- Robust defensive programming checks and guards
Testing: 58+ unit and integration tests covering game logic, managers, and full workflows
Core Patterns:
- Custom Hooks for Business Logic: Separation of concerns via hooks like
useBattleLogicanduseBattleSequence, keeping components purely presentational - Context-Based State Management: Centralized WebSocket state via custom
useSocketContexthook, eliminating prop drilling - SCSS Modules: Scoped styling prevents collisions in a component-heavy UI
Key Features:
- Persistent sessions via localStorage UUID
- Real-time state synchronization across all clients via WebSocket events
- Optimistic UI updates with server-side validation and conflict resolution
- Component-driven architecture with custom hooks for clean separation of concerns
Testing: 27+ component and hook tests using Vitest + React Testing Library
#### Notes
-
Error Handling: The above diagram shows the Happy Path only. At multiple points (client validation, room validation, game logic), errors can occur. The system follows a consistent pattern: log the error, emit an error event to the client, and halt processing. The client displays the error to the user.
-
State Synchronization: After any state change, all clients in the room receive personalized updated
ViewRoomdata via theUPDATEevent, ensuring UI consistency.
This project was built over 2 months with 250+ commits and 30+ feature branches, showcasing:
- Feature branch workflow with descriptive commit messages
- Planning and tracking of tasks through detailed Issues
- Continuous refactoring based on learnings
- JavaScript to TypeScript, CSS to SCSS migrations
What started as a sandbox weekend project evolved into a production-ready multiplayer game with comprehensive testing, CI/CD, and scalable architecture.
Prerequisites:
- Node.js v20+ (or v18+)
- npm (comes with Node.js)
Quick Start:
# Clone and install
git clone https://github.com/leontutu/PokeMatch
cd PokeMatch
npm install
# Run tests (optional)
npm run test
# Start server (terminal 1)
npm run dev:server
# Start client (terminal 2)
npm run dev:client
# In your browser
Open: http://localhost:5173
Simulate 2nd player: Use a different browser or private window


