Getting Started

Pomelo

What is Pomelo?

Pomelo is an open-source competitive programming contest platform for hosting coding contests with automated code evaluation powered by Judge0.

It provides the pieces needed to run a local contest environment, including a participant-facing web app, an Express API, admin tooling, and Docker services for the backing stack.

Use this documentation to install dependencies, configure environment variables, start the services, and troubleshoot setup issues.

Installation

Run the following command to automatically install and set up Pomelo:

Terminal
$ curl -fsSL pomelo.sosc.org.in/install.sh | sudo bash

During Installation

When you run the installation script, it will prompt you to select which version of Pomelo to install (defaults to the latest release).

Next Steps

Once the installation finishes and the Pomelo daemon is running, you can start the entire platform with:

Terminal
$ pomelo start

To access the built-in administrator interface to manage your instance, simply run:

Terminal
$ pomelo ui

Workspace Setup

Follow these steps to set up the Pomelo workspace on your local machine.

Prerequisites

The Pomelo stack requires specific system tools to run locally and build. Make sure the following are installed:

  • Node.js (node): Required for the Next.js frontend and Express backend.
  • Bun (bun): Used specifically to compile the CLI and Daemon binaries.
  • pnpm: The strict package manager used across the monorepo workspace.
  • Docker & Docker Compose: Required for the database and Judge0 execution environment.

1. Clone the repository

Clone the repository to your local machine:

Terminal
$ git clone https://github.com/so-sc/pomelo && cd pomelo

2. Install workspace dependencies

Run pnpm install at the repository root to install all workspace dependencies.

Terminal
$ pnpm install

3. Start development services

Run pnpm dev to start the Next.js frontend, Express API, and local code-gen watchers.

Terminal
$ pnpm dev

WARNING: This only starts the Node.js services. The developer must also manually start the backing infrastructure containers (MongoDB, Postgres, Redis, Judge0) for the platform to function. See the Docker Setup section for instructions.

Environment Variables

Developers must copy the template .env.example file to .env before running the stack.

Terminal
$ cp .env.example .env

Development Variables

VariableDefault ValueDescription
AUTH_SECRET(required)Long random secret used by NextAuth for session encryption.
PORT8080Port the Express API listens on.
MONGODB_URImongodb://localhost:27017/pomeloMongoDB connection string.
JUDGE0_URLhttp://judge0-server:2358URL configuration for the Judge0 execution engine.
DOMAINlocalhost:3000Frontend domain used by the Next.js client.
PROTOCOLhttpProtocol for the frontend app.
BACKEND_URLhttp://localhost:8080URL used by server-side code to call the backend.
POSTGRES_PASSWORD(required)Password for the PostgreSQL database used by Judge0.
REDIS_PASSWORD(required)Password for the Redis queue used by Judge0.

Dev Setup

Docker Setup

Pomelo includes Docker Compose definitions in docker/app/ and docker/judge0/. Use the following command to start the backing services for local development.

Start the Docker dev stack

Terminal
docker compose --project-name pomelo --env-file .env \
-f docker/app/docker-compose.dev.yaml \
-f docker/judge0/docker-compose.dev.yaml \
--project-directory . up mongo judge0-server judge0-workers -d

Services

mongo

MongoDB database for contest and user data.

:27017
server

Express API for auth, contests, and submissions.

:8080
client

Participant-facing web app.

:3000
seed

Seeds MongoDB with initial data, then exits.

judge0-server

Judge0 core server for code execution.

:2358
judge0-workers

Judge0 worker processes.

judge0-db

PostgreSQL for Judge0 internal state.

judge0-redis

Redis for Judge0 job queuing.

Stop containers

Terminal
$ docker compose --project-name pomelo down

Remove volumes

Terminal
$ docker compose --project-name pomelo down -v

Local Installation

Packaging Script

The script at scripts/package.sh compiles the workspace into a standalone build.tar.gz archive containing only pre-built artifacts.

Usage

Run the script without arguments to create the default archive:

Terminal
$ ./scripts/package.sh

Or specify a custom output filename:

Terminal
$ ./scripts/package.sh custom-name.tar.gz

Installation Script

The script at scripts/install.sh deploys Pomelo to a host machine under /opt/pomelo.

Usage

To install from a local tarball:

Terminal
$ sudo bash scripts/install.sh --archive build.tar.gz

Uninstalling

To cleanly remove the installation:

Terminal
$ sudo bash scripts/install.sh --uninstall

Admin Tooling

Pomelo CLI

The admin directory contains the source for the administrator tooling.

The CLI and daemon are written in TypeScript and compiled into single-file executables using Bun. You must have Bun installed to compile these tools from source.

Daemon

pomelod is the background orchestrator daemon for Pomelo. Once installed, it monitors contest states and manages background tasks.

Systemd Policy

During installation, Pomelo sets up a persistent systemd service for the daemon at /etc/systemd/system/pomelod.service.

This policy ensures that the daemon automatically starts on boot and restarts on failure. If systemd is unavailable on the host system or the installation is not run as root, the daemon will start as a standard non-persistent background process instead.

CLI

pomelo is the terminal utility for administrators. It is symlinked to /usr/local/bin/pomelo during installation and provides a centralized way to interact with the platform services.

Commands

CommandDescription
pomelo startStarts all Pomelo backend services.
pomelo stopStops the running Pomelo services.
pomelo restartRestarts the Pomelo services.
pomelo statusChecks the status of the daemon and Docker containers.
pomelo logsStreams logs from the running services.
pomelo uiOpens the web admin dashboard on port 8462.
pomelo uninstallUninstalls Pomelo and cleans up the systemd service.

CLI Development

This section covers how to work on the CLI locally, which is located in the @pomelo/admin package.

Viewing the UI

To start the Vite UI on port 8462:

Terminal
$ pnpm --filter @pomelo/admin dev

Building Binaries

To compile the TypeScript files into pomelo and pomelod binaries using Bun:

Terminal
$ pnpm --filter @pomelo/admin build:cli

Hot-Swapping (Testing Local CLI)

You can test local changes by running the hot-swap script.

Terminal
$ sudo bash scripts/install-cli.sh

WARNING: This script requires sudo privileges. You must have already installed Pomelo to /opt/pomelo using install.sh first. This script only copies the newly built binaries over the existing installation and restarts the pomelod systemd service.

Troubleshooting

Common Issues

Open the issue that matches what you are seeing, then compare the guidance with your local setup.

Toolchain pnpm install fails

Confirm pnpm 10.0.0 or newer is installed.

Confirm Node.js is installed.

Confirm Git is available in PATH.

Environment pnpm dev fails

Confirm .env exists and matches .env.example.

Confirm AUTH_SECRET is set to a non-empty value.

Confirm MONGODB_URI points to a running MongoDB instance.

Confirm JUDGE0_URL points to a running Judge0 server.

Containers Docker Compose fails

Confirm Docker and Docker Compose v2 are installed.

Confirm .env exists in the repository root.

Confirm POSTGRES_PASSWORD and REDIS_PASSWORD are set.

Run the Docker Compose command from the repo root directory.

Database Backend cannot connect to MongoDB

Verify MONGODB_URI is correct and reachable.

Confirm the mongo container or service is running.

Check logs with docker logs pomelo-mongo-1.

Judge0 Judge0 jobs fail or time out

Verify JUDGE0_URL is correct.

Confirm judge0-server and judge0-workers are running.

Confirm judge0-db and judge0-redis are healthy.

API Reference

Authentication API

The Pomelo frontend uses NextAuth for authentication. API routes enforce authentication using the following middleware:

MiddlewareDescription
requireAuth()Enforces standard authentication for routes.
isAdminEnforces admin-only access for elevated routes.

Contests API

Endpoints for managing and participating in contests.

MethodEndpointDescription
POST/api/contests/joinValidates a join code and returns a contestId.
GET/api/contests/:idFetches public contest landing data.
POST/api/contests/startInitializes an attempt session for a user.
GET/api/contests/:id/dataFetches the active questions and test data for an ongoing attempt.
POST/api/contests/:id/endSubmits the final test and locks the session.
GET/api/contests/:id/leaderboardAdmin-only route to view ranked scores.

Submissions API

Endpoints for handling code execution and test submissions.

MethodEndpointDescription
POST/api/contests/:id/runPerforms a dry-run code execution against sample test cases.
POST/api/submitThe unified submission endpoint for all question types.