A fully self-hostable, open source chess platform.
Play, analyze, and compete — on your own server.
See the full step-by-step walkthrough in the screenshots/ directory.
Game Play
- Real-time multiplayer via Socket.io
- Challenge friends directly
- 31 bot personalities from Amir (200) to Erfan (3200) — each with unique playstyle and behavior
- Three bot tiers: custom JS engine (200-1200), Stockfish hybrid (1300-1900), full Stockfish (2000+)
- Bot chat messages — bots talk during games based on personality and game events
- Simulated think time — bots pause before moving (beginners: 1-3s confused, grandmasters: 300ms instant)
- Bot emoji reactions — bots send 👍 ✨ 🤦 🤔 based on personality during games
- Opening preferences — custom-tier bots follow preferred openings (Bella attempts Scholar's Mate, Ahmed plays Ruy Lopez)
- Game mode presets: Challenge (no help), Friendly (hints + takebacks), Assisted (all tools), Custom
- Time controls: Bullet, Blitz, Rapid, Classical, Unlimited, or custom
- Elo rating system (K=32) with automatic updates
- Draw offers, resignation, timeout detection
- Rematch system after game ends
- Emoji reactions during live games (6 chess-themed reactions)
- Move feedback and classification during bot games
- PGN export (copy to clipboard + .pgn file download)
- Game notes (per-game annotations, auto-saved)
- Sound effects on moves, captures, check, and game events
Post-Game Analysis
- Stockfish-powered analysis (depth 18) on every position
- Move classifications: Brilliant, Great, Best, Excellent, Good, Inaccuracy, Mistake, Blunder
- Per-player accuracy percentage
- Interactive evaluation graph
- Best move arrows for mistakes
- Opening recognition (ECO codes)
Personal Stats
- Rating history chart
- Win/loss/draw record (overall, vs humans, vs bots)
- Top openings with win rates
- Accuracy tracking (average, best, worst game)
- Win/loss streaks
- 30-day activity chart
Social
- Friend system with online presence indicators
- User profiles with game statistics (wins/losses/draws)
- User search
- Activity feed showing recent games, analyses, and new friends
- Keyboard shortcuts throughout the app
Collections
- Organize games into named collections
- Add/remove games from collections
- Browse collection contents
Invite System
- Invite-only registration with invite codes
- Quota system: 10 invites per batch, 75% usage unlocks next batch
- Admin can generate invites
PWA & Offline
- Progressive Web App — installable on mobile and desktop
- Offline bot play with Stockfish WASM (same behavior as online)
- Offline games sync to server when connection resumes
- Offline fallback page when navigating without network
- Online-only features (friends, history, stats, etc.) grayed out when offline
- Smart caching: pages, WASM, sounds, fonts, images all cached for offline use
Customization
- Dark / light mode
- 6 board themes: Classic, Wood, Green, Blue, Purple, Dark
- 3 piece styles: Classic, Modern, Minimal
- Sound toggle
- Settings saved to your profile (synced across devices)
- White-label support (custom site name and URL)
API
- Versioned API (
/api/v1/) with backward-compatible redirects - Zod runtime request validation with auto-generated OpenAPI schemas
- Structured error codes (
{ code: "AUTH_INVALID_CREDENTIALS", error: "..." }) - Interactive API docs at
/docs(Swagger UI)
Admin Panel
- Rich dashboard with 17+ metrics: user/game stats, result distribution, time control popularity, bot vs human split, top bots, online count
- User management: search, activate/deactivate, verify, promote/demote, create, delete
- Game management: browse, filter by status, delete
- Bot personality editor: edit all parameters via sliders, JSON editors for messages and openings, enable/disable, create/delete bots
- Reseed from YAML: one-click reset of all bot personalities to YAML defaults
- Site settings: registration toggle, max users, email verification
- Full audit log of all admin actions
- CSRF protection on all mutations
Self-Hosting
- Single command deploy:
docker compose up - No external services or third-party APIs
- PostgreSQL with PgBouncer connection pooling (transaction mode, password from env)
- Redis with password authentication
- Nginx reverse proxy with WebSocket support
- Automatic database migrations on startup
- Database backup script with rotation
- Configurable registration (open/closed, user limits)
- Zombie game cleanup: server automatically aborts bot games stuck in ACTIVE status for >24 hours (runs every 5 minutes)
- YAML-configurable rate limiting with hot-reload (no restart needed)
- Request logging with sensitive field redaction
- Terms of Service / Privacy Policy gate (users must accept)
- Conventional commits enforced via git hooks
git clone https://github.com/amiwrpremium/eye-on-chess.git
cd eye-on-chess
cp .env.example .env
# Edit .env — at minimum, change JWT_SECRET and SEED_USER_PASSWORD
docker compose -f deployment/docker-compose.yml up -dOpen http://localhost and log in with the admin credentials from your .env.
docker compose -f deployment/docker-compose.dev.yml up --buildAll traffic goes through Nginx on http://localhost (port 80). No other ports are exposed.
Source files are volume-mounted — changes hot-reload automatically.
To populate the database with demo data (10 users, friendships, games, collections):
make seed-demo # All demo users use password: demo123456All configuration is done via environment variables in .env. See .env.example for a fully documented template.
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
REDIS_URL |
Redis connection string |
JWT_SECRET |
Secret for JWT signing. Generate with openssl rand -hex 32 |
| Variable | Default | Description |
|---|---|---|
SITE_NAME |
EyeOnChess |
Display name (white-label) |
SITE_URL |
http://localhost |
Public URL |
NEXT_PUBLIC_API_URL |
http://localhost |
Public URL (routed through Nginx) |
API_URL |
http://api:3001 |
Internal API URL (Docker network) |
NODE_ENV |
development |
Set to production for secure cookies |
| Variable | Default | Description |
|---|---|---|
REGISTRATION_OPEN |
true |
Set false to close registrations |
MAX_USERS |
0 |
Max users allowed (0 = unlimited) |
REQUIRE_EMAIL_VERIFICATION |
false |
Block unverified users from logging in |
| Variable | Default | Description |
|---|---|---|
SEED_USER_EMAIL |
admin@eyeonchess.local |
Admin email |
SEED_USER_USERNAME |
admin |
Admin username |
SEED_USER_PASSWORD |
changeme123 |
Admin password — change this! |
| Variable | Default | Description |
|---|---|---|
STOCKFISH_PATH |
stockfish |
Path to Stockfish binary |
| Variable | Default | Description |
|---|---|---|
GRAFANA_ADMIN_USER |
admin |
Grafana admin username |
GRAFANA_ADMIN_PASSWORD |
admin |
Grafana admin password |
GRAFANA_PORT |
— | Removed — use grafana.{your-domain} subdomain |
apps/web → Next.js 14 frontend — player-facing (TypeScript, Tailwind CSS)
apps/admin → Next.js 14 admin panel — separate subdomain (TypeScript, Tailwind CSS)
apps/api → Fastify backend (TypeScript, Prisma, Socket.io)
packages/chess → Shared chess types, constants, helpers
packages/ui → Shared UI components (Toast, ConfirmModal, Skeleton)
deployment/ → Dockerfiles, Docker Compose files, Nginx config
scripts/ → Backup utilities
| Service | Role |
|---|---|
| Nginx | Reverse proxy (ports 80/443), routes /api and /socket.io to API |
| Certbot | Automatic SSL via Let's Encrypt (runs once, then renews) |
| Migrate | Database migrations + seeds (init container, runs once) |
| Web | Next.js frontend (player-facing) |
| Admin | Next.js admin panel (admin.{domain} subdomain) |
| API | Fastify REST API + Socket.io for real-time |
| Worker | Stockfish analysis pipeline (polls Redis queue) |
| Postgres | Primary database (Prisma ORM) |
| PgBouncer | Connection pooler for PostgreSQL (transaction mode) |
| Redis | Presence, game clocks, analysis job queue, caching |
| Prometheus | Metrics collection (scrapes API /metrics every 15s) |
| Loki | Log aggregation |
| Promtail | Ships Docker container logs to Loki |
| Grafana | Dashboards and log viewer (via grafana.{domain} subdomain) |
| Layer | Technology |
|---|---|
| Frontend | Next.js 14 (App Router), TypeScript, Tailwind CSS, Zustand |
| Board UI | Chessground |
| Chess Logic | chess.js |
| Backend | Fastify, TypeScript, Zod |
| Database | PostgreSQL, Prisma ORM, PgBouncer |
| Real-time | Socket.io |
| Cache | Redis |
| Analysis | Stockfish 15 |
| Auth | Custom JWT (access token + httpOnly refresh cookie) |
| Observability | Grafana 11, Prometheus 3, Loki 3, Promtail 3 |
| Deployment | Docker Compose, Nginx |
# Backup
./scripts/backup.sh
# Restore
gunzip -c backups/eyeonchess_YYYYMMDD_HHMMSS.sql.gz | \
docker compose -f deployment/docker-compose.yml exec -T postgres psql -U postgres eyeonchessBackups are saved to ./backups/ with automatic rotation (keeps last 7).
Full documentation is in the docs/ directory:
- Quick Start
- Configuration Reference
- Architecture Overview
- API Reference
- Frontend Guide
- Bot Personalities
- Admin Panel
- Database Schema
- Deployment Guide
# Run all tests
pnpm test
# Run tests for a specific package
pnpm --filter api testWe welcome contributions! See CONTRIBUTING.md for:
- How to run locally
- Branch naming conventions
- PR guidelines
- Code style notes
- Stockfish — The powerful open source chess engine used for game analysis and bot play. Stockfish is licensed under the GNU General Public License v3. We are grateful to the Stockfish team and contributors for making this incredible engine freely available.
- chess.js — Chess move generation, validation, and FEN/PGN parsing.
- Chessground — The interactive chessboard UI library, originally built for Lichess.
- Lichess — Inspiration for many features and UX patterns.
This software is provided "as is", without warranty of any kind, express or implied. Use it at your own risk.
EyeOnChess is an independent open source project. It is not affiliated with, endorsed by, or associated with Lichess, Chess.com, Stockfish, or any other chess platform or organization. All trademarks and product names are the property of their respective owners.
