Real-time Competitive Programming Platform Built for Scale
Supporting 20,000+ concurrent users with 1,500-2,000 RPS
Documentation • Architecture • Scaling Guide • Deployment • Testing
- Overview
- Key Features
- System Architecture
- Quick Start
- Scaling Strategy
- Project Structure
- API Documentation
- Deployment Options
- Monitoring & Observability
- Load Testing
- Documentation Links
- License
Nimaora CodeBattle is a high-performance, real-time competitive programming platform designed to simulate coding competitions at scale. Built for the Juniora programming challenge, it demonstrates enterprise-grade architecture capable of handling:
| Metric | Target | Implementation |
|---|---|---|
| Concurrent Users | 20,000+ | Horizontal scaling with Kubernetes HPA |
| Requests Per Second | 1,500-2,000 RPS | Laravel Octane with Swoole |
| WebSocket Connections | 20,000+ | Laravel Reverb with sticky sessions |
| Leaderboard Updates | Real-time | Redis Sorted Sets (O(log N)) |
| Attack Notifications | < 100ms | Priority queues + WebSocket |
Nimaora is an interactive programming competition where students:
- Join a battle with a unique username (session-based authentication)
- Receive 15 randomly assigned questions from a question bank
- Solve problems to earn points
- Choose Arrows (attack) or Shields (defense) as rewards
- Attack other participants to reduce their points
- Compete for the top position on the real-time leaderboard
- Session-based login with username uniqueness
- No duplicate sessions - prevents same username from multiple devices
- Automatic session expiry with heartbeat mechanism
- Graceful reconnection support
- Random assignment - 15 questions per participant from 30+ question bank
- Three difficulty levels - Easy (10-20 pts), Medium (25-35 pts), Hard (40-55 pts)
- Single attempt only - one chance per question
- Immediate feedback - real-time scoring
- Arrows - Attack other participants
- Shields - Defend against incoming attacks
- Smart targeting - Cannot attack users with 0 points
- Instant notifications - Real-time attack alerts via WebSocket
- Real-time updates - Debounced broadcasts
- Optimized queries - Redis Sorted Sets for O(log N) operations
- Online presence - Shows active participants
- Rank tracking - Get your position instantly
- WebSocket via Laravel Reverb
- Private channels for attack notifications
- Presence channels for participant tracking
- Automatic reconnection handling
┌─────────────────────────────────────────────────────────────────────────────────┐
│ USERS │
│ (20,000+ Concurrent Connections) │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ ArvanCloud CDN + WAF │
│ [Edge Cache] [DDoS Shield] [SSL Termination] [Geo Routing] │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Traefik Load Balancer │
│ nimaora.dwin.codes → Frontend │
│ api.nimaora.dwin.codes → Backend API │
│ ws.nimaora.dwin.codes → WebSocket Server │
└─────────────────────────────────────────────────────────────────────────────────┘
│
┌───────────────────────────┼───────────────────────────┐
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ Frontend │ │ Backend API │ │ WebSocket │
│ (Next.js 15) │ │ (Laravel Octane) │ │ (Laravel Reverb) │
│ 3-30 replicas │ │ 5-50 replicas │ │ 2-20 replicas │
│ React 19 + RSC │ │ Swoole 10K conn │ │ Sticky Sessions │
└─────────────────────┘ └──────────┬──────────┘ └─────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ PostgreSQL 16 │ │ Redis 7 │ │ RabbitMQ │
│ + PgBouncer Pool │ │ Sorted Sets │ │ Priority Queues │
│ 1000 connections │ │ 4GB Memory │ │ 100K msg/sec │
│ Query Indexing │ │ Master-Replica │ │ HA with Mirroring │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
For detailed architecture documentation, see SYSTEM_ARCHITECTURE.md.
- Docker 24.0+ and Docker Compose v2.20+
- Node.js 22+ (for local development)
- PHP 8.3+ with Composer (for local development)
- 8GB RAM minimum (16GB recommended for full stack)
# Clone the repository
git clone https://git.dwin.codes/nimaora/nimaora.git
cd nimaora
# Copy environment configuration
cp .env.example .env
# Generate secure passwords (edit .env with your values)
openssl rand -base64 32 # Use for APP_KEY, DB_PASSWORD, etc.
# Start all services
docker compose up -d
# Wait for services to be healthy
docker compose ps
# Run database migrations and seed data
docker compose exec backend php artisan migrate --seed
# Access the application
open http://localhost:3000# Backend Setup
cd nimaora-backend
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan serve --host=0.0.0.0 --port=8000
# WebSocket Server (new terminal)
php artisan reverb:start --host=0.0.0.0 --port=8080
# Frontend Setup (new terminal)
cd nimaora-frontend
npm install
cp .env.example .env.local
npm run dev| Service | URL | Credentials |
|---|---|---|
| Frontend | http://localhost:3000 | - |
| API | http://localhost:8000/api | - |
| WebSocket | ws://localhost:8080 | - |
| Grafana | http://localhost:3001 | admin/nimaora |
| RabbitMQ | http://localhost:15672 | nimaora/secret |
| pgAdmin | http://localhost:5050 | admin@nimaora.dwin.codes |
# Horizontal Pod Autoscaler Configuration
Backend HPA:
minReplicas: 10
maxReplicas: 100
metrics:
- cpu: 60% threshold
- memory: 70% threshold
- custom: http_requests_per_second > 150
scaleUp: 200% in 15 seconds (aggressive)
scaleDown: 10% in 60 seconds (conservative)| Component | Technology | Capacity |
|---|---|---|
| API Server | Laravel Octane + Swoole | 10,000+ conn/pod |
| Connection Pool | Persistent connections | Reduced overhead |
| Coroutines | Swoole async I/O | Non-blocking operations |
| Cache | In-memory state | Faster responses |
-- Leaderboard Query (Indexed for Performance)
SELECT username, points, shields, arrows
FROM battle_participants
WHERE battle_id = ?
ORDER BY points DESC
LIMIT 100;
-- Index: (battle_id, points DESC)PgBouncer Connection Pooling:
- Max 10,000 client connections
- Transaction-level pooling
- 100 default pool size
// Redis Sorted Set Operations
ZADD battle:{id}:leaderboard {score} {username} // O(log N)
ZREVRANGE battle:{id}:leaderboard 0 99 // O(log N + M)
ZREVRANK battle:{id}:leaderboard {username} // O(log N)Queue Priority (Highest to Lowest):
├── attacks (Priority -5) ← Real-time combat
├── broadcast (Priority -3) ← WebSocket events
├── leaderboard (Priority 0) ← Rankings update
├── default (Priority 0) ← General jobs
└── notifications (Priority +5) ← User alerts
For detailed scaling documentation, see docs/SCALING_ARCHITECTURE.md.
nimaora-codebattle/
├── nimaora-backend/ # Laravel 12 Backend
│ ├── app/
│ │ ├── Contracts/ # Repository interfaces
│ │ ├── DTOs/ # Data transfer objects
│ │ ├── Events/ # WebSocket events
│ │ │ ├── AttackReceived.php
│ │ │ ├── LeaderboardUpdated.php
│ │ │ └── ParticipantUpdated.php
│ │ ├── Http/Controllers/Api/ # API controllers
│ │ ├── Jobs/ # Queue jobs
│ │ │ ├── ProcessAttack.php
│ │ │ └── BroadcastLeaderboardUpdate.php
│ │ ├── Models/ # Eloquent models
│ │ ├── Repositories/ # Data access layer
│ │ └── Services/ # Business logic
│ │ ├── BattleService.php
│ │ └── Cache/LeaderboardCache.php
│ └── database/
│ ├── migrations/ # Database schema
│ └── seeders/ # Test data (2 battles, 30 questions)
│
├── nimaora-frontend/ # Next.js 15 Frontend
│ └── src/
│ ├── app/ # App Router pages
│ │ └── battle/page.tsx # Main battle interface
│ ├── components/ # React components
│ │ └── battle/ # Battle-specific components
│ ├── hooks/ # Custom hooks
│ │ └── useRealtime.ts # WebSocket hooks
│ ├── lib/ # Utilities
│ │ └── echo.ts # Laravel Echo client
│ └── store/ # Zustand state management
│
├── nimaora-infrastructure/ # DevOps & Infrastructure
│ ├── ansible/ # Server configuration
│ │ ├── playbooks/
│ │ └── roles/
│ ├── docker/ # Docker configurations
│ │ ├── backend-unified.Dockerfile # Multi-mode backend image
│ │ └── frontend.Dockerfile
│ ├── kubernetes/ # K8s manifests
│ │ ├── base/ # Base configurations
│ │ └── overlays/ # Environment overlays
│ ├── terraform/ # Infrastructure as Code
│ │ ├── arvancloud/ # ArvanCloud deployment
│ │ └── aws/ # AWS deployment
│ ├── load-tests/ # k6 load testing
│ └── monitoring/ # Prometheus, Grafana, Loki
│
├── docs/ # Documentation
│ ├── SCALING_ARCHITECTURE.md # Scaling deep dive
│ ├── DEPLOYMENT_GUIDE.md # Deployment instructions
│ ├── API_DOCUMENTATION.md # API reference
│ ├── DEVELOPMENT_SETUP.md # Developer guide
│ └── TESTING_GUIDE.md # Testing instructions
│
├── docker-compose.yml # Local development stack
├── DOCUMENTATION.md # Technical documentation
├── SYSTEM_ARCHITECTURE.md # Architecture overview
└── README.md # This file
| Method | Endpoint | Description | Rate Limit |
|---|---|---|---|
POST |
/api/battles/{id}/join |
Join a battle | 10/min |
POST |
/api/battles/{id}/leave |
Leave a battle | 10/min |
GET |
/api/battles/{id}/leaderboard |
Get leaderboard | 60/min |
GET |
/api/battles/{id}/questions |
Get assigned questions | 30/min |
POST |
/api/battles/{id}/questions/{qid}/submit |
Submit answer | 30/min |
POST |
/api/battles/{id}/reward |
Select arrow/shield | 30/min |
POST |
/api/battles/{id}/attack |
Attack participant | 20/min |
POST |
/api/battles/{id}/heartbeat |
Keep session alive | 60/min |
| Event | Channel | Direction | Description |
|---|---|---|---|
attack.received |
private-participant.{id} |
Server → Client | Attack notification |
leaderboard.updated |
battle.{id} |
Server → Client | Leaderboard change |
participant.updated |
battle.{id} |
Server → Client | Stats update |
For complete API documentation, see docs/API_DOCUMENTATION.md.
docker compose up -dkubectl apply -k nimaora-infrastructure/kubernetes/overlays/productioncd nimaora-infrastructure/terraform/arvancloud
terraform init && terraform apply
cd nimaora-infrastructure/ansible
ansible-playbook -i inventories/production/hosts.ini playbooks/site.ymlFor complete deployment instructions, see docs/DEPLOYMENT_GUIDE.md.
| Tool | Purpose | URL |
|---|---|---|
| Grafana | Metrics visualization | grafana.nimaora.dwin.codes |
| Prometheus | Metrics collection | prometheus.nimaora.dwin.codes |
| Loki | Log aggregation | Via Grafana |
| Laravel Pulse | Application monitoring | pulse.nimaora.dwin.codes |
| Laravel Horizon | Queue monitoring | horizon.nimaora.dwin.codes |
Performance Targets:
- HTTP P95 Latency: < 500ms
- HTTP P99 Latency: < 1000ms
- Error Rate: < 1%
- Leaderboard Update: < 200ms
- Attack Notification: < 100ms
- WebSocket Connections: 20,000+
- RPS: 1,500-2,000| Alert | Threshold | Severity |
|---|---|---|
| High Request Rate | > 2000 RPS | Warning |
| Backend Latency | P95 > 500ms | Critical |
| Queue Depth | > 10,000 messages | Warning |
| Database Connections | > 800 | Critical |
| Container OOM | Any event | Critical |
We use k6 for comprehensive load testing. See nimaora-infrastructure/load-tests/README.md for full documentation.
# Install k6
brew install k6 # macOS
# or
sudo apt-get install k6 # Ubuntu
# Run smoke test
cd nimaora-infrastructure/load-tests
k6 run -e TEST_PROFILE=smoke k6-load-test.js
# Run load test
k6 run -e TEST_PROFILE=load k6-load-test.js
# Run stress test (50K RPS target)
k6 run -e TEST_PROFILE=stress k6-load-test.js| Profile | VUs | Duration | Purpose |
|---|---|---|---|
smoke |
10 | 1 min | Quick validation |
load |
0→10,000 | 37 min | Normal load |
stress |
500→50,000 RPS | 45 min | Find limits |
spike |
1,000→50,000 | 8 min | Test autoscaling |
massive |
100,000 RPS | 60 min | Massive scale |
| Document | Description |
|---|---|
| Technical Documentation | Complete technical details |
| System Architecture | Architecture diagrams |
| Scaling Architecture | Deep dive into scaling |
| Deployment Guide | Full deployment instructions |
| API Documentation | API reference |
| Development Setup | Developer guide |
| Testing Guide | Testing instructions |
| Load Testing | k6 load testing guide |
| Backend Documentation | Backend specifics |
| Frontend Documentation | Frontend specifics |
- Framework: Laravel 12 (PHP 8.3)
- Server: Laravel Octane + Swoole
- Database: PostgreSQL 16
- Cache: Redis 7
- Queue: RabbitMQ 3.13
- WebSocket: Laravel Reverb
- Monitoring: Laravel Horizon, Pulse
- Framework: Next.js 15
- Runtime: React 19
- Language: TypeScript 5.6
- State: Zustand
- Styling: Tailwind CSS
- Real-time: Laravel Echo
- Containers: Docker
- Orchestration: Kubernetes
- IaC: Terraform, Ansible
- Load Balancer: Traefik
- Monitoring: Prometheus, Grafana, Loki
MIT License - See LICENSE file for details.
Built for Performance | Designed for Scale | Made for Competition
Made with love by dwin.codes - dwin.life - dwingh.me















