The Grader System is a comprehensive online judge platform designed to facilitate competitive programming and programming education. It features a modern, responsive React frontend, a robust Node.js (Express) backend, and a PostgreSQL database, all orchestrated with Docker for seamless setup, deployment, and scalability. This system allows users to register, solve programming problems by submitting C++ code, and receive real-time feedback on their submissions. Administrators have powerful tools to manage users, problems, contests, and the database, making it a versatile platform for various programming challenges.
Target Audience: This system is ideal for students, educators, and anyone interested in developing their programming skills through competitive programming or structured practice.
The Grader System offers a rich set of features for both users and administrators:
- User Management:
- User Registration and Login: Secure user authentication with encrypted passwords and session management.
- User Roles: Differentiated access for regular users, staffs and administrators.
- Batch User Creation (Admin): Administrators can generate multiple user accounts with a defined prefix and random passwords.
- Problem Management:
- Problem Statements (PDF): Upload and display problem descriptions in PDF format (up to 2GB).
- Test Case Management: Store and manage test cases (input/output) for each problem in the database.
- Single Problem Upload (Admin): Administrators can add new problems or update existing ones individually, including their metadata, PDF, and test cases (via ZIP upload).
- Batch Problem Upload (Admin): Efficiently upload multiple problems at once using structured ZIP files (up to 2GB).
- Problem Visibility Control (Admin): Administrators can toggle the visibility of problems to users.
- Code Submission & Judging:
- C++ Code Submission: Users can submit C++ solutions to problems (C++ only currently supported).
- Isolated Judging Environment: Code is compiled and executed in an isolated environment to prevent security risks and ensure fair evaluation.
- Real-time Judging: Submissions are judged promptly, providing immediate feedback on correctness, execution time, and memory usage.
- Detailed Results: For each submission, users receive detailed results per test case, including status (Accepted, Wrong Answer, Time Limit Exceeded, Memory Limit Exceeded, Runtime Error, Compilation Error).
- Time and Memory Limits: Configurable time and memory limits for each problem to control resource usage during judging.
- Contest Management:
- Contest Creation and Configuration (Admin): Administrators can create and configure new programming contests with specific problems, start/end times, and visibility settings.
- Contest Participation: Users can view available contests and join those that are currently active or scheduled.
- Contest-Specific Submissions: Submissions made within a contest are tracked separately from general problem submissions, ensuring contest integrity.
- Contest Scoreboard: Real-time scoreboard displaying participants' scores and rankings within a contest.
- Scoreboard:
- Global Scoreboard: A public scoreboard displaying user rankings based on their performance across all general problems.
- Database Management (Admin Only):
- Export Database: Administrators can export the entire database to a
.sqldump file for backup purposes. - Import Database: Administrators can restore the database from a
.sql,.dump, or.tarfile. WARNING: Importing a database will PERMANENTLY DELETE ALL EXISTING DATA in the database and replace it with the contents of the uploaded file. Proceed with extreme caution and ensure you have a backup of your current database if needed.
- Export Database: Administrators can export the entire database to a
- System Settings (Admin Only):
- Registration Toggle: Administrators can enable or disable new user registrations.
The Grader System is built with a modern, type-safe tech stack (TypeScript-first), ensuring a robust, scalable, and responsive application.
- Frontend:
- React 19 & TypeScript: Modern UI development with strong typing.
- React Router 7: For declarative routing and data loading.
- Axios: Promise-based HTTP client with typed API contracts.
- Vanilla CSS & HTML5: Clean, performant styling without heavy utility frameworks.
- Backend:
- Node.js & Express 5 (TypeScript): High-performance RESTful API framework.
- PostgreSQL: Robust relational database accessed via raw parameterized SQL.
- Zod: Centralized runtime validation for request schemas.
bcrypt: Secure password hashing.multer&unzipper&archiver: File upload, extraction, and asset management.node-cron: For automated contest scheduling and lifecycle management.- Session-based Auth: Secure authentication using
express-sessionandconnect-pg-simple.
- Judging System:
- C++: High-performance execution for user-submitted code.
- GCC: Used to compile the judging wrapper and user submissions.
- Containerization & Deployment:
- Docker & Docker Compose: Containerized microservices for consistent environments.
- Nginx: Reverse proxy handling
/apirouting and frontend serving.
- Tools & Testing:
- Jest & Supertest: Comprehensive backend integration and unit testing.
- React Testing Library: Component-level testing for the frontend.
- Git: Version control and collaboration.
To get the Grader System up and running, you only need to install a few essential tools on your host machine. The rest of the application's dependencies (Node.js, npm, PostgreSQL) are managed within Docker containers.
- Docker: Essential for containerizing, building, running, and managing the application's services.
- Git: Required to clone the project repository for local development and version control.
-
Clone the repository:
git clone https://github.com/Nonbangkok/OJ.git cd OJ -
Create the environment file:
- Copy the example environment file to create your own local configuration.
cp .env.example .env
- Open the
.envfile and change all of them and thePOSTGRES_PASSWORDandSECRET_KEYto your own strong, secret values.
- Copy the example environment file to create your own local configuration.
Once the installation and setup are complete, you can start the application:
- Build and Run Docker Containers:
Navigate to the root directory of the project (where
docker-compose.ymlis located) and execute the following command:docker-compose up --build -d
- The first time you run this command, it might take several minutes as Docker downloads the PostgreSQL image and builds the frontend and backend images.
- Access the Application:
After the containers have successfully started, open your web browser and navigate to:
http://localhost
The Nginx proxy, running in its own Docker container, handles routing. Requests to
/are forwarded to thefrontendservice, while requests to/api/are rewritten and forwarded to thebackendservice.
After successfully running the Docker containers for the first time, you need to initialize the PostgreSQL database and create an administrative user. This is a crucial step as the database tables are not automatically created when the containers start.
- Create Database Tables:
Execute the following command from the project's root directory to set up all necessary database tables and default system settings:
docker-compose exec backend node init_db.js- This script connects to the
oj_databasecontainer and runs the database schema initialization.
- This script connects to the
- Create an Admin User:
After creating the tables, you must create an initial administrator account. Run this command and follow the interactive prompts in your terminal to set up your admin username and password:
docker-compose exec backend node create_admin.js- This command will guide you through creating an admin user, which is essential for accessing the administrative functionalities of the system.
Your Grader System is now fully set up and ready for use!
The project includes automated tests for both the backend and frontend. You can run the full test suite or run tests for each part separately.
From the project root, execute the unified test script to run both backend and frontend tests:
./tests/run_tests.sh- This script runs backend tests first, then frontend tests. It exits with status code 0 if all tests pass, or 1 if any test fails.
- Note: Ensure Docker containers (including the database) are running before executing this script, as backend tests may require a database connection.
From the project root:
cd backend
npm test- Backend tests use Jest and Supertest to test API endpoints, controllers, and middleware (e.g., authentication, submissions, problems, contests, admin).
- Backend tests are located in
backend/tests/.
From the project root:
cd frontend
npm test- Frontend tests use Jest and React Testing Library (
@testing-library/react,@testing-library/jest-dom,@testing-library/user-event) to test pages, hooks, services, and components. - By default,
npm testruns in watch mode (re-runs on file changes). To run once and exit (e.g., in CI), use:CI=true npm test - Frontend tests are located in
frontend/src/tests/.
The system provides administration tools for exporting and importing the entire database, useful for backups or emergency recovery. These features are accessible via the Admin Panel under "Settings".
Administrators can export the current state of the database to a .sql dump file.
- Navigate to the Admin Panel.
- Go to the "Settings" section.
- Click the "Export Database" button.
- The browser will download an
oj_backup_*.sqlfile containing your entire database.
Administrators can import a database dump file (.sql, .dump, or .tar) to restore the database to a previous state.
WARNING: Importing a database will PERMANENTLY DELETE ALL EXISTING DATA in the database and replace it with the contents of the uploaded file. Proceed with extreme caution and ensure you have a backup of your current database if needed.
- Navigate to the Admin Panel.
- Go to the "Settings" section.
- In the "Import Database" section, click "Choose File" and select your database dump file.
- Click the "Upload & Import" button.
- Confirm the action when prompted. The import process will begin.
- After a successful import, you may need to refresh your browser or re-login.
The system provides robust tools for administrators to manage programming problems, accessible via the Admin Panel under the "Problem Management" section.
- Single Problem Upload:
Administrators can add new problems or update existing ones individually. This includes:
- Problem Metadata: Define problem ID, title, author, time limit (in milliseconds), and memory limit (in megabytes).
- Problem Statement (PDF): Upload a single PDF file (up to 2GB) containing the problem description.
- Test Cases: Upload a
.ziparchive (up to 2GB) containing the input and output test cases for the problem. The system will automatically parse and store these test cases.
- Note: Uploading new test cases for an existing problem will clear all previously associated test cases before inserting the new ones.
- Batch Problem Upload:
For efficiency, administrators can upload multiple problems simultaneously using a single structured
.zipfile (up to 2GB). This feature is available via the "Batch Upload" button on the Problem Management page.- Zip File Structure: The uploaded
.zipfile can follow two main structures:- Single Problem ZIP: The root of the ZIP contains all files for one problem (
config.json, PDF, and test cases). - Multiple Problems ZIP: The root of the ZIP contains multiple directories, where each directory represents a distinct problem.
- Single Problem ZIP: The root of the ZIP contains all files for one problem (
- Zip File Structure: The uploaded
The ZIP file contains all necessary files for a single problem at its root level.
Problem.zip
├── config.json
├── Problem.pdf
└── testcases/
├── input/
│ ├── 1.in
│ └── 2.in
└── output/
├── 1.out
└── 2.out
The ZIP file contains multiple problem directories. The system will iterate through each directory and process it as a separate problem, demonstrating the various ways test cases can be structured.
ProblemSet.zip
├── MyFirstProblem/
│ ├── config.json
│ ├── MyFirstProblem.pdf
│ └── testcases.zip (Internal structure: Flat)
│ ├── 1.in
│ ├── 1.out
│ ├── input_02.txt
│ └── output_02.txt
│
├── MySecondProblem/
│ ├── config.json
│ ├── MySecondProblem.pdf
│ └── testcases/ (Internal structure: Directories)
│ ├── input/
│ │ ├── 01.in
│ │ └── 02.in
│ └── output/
│ ├── 01.out
│ └── 02.out
│
└── MyThirdProblem/
├── config.json
├── MyThirdProblem.pdf
└── data/ (Internal structure: Flat directory)
├── case_01.txt
├── out_case_01.txt
├── case_02.txt
└── out_case_02.txt
Each problem directory (either at the root of a multi-problem ZIP or the content of a single-problem ZIP) must contain:
-
config.json: A JSON file detailing the problem's metadata.{ "id": "plus", "title": "Plus", "author": "Nonbangkok", "time_limit_ms": 1000, "memory_limit_mb": 32 }id: A unique string identifier for the problem (e.g., "plus").title: The display name of the problem (e.g., "Plus").author: The author of the problem.time_limit_ms: The maximum allowed execution time for a solution, in milliseconds.memory_limit_mb: The maximum allowed memory usage for a solution, in megabytes.
-
Problem Statement PDF: A single
.pdffile (up to 2GB) containing the problem description. The system will automatically detect and use the first PDF file found within the problem's directory. -
Test Cases: Test cases can be organized in one of several flexible formats:
-
Option A: Zip Archive (
testcases.zip) A single.zipfile namedtestcases.zipplaced within the problem directory. This inner ZIP file can itself have two internal structures:- Flat Structure: Input and output files are directly at the root of
testcases.zip. Files must be numerically paired. Supported naming conventions include:input1.in/output1.out,1.in/1.out,input1.txt/output1.txt,test_01.in/test_01.out,case_A.in/case_A.out, etc.Internal structure of MyFirstProblem/testcases.zip ├── 1.in ├── 1.out ├── input_02.txt └── output_02.txt - Directory Structure: The
testcases.zipcontainsinput/andoutput/subdirectories. All input files go intoinput/, and all corresponding output files go intooutput/. Files are paired by sorting them alphabetically/numerically.Another example of a testcases.zip internal structure ├── input/ │ ├── 01.in │ └── 02.in └── output/ ├── 01.out └── 02.out
- Flat Structure: Input and output files are directly at the root of
-
Option B:
input/outputSubdirectories Instead of atestcases.zip, you can provide a subdirectory (e.g.,testcases/ordata/) that directly contains two subfolders:input/andoutput/. All input files are placed ininput/, and their corresponding output files inoutput/. Files are paired by sorting them alphabetically/numerically (e.g.,01.inininput/matches01.outinoutput/).Internal structure of problem testcases , Option B : └── testcases/ ├── input/ │ ├── 01.in │ └── 02.in └── output/ ├── 01.out └── 02.out -
Option C: Flat Directory Structure As an alternative, you can place all test case files directly within a single subdirectory (e.g.,
testcases/ordata/). The system will pair files based on the numbers in their filenames (e.g.,input1.txtwithoutput1.txt,case_02.inwithcase_02.out,test_01.inwithtest_01.out,case_A.inwithcase_A.out).Internal structure of problem testcases , Option C : └── data/ ├── input1.txt ├── output1.txt ├── case_02.in └── case_02.out -
Recommendation: It is highly recommended to use numerically sequential and consistently named test case files (e.g.,
01.in,02.in, ...,01.out,02.out, ...) to ensure correct pairing and ordering during the judging process. This helps avoid unexpected behavior across different file systems and parsing logic.
-
Note: The script will clear any existing test cases for a problem before inserting the new ones.
The Grader System includes a dedicated module for managing programming contests, providing a structured environment for competitive events. This functionality is primarily accessible and configurable by administrators.
- Contest Creation and Configuration:
Administrators can create new contests, defining:
- Basic Information: Contest title, description, and visibility.
- Schedule: Start and end times for the contest.
- Associated Problems: Select existing problems to be part of the contest. Important: Problems assigned to an active contest become inaccessible as standalone problems for general submission during the contest period.
- Status Management: Contests progress through various statuses:
scheduled(waiting to start),running(currently active), andfinished(concluded). These statuses are managed automatically by the system's scheduler.
- Contest Participation: Users can view available contests and join those that are currently active or scheduled.
- Contest-Specific Submissions: During a contest, participants submit solutions to problems specifically within the contest environment. These submissions are tracked separately from general problem submissions, ensuring contest integrity.
- Contest Scoreboard: A real-time scoreboard is available for each contest, displaying the scores and rankings of participants. This scoreboard is dynamically updated as participants submit and their solutions are judged.
- Contest Scheduler:
The backend includes a dedicated service (
contestScheduler.js) that automatically manages the status of contests based on their defined start and end times.
