Skip to content

Chauhan48/code_judge_backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Online Coding Judge - Backend API

A Node.js backend service for an online coding judge platform built with Fastify, MongoDB, and JDoodle/Judge0 code execution engines.

Table of Contents


Project Overview

The Online Coding Judge backend provides REST APIs for:

  • Admin user authentication and problem/test management
  • Candidate invitation and test access via unique tokens
  • Code submission execution using JDoodle or Judge0 services
  • Submission tracking and progress monitoring
  • Real-time statistics dashboard for admins

Technology Stack:

  • Runtime: Node.js
  • Web Framework: Fastify
  • Database: MongoDB with Mongoose ODM
  • Authentication: JWT (JSON Web Tokens)
  • Code Execution: JDoodle API
  • Email: Nodemailer SMTP

Folder Structure

backend/
├── app/
│   ├── config/
│   │   └── index.js                 # Environment configuration
│   ├── controllers/
│   │   ├── admin.controller.js       # Admin operations (registration, login, invitations, problems, stats)
│   │   ├── invitation.controller.js  # Invitation acceptance
│   │   ├── problems.controller.js    # Problem retrieval
│   │   ├── progress.controller.js    # Candidate progress and statistics
│   │   ├── submission.controller.js  # Submission testing
│   │   ├── test.controller.js        # Test retrieval and code execution
│   │   └── index.js                  # Controller exports
│   ├── middlewares/
│   │   ├── auth.middleware.js        # JWT admin authentication
│   │   └── logger.middleware.js      # Request logging
│   ├── models/
│   │   ├── invitation.model.js       # Invitation schema (email, token, test, expiry)
│   │   ├── problem.model.js          # Problem schema (title, description, test cases, languages)
│   │   ├── submission.model.js       # Submission schema (code, status, score, execution results)
│   │   ├── test.model.js             # Test schema (assessment with multiple problems)
│   │   ├── user.model.js             # User schema (admin/candidate roles)
│   │   └── user.test.model.js        # User test progress tracking
│   ├── routes/
│   │   ├── admin.routes.js           # Admin API routes
│   │   ├── candidate.route.js        # Candidate routes (deprecated/legacy)
│   │   ├── invitation.routes.js      # Invitation routes
│   │   ├── problem.route.js          # Problem routes
│   │   ├── submission.routes.js      # Submission routes
│   │   ├── test.routes.js            # Test routes
│   │   └── index.js                  # Route registration
│   ├── services/
│   │   ├── email.service.js          # Email sending via Nodemailer
│   │   ├── jdoodle.service.js        # JDoodle code execution
│   │   └── judge0.service.js         # Judge0 code execution
│   ├── startup/
│   │   ├── db.startup.js             # MongoDB connection setup
│   │   └── server.startup.js         # Fastify server initialization
│   ├── utils/
│   │   ├── languageMap.js            # Language ID mapping for JDoodle
│   │   └── logger.js                 # Logging utility
│   └── middleware/
│       └── auth.middleware.js        # Authentication middleware
├── logs/                             # Log files directory
├── server.js                          # Application entry point
├── package.json                       # Project dependencies
├── .env.example                       # Environment variables template
└── README.md                          # This file

Installation

Prerequisites

  • Node.js v16+
  • MongoDB v4.0+
  • npm or yarn

Steps

  1. Clone the repository:
git clone <repository-url>
cd backend
  1. Install dependencies:
npm install
  1. Set up environment variables (see Environment Setup below):
cp .env.example .env

Environment Setup

Create a .env file in the project root with the following variables:

# Server Configuration
PORT=3000
NODE_ENV=development

# Database
MONGODB_URI=mongodb://localhost:27017/online-coding-judge

# JWT
JWT_SECRET=your-super-secret-key-min-32-chars
JWT_EXPIRES_IN=1d

# Frontend URL
FRONTEND_URL=http://localhost:5173

# JDoodle Configuration
JDOODLE_CLIENTID=your-jdoodle-client-id
JDOODLE_CLIENTSECRET=your-jdoodle-client-secret
JDOODLE_BASE_URL=https://api.jdoodle.com/v1

# By default the code-runner will prefer Judge0 if it's available.  If you
# only want to use JDoodle (or you don't have Judge0 running) set this to
# false and every test‑case evaluation will be performed via JDoodle instead of
# Judge0.
USE_JUDGE0=false

# Judge0 Configuration (Alternative to JDoodle)
JUDGE0_BASE_URL=http://127.0.0.1:2358
JUDGE0_AUTH_TOKEN=your-judge0-auth-token

# SMTP Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM=your-email@gmail.com

Running the Application

Development Mode

npm run dev

The server will start on http://localhost:3000 with automatic restart on file changes.

Production Mode

npm start

API Documentation

Base URL

All requests should be made to: http://localhost:3000/api

Authentication

Protected endpoints require an Authorization header with a JWT token:

Authorization: Bearer <your-jwt-token>

Admin Endpoints

1. Register Admin

POST /admin/register

Create a new admin account.

Request Body:

{
  "name": "John Admin",
  "email": "admin@example.com",
  "password": "securepassword123"
}

Response:

{
  "message": "Admin registered successfully",
  "user": {
    "_id": "63f...",
    "name": "John Admin",
    "email": "admin@example.com",
    "role": "admin"
  }
}

2. Login Admin

POST /admin/login

Authenticate an admin and receive JWT token.

Request Body:

{
  "email": "admin@example.com",
  "password": "securepassword123"
}

Response:

{
  "message": "Login successful",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "_id": "63f...",
    "name": "John Admin",
    "email": "admin@example.com",
    "role": "admin"
  }
}

3. Create Problem

POST /admin/problems (Requires Admin Auth)

Create a new coding problem with test cases.

Request Body:

{
  "title": "Two Sum",
  "slug": "two-sum",
  "description": "Given an array of integers nums and an integer target...",
  "difficulty": "easy",
  "languages": ["python", "java", "cpp", "javascript"],
  "timeLimitMs": 2000,
  "memoryLimitMb": 256,
  "publicTestCases": [
    {
      "input": "2 7 11 15\n9",
      "expectedOutput": "0 1"
    }
  ],
  "hiddenTestCases": [
    {
      "input": "3 3",
      "expectedOutput": "0 1"
    }
  ]
}

Response:

{
  "message": "Problem created successfully",
  "problem": {
    "_id": "63f...",
    "title": "Two Sum",
    "slug": "two-sum",
    ...
  }
}

4. Send Invitation

POST /admin/invite (Requires Admin Auth)

Send test invitations to candidates.

Request Body:

{
  "email": "candidate@example.com",
  "problemIds": ["63f...problem1", "63f...problem2"],
  "durationMinutes": 90
}

Response:

{
  "message": "Invitation sent successfully",
  "email": "candidate@example.com",
  "expiresAt": "2026-03-04T10:30:00.000Z",
  "testId": "63f..."
}

5. Get All Submissions

GET /admin/submissions (Requires Admin Auth)

Retrieve submissions with optional filters.

Query Parameters:

  • testId (optional): Filter by test ID
  • email (optional): Filter by candidate email
  • problemId (optional): Filter by problem ID

Example Request:

GET /admin/submissions?testId=63f...&email=candidate@example.com

Response:

{
  "submissions": [
    {
      "_id": "63f...",
      "user": {
        "_id": "63f...",
        "name": "John Candidate",
        "email": "candidate@example.com"
      },
      "problem": {
        "_id": "63f...",
        "title": "Two Sum"
      },
      "language": "python",
      "status": "accepted",
      "score": 100,
      "executionTime": 0.05,
      "memory": 7424,
      "createdAt": "2026-02-25T10:30:00.000Z"
    }
  ]
}

6. Get Admin Statistics

GET /admin/stats (Requires Admin Auth)

Get overview statistics for all candidates and submissions.

Query Parameters:

  • testId (optional): Scope statistics to a specific test

Example Request:

GET /admin/stats
GET /admin/stats?testId=63f...

Response:

{
  "totalCandidates": 25,
  "activeSessions": 8,
  "totalSubmissions": 156,
  "usersAttemptedCount": 18
}

7. Get All Candidates

GET /admin/candidates (Requires Admin Auth)

List all invited candidates with their participation status and submission counts.

Query Parameters:

  • status (optional): Filter by status (pending, accepted, expired)
  • testId (optional): Filter by test ID
  • email (optional): Filter by candidate email

Example Request:

GET /admin/candidates
GET /admin/candidates?status=pending

Response:

{
  "candidates": [
    {
      "id": "63f...",
      "email": "candidate@example.com",
      "status": "pending",
      "token": "a1b2c3d4e5f6...",
      "test": {
        "id": "63f...",
        "name": "Assessment for candidate@example.com",
        "durationMinutes": 90
      },
      "createdBy": {
        "id": "63f...",
        "name": "John Admin",
        "email": "admin@example.com"
      },
      "attempts": 3,
      "lastAttempt": {
        "id": "63f...",
        "status": "accepted",
        "score": 85,
        "passed": true,
        "createdAt": "2026-02-25T10:30:00.000Z"
      },
      "expiresAt": "2026-03-04T10:30:00.000Z",
      "createdAt": "2026-02-25T09:30:00.000Z"
    }
  ]
}

Test/Candidate Endpoints

1. Get Test Details by Token

GET /test?token=<invitation-token> OR POST /test

Retrieve test details and problems for a candidate using invitation token.

Request (GET):

GET /test?token=a1b2c3d4e5f6...

Request (POST):

{
  "token": "a1b2c3d4e5f6..."
}

Response:

{
  "testId": "63f...",
  "email": "candidate@example.com",
  "durationMinutes": 90,
  "problems": [
    {
      "_id": "63f...",
      "title": "Two Sum",
      "description": "Given an array of integers...",
      "difficulty": "easy",
      "languages": ["cpp", "java", "javascript", "python"],
      "publicTestCases": [
        {
          "input": "2 7 11 15 9",
          "output": "0 1"
        }
      ],
      "timeLimitMs": 2000,
      "memoryLimitMb": 256
    }
  ]
}

2. Submit Code for Execution

POST /test/run

Execute candidate's code and save submission.

Request Body:

{
  "sourceCode": "print('Hello World')",
  "stdin": "",
  "languageKey": "python",
  "token": "a1b2c3d4e5f6...",
  "problemId": "63f..."
}

Response:

{
  "output": "Hello World",
  "memory": "7424",
  "cpuTime": "0.05",
  "statusCode": 200
}

3. Get Candidate Progress

GET /test/progress?token=<invitation-token>

Retrieve candidate's progress across all problems in a test.

Request:

GET /test/progress?token=a1b2c3d4e5f6...

Response:

{
  "testId": "63f...",
  "email": "candidate@example.com",
  "attempted": true,
  "problems": [
    {
      "problemId": "63f...",
      "title": "Two Sum",
      "attempted": true,
      "attempts": 2,
      "lastAttempt": {
        "id": "63f...",
        "status": "accepted",
        "score": 100,
        "passed": true,
        "output": "0 1",
        "createdAt": "2026-02-25T10:30:00.000Z"
      }
    },
    {
      "problemId": "63f...",
      "title": "Reverse String",
      "attempted": false,
      "attempts": 0,
      "lastAttempt": null
    }
  ]
}

Invitation Endpoints

Accept Invitation

GET /invitation?token=<invitation-token>

Mark an invitation as accepted when candidate opens the test.

Request:

GET /invitation?token=a1b2c3d4e5f6...

Response:

{
  "success": true,
  "problems": [...]
}

Problem Endpoints

Get All Problems

GET /problems

Retrieve all active problems (public endpoint).

Response:

{
  "problems": [
    {
      "_id": "63f...",
      "title": "Two Sum",
      "slug": "two-sum",
      "difficulty": "easy",
      "languages": ["python", "java"],
      ...
    }
  ]
}

Database Models

User Model

Represents admin and candidate users.

{
  _id: ObjectId,
  name: String,
  email: String (unique),
  role: String (enum: "admin", "candidate"),
  passwordHash: String,
  isActive: Boolean,
  createdAt: Date,
  updatedAt: Date
}

Invitation Model

Represents test invitations sent to candidates.

{
  _id: ObjectId,
  email: String,
  test: ObjectId (ref: Test),
  token: String (unique),
  createdBy: ObjectId (ref: User),
  expiresAt: Date,
  status: String (enum: "pending", "accepted", "expired"),
  createdAt: Date,
  updatedAt: Date
}

Test Model

Represents an assessment with multiple problems.

{
  _id: ObjectId,
  name: String,
  description: String,
  problems: [ObjectId] (ref: Problem),
  durationMinutes: Number,
  startTime: Date,
  endTime: Date,
  inviteCode: String,
  createdBy: ObjectId (ref: User),
  isActive: Boolean,
  createdAt: Date,
  updatedAt: Date
}

Problem Model

Represents a coding problem.

{
  _id: ObjectId,
  title: String,
  slug: String (unique),
  description: String,
  difficulty: String (enum: "easy", "medium", "hard"),
  tags: [String],
  languages: [String],
  timeLimitMs: Number,
  memoryLimitMb: Number,
  publicTestCases: [{
    input: String,
    expectedOutput: String,
    score: Number
  }],
  hiddenTestCases: [{
    input: String,
    expectedOutput: String,
    score: Number
  }],
  createdBy: ObjectId (ref: User),
  isActive: Boolean,
  createdAt: Date,
  updatedAt: Date
}

Submission Model

Represents a code submission by a candidate.

{
  _id: ObjectId,
  user: ObjectId (ref: User),
  test: ObjectId (ref: Test),
  problem: ObjectId (ref: Problem),
  language: String,
  sourceCode: String,
  status: String (enum: "pending", "running", "accepted", "wrong_answer", "compile_error", "runtime_error", "time_limit_exceeded", "failed"),
  score: Number,
  executionTime: Number,
  memory: Number,
  judge0SubmissionId: String,
  rawJudge0Response: Object,
  createdAt: Date,
  updatedAt: Date
}

Services

Email Service

Sends invitation emails to candidates via SMTP.

Location: app/services/email.service.js

Functions:

  • sendInvitationEmail(to: string, inviteLink: string) - Sends HTML email with invitation link

JDoodle Service

Executes code using JDoodle API.

Location: app/services/jdoodle.service.js

Functions:

  • executeCode(params: object) - Executes code and returns output/memory/time

Parameters:

  • script: Source code
  • stdin: Standard input
  • language: Language identifier (python3, nodejs, cpp17, java)
  • versionIndex: Language version

Judge0 Service

Executes code using Judge0 API (alternative to JDoodle).

Location: app/services/judge0.service.js

Functions:

  • createSubmission(params: object) - Create and optionally wait for submission
  • getSubmission(token: string) - Get submission result by token
  • runTestCase(params: object) - Run single test case synchronously

Error Handling

Standard error response format:

{
  "message": "Error description"
}

HTTP Status Codes:

  • 200: Success
  • 201: Created
  • 400: Bad Request
  • 401: Unauthorized
  • 403: Forbidden
  • 404: Not Found
  • 500: Internal Server Error

Contributing

  1. Create a feature branch: git checkout -b feature/your-feature
  2. Make changes and test thoroughly
  3. Commit: git commit -am "Add your feature"
  4. Push: git push origin feature/your-feature
  5. Submit a pull request

License

This project is private and proprietary. Unauthorized copying is prohibited.


Questions? Contact the development team or refer to the API documentation above.

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors