Thanks for your interest in contributing! This guide will help you get started.
- Code of Conduct
- Getting Started
- Development Setup
- Making Changes
- Commit Conventions
- Pull Request Process
- Coding Standards
- Reporting Bugs
- Requesting Features
This project follows the Contributor Covenant Code of Conduct. By participating, you're expected to uphold it.
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/<your-username>/CodeVerdict.git cd CodeVerdict
- Add the upstream remote:
git remote add upstream https://github.com/ATOAPaymentsLimited/CodeVerdict.git
- Create a branch from
main:git checkout -b feature/your-feature-name
- Node.js 22 LTS
- Docker 24+ with Compose v2
- PostgreSQL 17 (only for running without Docker)
cd server && npm install && cd ..
cd client && npm install && cd ..cp .env.example .env
cp server/.env.example server/.env
cp client/.env.example client/.envEdit the .env files with your local values. See the README for details on each variable.
docker compose up --buildThis starts all 6 services: the app, app database (PostgreSQL 17), Judge0 server, Judge0 worker, Judge0 database (PostgreSQL 16), and Redis (Judge0 job queue).
# Terminal 1 - backend
cd server && npm run start:dev
# Terminal 2 - frontend
cd client && npm run devMake sure PostgreSQL is running locally and CORS_ORIGIN=http://localhost:5173 is set in server/.env.
You need a Judge0 instance for code submissions to work.
- Linux / macOS / WSL - self-host Judge0 locally using Docker. Follow the Judge0 deployment procedure, then set
JUDGE0_URLinserver/.envto your local instance. On macOS, Docker Desktop runs a Linux VM so Judge0 works out of the box. - Windows (without WSL) - Judge0 requires Linux-only features (cgroups, isolate). Use the hosted Judge0 CE API on RapidAPI instead. Signup and a payment method are required. Set
JUDGE0_URLandRAPIDAPI_KEYinserver/.envper the values from RapidAPI.
- Keep changes focused - one feature or fix per PR
- Write clear code - prefer readability over cleverness
- Follow existing patterns - look at how similar features are implemented before creating new abstractions
- Update documentation - if your change affects setup, configuration, or API behavior, update the README
- Entities go in
server/src/entities/ - All entities extend
BaseEntity(id,createdAt,updatedAt) - Use
class-validatordecorators on DTOs - Add
@ApiProperty()to DTO fields for Swagger docs - Use the
@Auth()decorator for protected routes,@Auth(AuthType.JWT, [AdminGuard])for admin-only routes - Use injected repositories, never
managerdirectly
- Use Composition API with
<script setup lang="ts"> - State management via Pinia stores in
client/src/stores/ - API calls go through service files in
client/src/services/ - Reusable logic goes in composables (
client/src/composables/)
Always generate migrations using the TypeORM CLI - never write them by hand:
cd server
npm run migration:generate -- src/migrations/DescriptiveNameReview the generated file before committing. Use PascalCase names (e.g., AddProblemDifficultyColumn).
We use Conventional Commits:
<type>: <short description>
[optional body]
| Type | When to use |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting, semicolons, etc. (no logic change) |
refactor |
Code change that neither fixes a bug nor adds a feature |
perf |
Performance improvement |
chore |
Build process, dependencies, tooling |
feat: add problem difficulty field to exam problems
fix: prevent timer drift with server-synced countdown
docs: add Docker troubleshooting section to README
chore: bump NestJS to v11.1
-
Sync with upstream before opening a PR:
git fetch upstream git rebase upstream/main
-
Ensure your code passes linting:
cd server && npm run lint cd client && npm run lint cd client && npm run build # catches TypeScript errors
-
Open a PR against
mainwith:- A clear title following commit conventions
- A description explaining what changed and why
- Screenshots for UI changes
-
Respond to review feedback - we aim to review PRs within a few days
-
One approval required before merging
- Code follows existing patterns and conventions
- Linting passes (
npm run lintin server) - TypeScript compiles without errors (
npm run buildin client) - New environment variables are documented in
.env.examplefiles - Database changes have a generated migration
- README updated if setup/configuration changed
- Strict mode enabled
- No
anytypes unless absolutely necessary (and documented why) - Use interfaces for object shapes, enums for fixed sets
- Follow NestJS module structure: controller -> service -> repository
- Use DTOs for all request/response bodies
- Validate inputs with
class-validator - Use pessimistic locking (
SELECT ... FOR UPDATE) for score-related writes
- Components use
<script setup lang="ts"> - Keep components focused - extract logic into composables
- Use Pinia for shared state, local refs for component-only state
- No hardcoded secrets or credentials - use environment variables
- No
console.login production code (use NestJSLoggeron the backend) - Prefer early returns over deeply nested conditionals
Open a GitHub issue with:
- Title: Short, descriptive summary
- Environment: OS, Node version, Docker version, browser
- Steps to reproduce: Numbered list, as specific as possible
- Expected behavior: What should happen
- Actual behavior: What actually happens
- Logs/screenshots: Include error messages, console output, or screenshots
Open a GitHub issue with:
- Title: Short description of the feature
- Problem: What problem does this solve?
- Proposed solution: How you'd like it to work
- Alternatives considered: Other approaches you thought about
For larger features, open an issue first to discuss the approach before writing code.
Open a discussion or reach out via issues. We're happy to help you get started!