Skip to content

Latest commit

Β 

History

50 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

⚑ CodeForge

A Full-Stack Competitive Programming Platform

Solve Problems Β· Fight in 1v1 Battles Β· Join Contests Β· Climb the Leaderboard

Live Demo Β  Backend API Β  License


React Vite Node.js Express MongoDB Redis BullMQ Socket.io Docker


πŸ“Œ What is CodeForge?

CodeForge is a competitive programming platform built from scratch β€” similar to LeetCode and Codeforces. Users can solve algorithmic problems, fight real-time 1v1 coding battles, participate in timed contests, and track their ELO rating progress over time.

The project is fully deployed and live:

⚠️ Backend is on Render's free tier β€” it may take ~20–30s to wake up on first request.


✨ Features

🧩 Problem Solving

  • Browse problems filtered by difficulty: Easy, Medium, Hard
  • Built-in C++ code editor with line numbers and tab support
  • Run Code β€” test against visible sample cases instantly (no DB save)
  • Submit β€” runs code against all hidden test cases via a background queue
  • Verdicts: Accepted, Wrong Answer, Compile Error, Runtime Error, Time Limit Exceeded
  • Full submission history with runtime and memory stats per submission

βš”οΈ 1v1 Battle Arena

  • Enter a matchmaking lobby β€” get auto-paired with another online user
  • Both players receive the same problem at the same time
  • First to get Accepted on all test cases wins the battle
  • Live opponent progress updates via WebSockets (tests passed, verdict, etc.)
  • Battle ELO rating updates automatically after every match
Player 1 ──[ Matchmaking ]──► CodeForge Server ◄──[ Matchmaking ]── Player 2
                                    β”‚
                         Creates 1v1 Battle Room
                                    β”‚
               Both solve simultaneously ──► First to AC wins!

πŸ† Contests

  • Join scheduled timed programming contests
  • Multiple problems per contest
  • Live leaderboard β€” ICPC-style scoring (problems solved + time penalty)
  • Rating gets automatically calculated by a background cron job once the contest ends

πŸ“Š Rating System

  • Two separate ratings: Contest Rating and Battle Rating
  • Both start at 1200 and change based on performance
  • Full rating history stored for each user β€” tracked over time

πŸ” Authentication & Security

  • JWT-based login/logout with Redis token blacklisting (tokens are immediately invalidated on logout)
  • Passwords hashed using bcryptjs
  • API rate limiting to prevent abuse
  • Code execution with timeout limits and memory caps

πŸ›‘οΈ Admin Panel

  • Create, edit, and delete problems
  • Add/remove test cases (visible or hidden)
  • Create and schedule contests

πŸ—οΈ How It Works β€” Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     Browser (React + Vite)       β”‚
β”‚   Hosted on Vercel (Global CDN)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚  HTTP REST + WebSocket
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             Express.js Backend (Node.js 20)              β”‚
β”‚           Running in Docker on Render Cloud              β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  REST APIs  β”‚   β”‚  Socket.io   β”‚   β”‚    BullMQ     β”‚  β”‚
β”‚  β”‚ (Auth, Sub, β”‚   β”‚  (Battles,   β”‚   β”‚  (Job Queue   β”‚  β”‚
β”‚  β”‚  Contest..) β”‚   β”‚  Matchmaking)β”‚   β”‚  for judging) β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚         β”‚                                     β”‚          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚               Judge Service                        β”‚  β”‚
β”‚  β”‚  1. Wrap user code in a complete C++ program        β”‚  β”‚
β”‚  β”‚  2. Compile with g++                               β”‚  β”‚
β”‚  β”‚  3. Run against each test case, capture output     β”‚  β”‚
β”‚  β”‚  4. Compare output vs expected β†’ give verdict      β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚                    β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚  MongoDB Atlas     β”‚   β”‚  Upstash Redis         β”‚
         β”‚  - Users           β”‚   β”‚  - BullMQ job queue    β”‚
         β”‚  - Problems        β”‚   β”‚  - Blacklisted tokens  β”‚
         β”‚  - Submissions     β”‚   β”‚  - Rate limit counters β”‚
         β”‚  - Contests        β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚  - Battles         β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βš™οΈ Code Execution Engine

This is the core of the platform. When a user submits C++ code, it can't just be run directly β€” it needs a proper main() with input reading and output printing. Here's how it works:

Step 1 β€” Code Wrapping
  User writes a Solution class β†’ system wraps it in a complete C++ program
  with input parsing (int, vector<int>, string, etc.) and a main() function

Step 2 β€” Compilation
  g++ -O1 main.cpp -o main
  If compilation fails β†’ returns Compile Error with the g++ output

Step 3 β€” Test Case Execution
  For each test case: ./main < input.txt
  5 second timeout per test case
  Captures stdout, stderr, and execution time

Step 4 β€” Verdict
  Compare actual output vs expected output (after trimming whitespace)
  β†’ Accepted / Wrong Answer / TLE / Runtime Error

Two execution modes:

  • Docker mode (local/self-hosted): Runs in isolated containers with --network none, memory limit 128MB, CPU limit 0.5 cores
  • Direct mode (Render cloud): Runs g++ natively inside a temp directory, cleaned up automatically

πŸ—„οΈ Database Schema

Entity Relationships

erDiagram
    User ||--o{ Submission : submits
    User ||--o{ Battle : competes_in
    User ||--o{ Contest : registers_for
    Problem ||--o{ TestCase : contains
    Problem ||--o{ Submission : evaluated_on
    Contest ||--o{ Problem : includes
    Battle ||--|| Problem : plays_on
    Battle ||--o| User : winner
Loading

Collections Overview

πŸ‘€ users

Field Type Description
_id ObjectId Unique User ID
name String Display name
email String Unique email address
password String Hashed password (bcryptjs)
role String 'user' or 'admin'
contestRating Number Contest rating (starts at 1200)
battleRating Number 1v1 Battle rating (starts at 1200)
ratingHistory Array Audit log of rating changes with timestamps

🧩 problems

Field Type Description
_id ObjectId Unique Problem ID
problemNumber Number Unique incremental problem number
title String Problem title
description String Problem statement, input/output formats & constraints
difficulty String 'Easy' | 'Medium' | 'Hard'
functionName String Target function name inside Solution class
starterCode String Boilerplate code template shown in editor
judgeConfig Object { returnType: String, parameters: [{ name, type }] }

πŸ§ͺ testcases

Field Type Description
_id ObjectId Unique Test Case ID
problem ObjectId Ref $\rightarrow$ problems
input String Raw input fed via stdin
expectedOutput String Expected output checked against stdout
isHidden Boolean false = visible sample test case, true = hidden judge case

⚑ submissions

Field Type Description
_id ObjectId Unique Submission ID
user ObjectId Ref $\rightarrow$ users
problem ObjectId Ref $\rightarrow$ problems
code String Submitted C++ source code
language String 'cpp'
status String 'pending' | 'accepted' | 'wrong_answer' | 'compile_error' | 'runtime_error' | 'time_limit_exceeded'
passedTests Number Number of test cases passed
totalTests Number Total test cases evaluated
runtime Number Execution time in milliseconds
memory Number Peak memory usage in KB
error String Compiler or runtime error message (if any)
battle ObjectId Ref $\rightarrow$ battles (null if practice submission)

πŸ† contests

Field Type Description
_id ObjectId Unique Contest ID
title String Contest title & theme
description String Rules and guidelines
startTime Date Contest start timestamp
endTime Date Contest end timestamp
problems [ObjectId] Array of Problem references
participants [ObjectId] Array of registered User references
finalLeaderboard Array Final ranks, scores, and penalty times

βš”οΈ battles

Field Type Description
_id ObjectId Unique Battle ID
player1 Object { user: Ref, rating: Number, currentCode: String }
player2 Object { user: Ref, rating: Number, currentCode: String }
problem ObjectId Ref $\rightarrow$ problems assigned to both players
winner ObjectId Ref $\rightarrow$ users (null if tied or in progress)
status String 'waiting' | 'in_progress' | 'finished'
duration Number Match duration limit (default: 15 minutes)
endReason String 'accepted' | 'timeout' | 'surrender'

πŸ“‘ API Reference

All endpoints are prefixed with /api/v1.

Auth (/auth)

Method Endpoint Auth Description
POST /register Public Create a new account
POST /login Public Login and get JWT token
POST /logout User Invalidate current token

Problems (/problems)

Method Endpoint Auth Description
GET / Public Get all problems (filter, paginate, search)
GET /:id Public Get a single problem
POST / Admin Create a problem
PUT /:id Admin Update a problem
DELETE /:id Admin Delete a problem

Submissions (/submissions)

Method Endpoint Auth Description
POST /run User Run code on sample test cases (no DB save)
POST / User Submit code for full judging (queued async)
GET /:id User Check submission result
GET /my User My submission history
GET /problem/:id User My submissions for a specific problem
GET /my/stats User My acceptance rate and stats

Battles (/battles)

Method Endpoint Auth Description
POST /matchmake User Join matchmaking pool
GET /:id User Get current battle info

Contests (/contests)

Method Endpoint Auth Description
GET / Public Get all contests
GET /:id Public Get contest details
POST / Admin Create a contest
POST /:id/register User Register for a contest
GET /:id/leaderboard Public Live leaderboard

Users (/users)

Method Endpoint Auth Description
GET /profile User My profile and rating history
GET /leaderboard Public Global rankings

πŸ”Œ WebSocket Events (Socket.io)

Socket connects with JWT: io(SERVER_URL, { query: { token } })

Events you send (Client β†’ Server):

Event Payload What it does
join_lobby β€” Enter matchmaking
leave_lobby β€” Cancel matchmaking
join_battle { battleId } Join battle room
battle_code_update { battleId, code } Sync code state
surrender_battle { battleId } Forfeit the match

Events you receive (Server β†’ Client):

Event Payload What it means
match_found { battleId, problem, opponent } Opponent found, battle starting
opponent_status { testsPassed, totalTests, status } Opponent progress update
battle_submission_result { status, passedTests } Your submission judged
battle_ended { winner, reason, ratingChanges } Match is over

πŸ“‚ Project Structure

CodeForge/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ Dockerfile                    # Node.js 20 + g++ for Render deployment
β”‚   β”œβ”€β”€ server.js                     # App entry β€” HTTP server + Socket.io setup
β”‚   └── src/
β”‚       β”œβ”€β”€ app.js                    # Express app, middleware, routes
β”‚       β”œβ”€β”€ config/
β”‚       β”‚   β”œβ”€β”€ database.js           # MongoDB connection
β”‚       β”‚   β”œβ”€β”€ redis.js              # Redis client
β”‚       β”‚   └── queue.config.js       # BullMQ Redis connection (with TLS)
β”‚       β”œβ”€β”€ controllers/              # Request handlers
β”‚       β”œβ”€β”€ middlewares/
β”‚       β”‚   β”œβ”€β”€ auth.middleware.js    # JWT verification + blacklist check
β”‚       β”‚   └── rateLimiter.middleware.js
β”‚       β”œβ”€β”€ models/                   # Mongoose schemas
β”‚       β”œβ”€β”€ queues/
β”‚       β”‚   └── submission.queue.js   # BullMQ queue setup
β”‚       β”œβ”€β”€ repositories/             # DB query functions
β”‚       β”œβ”€β”€ routes/                   # API route definitions
β”‚       β”œβ”€β”€ services/
β”‚       β”‚   β”œβ”€β”€ judge.service.js      # Core judging logic
β”‚       β”‚   β”œβ”€β”€ matchmaking.service.js
β”‚       β”‚   β”œβ”€β”€ battleResult.service.js
β”‚       β”‚   β”œβ”€β”€ rating.service.js     # ELO calculations
β”‚       β”‚   β”œβ”€β”€ contestRatingScheduler.service.js  # Cron job for auto-rating
β”‚       β”‚   └── executor/
β”‚       β”‚       β”œβ”€β”€ code-generator.js # Wraps user code into a full C++ program
β”‚       β”‚       β”œβ”€β”€ cpp.executor.js   # Compiles and runs code (Docker or direct)
β”‚       β”‚       └── executor.factory.js
β”‚       β”œβ”€β”€ sockets/
β”‚       β”‚   β”œβ”€β”€ socket.js             # Socket.io connection setup
β”‚       β”‚   β”œβ”€β”€ socketManager.js      # Global io() instance
β”‚       β”‚   └── battle.socket.js      # Battle room event handlers
β”‚       β”œβ”€β”€ utils/
β”‚       β”‚   └── cache.js              # Redis helper functions
β”‚       └── workers/
β”‚           └── submission.worker.js  # BullMQ worker β€” processes judge jobs
β”‚
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ vercel.json                   # SPA routing fix for Vercel
β”‚   └── src/
β”‚       β”œβ”€β”€ App.jsx                   # Routes
β”‚       β”œβ”€β”€ components/               # Navbar, Cards, Modals
β”‚       β”œβ”€β”€ context/                  # Auth context (global user state)
β”‚       β”œβ”€β”€ pages/
β”‚       β”‚   β”œβ”€β”€ ProblemList.jsx       # Problem browser
β”‚       β”‚   β”œβ”€β”€ ProblemDetail.jsx     # Editor + Run/Submit + Submission history
β”‚       β”‚   β”œβ”€β”€ BattleLobby.jsx       # Matchmaking UI
β”‚       β”‚   β”œβ”€β”€ BattleArena.jsx       # Live 1v1 battle screen
β”‚       β”‚   β”œβ”€β”€ Contests.jsx          # Contest list
β”‚       β”‚   β”œβ”€β”€ ContestDetail.jsx     # Contest problems + leaderboard
β”‚       β”‚   β”œβ”€β”€ Profile.jsx           # User stats + rating chart
β”‚       β”‚   β”œβ”€β”€ Submissions.jsx       # All submissions view
β”‚       β”‚   β”œβ”€β”€ CreateProblem.jsx     # Admin: add problem
β”‚       β”‚   └── CreateContest.jsx     # Admin: add contest
β”‚       └── services/
β”‚           β”œβ”€β”€ api.js                # Axios instance with auth interceptor
β”‚           └── socket.js             # Shared socket.io client
└── README.md

πŸ› οΈ Running Locally

Requirements

  • Node.js v18+
  • MongoDB (local or Atlas URI)
  • Redis (local or Upstash URL)
  • g++ compiler installed (sudo apt install g++ on Linux / MinGW on Windows)

1. Clone the Repo

git clone https://github.com/Lovejindal1/CodeForge.git
cd CodeForge

2. Setup Backend

cd backend
npm install
cp .env.example .env   # Fill in your values
npm start

Backend runs at http://localhost:3000

3. Setup Frontend

cd frontend
npm install
npm run dev

Frontend runs at http://localhost:5173


πŸ” Environment Variables

backend/.env

Variable Required Description
PORT No Port to run on (default: 3000)
NODE_ENV Yes development or production
MONGO_URI Yes MongoDB connection string
REDIS_URL Yes Redis URL (use rediss:// for TLS)
JWT_SECRET Yes Secret key for signing tokens
JWT_EXPIRES_IN Yes Token expiry e.g. 7d
FRONTEND_URL Yes Allowed CORS origin

frontend/.env

Variable Required Description
VITE_API_URL Yes Backend REST API base URL
VITE_SOCKET_URL Yes Backend WebSocket URL

πŸš€ Cloud Deployment Guide

CodeForge is built on a modern, decoupled cloud architecture using 5 free-tier services:

[Vercel]                 ──► Frontend (React + Vite SPA)
[Render]                 ──► Backend API & Judge (Docker with g++)
[MongoDB Atlas]          ──► Primary Database (M0 Cloud Cluster)
[Upstash Redis]          ──► Task Queue & Cache (Serverless Redis TLS)
[UptimeRobot]            ──► 24/7 Keep-Alive Heartbeat (/health pinger)

Step 1: Database Setup (MongoDB Atlas)

  1. Sign up at MongoDB Atlas and create a free M0 Cluster.
  2. Network Access: Add IP 0.0.0.0/0 (Allow access from anywhere, required for cloud hosting).
  3. Database Access: Create a database user with Read/Write privileges.
  4. Connection String: Click Connect $\rightarrow$ Drivers $\rightarrow$ Copy the URI:
    mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/codeforge?retryWrites=true&w=majority
    

Step 2: Queue & Cache Setup (Upstash Redis)

  1. Sign up at Upstash Redis and create a free database.
  2. Select the cloud region closest to your Render server region.
  3. In the database dashboard, copy the rediss:// connection string (TLS enabled).
  4. Usage in CodeForge:
    • BullMQ: Powers the asynchronous submission judging worker queue.
    • Token Blacklist: Instantly invalidates JWTs on logout.
    • Rate Limiting: Throttles brute-force API requests.

Step 3: Backend Deployment (Render with Docker)

  1. Sign up at Render and click New + $\rightarrow$ Web Service.
  2. Connect your GitHub repository: https://github.com/Lovejindal1/CodeForge.
  3. Configure the service:
    • Name: codeforge-backend
    • Runtime / Environment: Docker
    • Root Directory: backend
    • Dockerfile Path: ./Dockerfile
    • Instance Type: Free
  4. Add Environment Variables:
    NODE_ENV=production
    PORT=3000
    MONGO_URI=mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/codeforge
    REDIS_URL=rediss://default:xxxxxx@xxxxxx.upstash.io:6379
    JWT_SECRET=your_super_secret_jwt_key
    JWT_EXPIRES_IN=7d
    FRONTEND_URL=https://code-forge-iota-ten.vercel.app
  5. Click Create Web Service. Render builds the Docker image (node:20-bullseye-slim with g++) and starts the server.

Step 4: Frontend Deployment (Vercel)

  1. Sign up at Vercel and click Add New $\rightarrow$ Project.
  2. Import the CodeForge repository.
  3. Configure project settings:
    • Root Directory: frontend
    • Framework Preset: Vite
  4. Add Environment Variables:
    VITE_API_URL=https://<your-render-backend-url>/api/v1
    VITE_SOCKET_URL=https://<your-render-backend-url>
  5. Click Deploy.

    Note: Single Page Application (SPA) routing is pre-configured via frontend/vercel.json to prevent 404 errors on page refreshes.


Step 5: 24/7 Keep-Alive Monitor (UptimeRobot)

Render's free tier automatically spins down web services after 15 minutes of inactivity, resulting in a ~30–40s cold start when a user visits. To prevent this:

  1. Sign up for free at UptimeRobot.
  2. Click Add New Monitor:
    • Monitor Type: HTTP(s)
    • Friendly Name: CodeForge Backend Keep-Alive
    • URL (or IP): https://<your-render-backend-url>/health
    • Monitoring Interval: Every 5 minutes
  3. Save monitor. UptimeRobot now pings the /health endpoint every 5 minutes, keeping the backend warm 24/7 with zero cold start delays.

πŸ‘¨β€πŸ’» Author

Love Jindal


⭐ If you like this project, please give it a star!

Made with ❀️ by Love Jindal

About

Full-stack competitive programming & real-time algorithmic 1v1 battle arena platform built with React, Node.js, Socket.io, BullMQ, and Docker.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages