Live Platform · Docs · Report Bug · Request Feature
EvalX is a full-stack, production-grade competitive programming platform engineered from the ground up — featuring real-time contest leaderboards, async code evaluation, end-to-end payment infrastructure, and a multi-tier admin ecosystem. Deployed at evalx.in.
- The Problem
- Why EvalX
- Live Demo
- Architecture
- Feature Deep-Dive
- Tech Stack
- Getting Started
- Environment Variables
- API Reference
- Deployment
- Roadmap
- Engineering Decisions & Lessons
- Contributing
- Author
The competitive programming ecosystem is dominated by platforms that are either:
- Too generic — LeetCode and Codeforces aren't tailored for college communities, internal hackathons, or custom contest formats.
- Too expensive — Hosted judge infrastructure, white-label tools, and contest APIs cost thousands per month.
- Too closed — No way to self-host, customize scoring logic, or own your community's data.
Universities, coding clubs, and bootcamps need a self-sovereign, extensible, production-grade platform they can actually run — without vendor lock-in.
EvalX is engineered with a single thesis: build the infrastructure that the competitive programming world is missing.
| Capability | EvalX | LeetCode | Codeforces |
|---|---|---|---|
| Self-hostable | ✅ | ❌ | ❌ |
| Custom contest creation | ✅ | ❌ | ✅ |
| Real-time leaderboards | ✅ | Limited | ✅ |
| Payment-gated contests | ✅ | ❌ | ❌ |
| College/community mode | ✅ (Roadmap) | ❌ | ❌ |
| Open admin ecosystem | ✅ | ❌ | ❌ |
| Zero vendor lock-in | ✅ | ❌ | ❌ |
Production URL: https://evalx.in
| Role | Credentials |
|---|---|
| Public User | Register at evalx.in |
| Demo Admin | Contact maintainer |
┌─────────────────────────────────┐
│ evalx.in (Vercel) │
│ React 18 + Vite + Redux TK │
│ Monaco Editor + Socket.io-cli │
└───────────────┬─────────────────┘
│ HTTPS / WSS
┌───────────────▼─────────────────┐
│ Express 4 API (Render) │
│ Auth · Contest · Judge · Admin │
│ Socket.io · Bull · Pino logs │
└───┬───────────┬──────────┬──────┘
│ │ │
┌───────────────▼──┐ ┌─────▼────┐ ┌──▼───────────┐
│ MongoDB Atlas │ │ Upstash │ │ Resend │
│ Primary DB │ │ Redis │ │ Email API │
│ Atlas Search │ │ Queue + │ │ OTP + Alerts │
└──────────────────┘ │ Cache │ └──────────────┘
└──────────┘
│
┌──────────▼───────────┐
│ Bull Worker Pool │
│ Code Eval Queue │
│ Async Judge Jobs │
└──────────────────────┘
User submits code
│
▼
POST /api/submissions
│
▼
Job enqueued → Bull Queue (Upstash Redis)
│
▼
Worker picks up job → runs test cases
│
▼
Result stored in MongoDB
│
▼
Socket.io emits verdict → Client updates in real-time
│
▼
Leaderboard recomputed + broadcast
- JWT dual-token flow — short-lived access tokens + long-lived refresh tokens
- HttpOnly cookie storage for refresh tokens with bcrypt-hashed DB persistence (rotation-safe)
- Email OTP verification via Resend — zero SMTP dependency
- RBAC — three-tier hierarchy:
user→admin→superadmin - HMAC webhook verification for Razorpay payment events
- Full Contest + Problem CRUD with ownership guards
- Draft-only edit protection — live contests are immutable
- Payment-gated registration with atomic idempotent transactions (no double-charge on retry)
- Real-time leaderboards over Socket.io — sub-second rank updates as submissions arrive
- Async evaluation via Bull job queues backed by Upstash Redis
- Decoupled worker architecture — horizontal scale-ready
- Submission results pushed live over WebSocket — no polling
- Structured verdict:
AC / WA / TLE / CE / REwith per-test-case breakdown
/admin— contest and problem governance for admins/superadmin— system health aggregation, audit log viewer, access-control governance, user role management- Pino structured logging — JSON in production, pretty-printed in dev, fully queryable
- Razorpay integration — order creation, payment verification, webhook processing
- Idempotent registration guard — retries don't create duplicate records
- Full audit trail per transaction
| Layer | Technology |
|---|---|
| Framework | React 18 + Vite |
| State | Redux Toolkit |
| Styling | Tailwind CSS + Custom Design Tokens |
| Code Editor | Monaco Editor (custom EvalX dark theme) |
| Realtime | Socket.io-client |
| Hosting | Vercel |
| Layer | Technology |
|---|---|
| Runtime | Node.js + Express 4 |
| Database | MongoDB Atlas + Mongoose |
| Queue | Bull + Upstash Redis |
| Cache | Upstash Redis |
| Realtime | Socket.io |
| Payments | Razorpay |
| Resend | |
| Logging | Pino |
| Hosting | Render |
- Base color:
#07090f(near-black) - Accent:
#f0a500(amber) - Display font: Barlow Condensed
- Code font: IBM Plex Mono
- Aesthetic: Industrial terminal — built for engineers, by an engineer
node >= 18.x
npm >= 9.x
MongoDB Atlas account
Upstash Redis account
Resend account
Razorpay account (for payments)# 1. Clone the repository
git clone https://github.com/yourusername/evalx.git
cd evalx
# 2. Install backend dependencies
cd server && npm install
# 3. Install frontend dependencies
cd ../client && npm install
# 4. Configure environment variables (see below)
cp server/.env.example server/.env
cp client/.env.example client/.env
# 5. Start the backend
cd server && npm run dev
# 6. Start the frontend
cd client && npm run devFrontend runs at http://localhost:5173
Backend runs at http://localhost:5000
# App
NODE_ENV=development
PORT=5000
CLIENT_URL=http://localhost:5173
# MongoDB
MONGODB_URI=mongodb+srv://<user>:<pass>@cluster.mongodb.net/evalx
# JWT
JWT_ACCESS_SECRET=your_access_secret
JWT_REFRESH_SECRET=your_refresh_secret
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d
# Redis (Upstash)
REDIS_URL=rediss://<upstash-url>
REDIS_TOKEN=your_upstash_token
# Email (Resend)
RESEND_API_KEY=re_xxxxxxxxxxxx
RESEND_FROM=noreply@evalx.in
# Payments (Razorpay)
RAZORPAY_KEY_ID=rzp_live_xxxx
RAZORPAY_KEY_SECRET=your_razorpay_secret
RAZORPAY_WEBHOOK_SECRET=your_webhook_secretVITE_API_URL=http://localhost:5000
VITE_SOCKET_URL=http://localhost:5000| Method | Endpoint | Description |
|---|---|---|
POST |
/api/auth/register |
Register with email OTP |
POST |
/api/auth/verify-otp |
Verify email OTP |
POST |
/api/auth/login |
Login → access + refresh tokens |
POST |
/api/auth/refresh |
Rotate refresh token |
POST |
/api/auth/logout |
Invalidate refresh token |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/contests |
List all public contests |
POST |
/api/contests |
Create contest (admin) |
GET |
/api/contests/:id |
Contest detail |
POST |
/api/contests/:id/register |
Register (payment flow) |
GET |
/api/contests/:id/leaderboard |
Live leaderboard |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/submissions |
Submit code → async eval |
GET |
/api/submissions/:id |
Poll submission result |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/admin/health |
System health metrics |
GET |
/api/admin/audit-logs |
Audit log viewer |
PATCH |
/api/superadmin/users/:id/role |
Promote / demote users |
Full Postman collection available on request.
# Push to main branch — Vercel auto-deploys
git push origin mainSet environment variables in Vercel dashboard under Project Settings → Environment Variables.
- Connect GitHub repo to Render
- Set Build Command:
npm install - Set Start Command:
node src/index.js - Add all environment variables from
server/.env - Ensure host binding is
0.0.0.0(required for Render port detection)
EvalX is live at evalx.in — configured via Vercel DNS with CNAME records.
Current release:
v0.2.0— Core platform complete.
- Elo Rating System — skill-based dynamic ranking
- Daily Streaks — habit loop + engagement mechanics
- College Battalion Mode — institution-vs-institution leaderboards
- Daily Puzzle — one problem, 24 hours, global ranking
- Redis Leaderboard Migration —
ZADD/ZREVRANKfor O(log n) ranking - Redis Caching Layer — hot path cache for contest/problem reads
- Socket handshake authentication
- Feature flags + maintenance mode toggle
- Superadmin surface for system toggles
- Audit coverage: auth flows + organizer actions
- Real judge integration (replacing mock judge)
- Phased monetization: premium problems, contest hosting subscriptions
- Organization accounts for colleges and bootcamps
- Public contest marketplace
This project was built zero-budget with zero shortcuts. Every architectural decision was earned through debugging in production.
| Problem Encountered | Root Cause | Fix |
|---|---|---|
| Refresh tokens silently corrupted | Synchronous bcrypt in Mongoose pre-save hook | Always async/await inside hooks |
All findById calls returning null |
Missing DB name in MongoDB URI | Include /dbname in connection string |
SMTP ECONNREFUSED on deploy |
Node.js defaulting to IPv6 binding | Explicit IPv4 binding for mail |
| Outbound email blocked on Railway | Railway free tier blocks all SMTP ports | Migrated to Resend HTTP API |
| Express 5 wildcard routes crashing | path-to-regexp v8 breaking change |
Pinned to Express 4 |
| Browser misreporting 5xx as CORS | CORS headers missing from error responses | Attach CORS headers to all responses |
| Port not detected on Render | Default localhost binding | Explicit 0.0.0.0 binding |
| Named exports silently failing | Import/export name mismatch | Verify all export names at compile time |
EvalX is open to contributions. If you're interested in competitive programming infrastructure, real-time systems, or developer tooling:
# 1. Fork the repo
# 2. Create a feature branch
git checkout -b feat/your-feature-name
# 3. Commit with conventional commits
git commit -m "feat(contests): add penalty time scoring"
# 4. Push and open a PR
git push origin feat/your-feature-nameCommit convention: type(scope): summary
Types: feat · fix · perf · refactor · docs · chore
Shashank Ranjan B.Tech (3rd Year) · Full-Stack Development
"Built this from scratch — zero team, zero budget, zero compromises on production quality."
⭐ Star this repo if EvalX impressed you — it helps more than you think.
Made with ⚡ and too much caffeine · EvalX v0.2.0 · MIT License