Skip to main content
Evaly is an open-source test and exam management platform built with modern web technologies. We welcome contributions from developers of all skill levels.

Getting Started

Before you begin, make sure you have the required tools installed on your system.

Prerequisites

1

Install Bun

Download and install Bun v1.0.0 or higher. Bun is the JavaScript runtime used by Evaly.
curl -fsSL https://bun.sh/install | bash
2

Install Node.js

Install Node.js v18.0.0 or higher for the Convex CLI.
# Using nvm (recommended)
nvm install 18
nvm use 18
3

Create Convex Account

Sign up for a free Convex account to run the backend services.

Setting Up Your Development Environment

1

Fork and Clone

Fork the repository on GitHub and clone your fork locally:
git clone https://github.com/YOUR_USERNAME/evaly.git
cd evaly
2

Install Dependencies

Install all project dependencies using Bun:
bun install
3

Configure Environment

Create a .env.local file in the root directory:
# Convex deployment (from your Convex dashboard)
CONVEX_DEPLOYMENT=your-convex-deployment-name
Set up Convex environment variables through the Convex Dashboard or CLI:
# Authentication
npx convex env set AUTH_GOOGLE_ID your-google-client-id
npx convex env set AUTH_GOOGLE_SECRET your-google-client-secret
npx convex env set SITE_URL http://localhost:3000

# File uploads (Cloudflare R2)
npx convex env set R2_ACCESS_KEY_ID your-r2-access-key
npx convex env set R2_SECRET_ACCESS_KEY your-r2-secret-key
npx convex env set R2_BUCKET your-bucket-name
npx convex env set R2_ENDPOINT your-r2-endpoint
npx convex env set R2_CDN_URL your-cdn-url
npx convex env set R2_TOKEN your-r2-token
4

Start Development Servers

You’ll need two terminal windows to run both the backend and frontend:Terminal 1 - Convex Backend:
npx convex dev
Terminal 2 - Frontend:
bun run dev
The application will be available at http://localhost:3000

Making Your First Contribution

1

Create a Feature Branch

Create a new branch for your feature or bug fix:
git checkout -b feature/amazing-feature
Use descriptive branch names:
  • feature/ for new features
  • fix/ for bug fixes
  • docs/ for documentation updates
  • refactor/ for code refactoring
2

Make Your Changes

Write clean, well-documented code following the project’s conventions. Run type checking frequently:
bun run typecheck
3

Test Your Changes

Ensure your changes work as expected and don’t break existing functionality. See the Testing guide for details.
# Run unit tests
bun run test

# Run end-to-end tests
bun run test:e2e
4

Commit Your Changes

Write clear, descriptive commit messages:
git add .
git commit -m "Add feature: detailed description of what changed"
Good commit message examples:
  • fix: resolve race condition in test submission
  • feat: add support for essay question type
  • docs: update API documentation for grading endpoints
5

Push and Create Pull Request

Push your branch to GitHub and create a pull request:
git push origin feature/amazing-feature
In your pull request description:
  • Explain what changes you made and why
  • Reference any related issues
  • Include screenshots for UI changes
  • List any breaking changes

Project Structure

Understanding the codebase structure will help you navigate and contribute effectively:
evaly/
├── convex/                     # Backend logic and database schema
│   ├── organizer/             # Organizer-specific server functions
│   ├── participant/           # Participant-specific server functions
│   ├── schemas/               # Database schema definitions
│   ├── auth.config.ts         # Authentication configuration
│   └── schema.ts              # Main schema file
├── src/
│   ├── components/
│   │   ├── pages/             # Full page components
│   │   ├── shared/            # Reusable business components
│   │   └── ui/                # Base UI primitives (shadcn/ui)
│   ├── hooks/                 # Custom React hooks
│   ├── lib/                   # Utility functions and configurations
│   └── routes/                # File-based routing structure
│       ├── (organizer)/       # Protected organizer routes
│       └── (participant)/     # Public participant routes
├── e2e/                       # End-to-end tests (Playwright)
├── public/                    # Static assets
└── docs/                      # Additional documentation

Development Guidelines

Code Style

  • TypeScript: Use strict TypeScript with proper type annotations
  • Formatting: The project uses consistent formatting (follow existing patterns)
  • Components: Use functional components with hooks
  • Naming: Use descriptive names (camelCase for variables, PascalCase for components)

Backend Development (Convex)

  • Use mutation() for data modifications
  • Use query() for data reads (automatically cached and reactive)
  • Use action() for external API calls or multi-step operations
  • Always validate inputs with Convex validators (v.*)
  • Use ConvexError for error handling, never standard throw new Error()
import { ConvexError } from "convex/values";

throw new ConvexError({
  message: "User not authorized",
  code: "UNAUTHORIZED",
  display: "toast"
});

Frontend Development

  • Use TanStack Router for navigation and routing
  • Use Convex React hooks for data fetching
  • Follow the component structure: pages/shared/ui/
  • Use Tailwind CSS for styling (no custom CSS files)
  • Prefer shadcn/ui components for UI elements
Always check the CLAUDE.md file in the repository root for detailed architectural patterns and conventions.

Common Development Commands

# Start development server
bun run dev

# Start Convex backend
npx convex dev

# Type checking
bun run typecheck

Getting Help

If you need assistance while contributing:

Code Review Process

All contributions go through a code review process:
  1. A maintainer will review your pull request
  2. You may be asked to make changes or improvements
  3. Once approved, your changes will be merged
  4. Your contribution will be included in the next release
Thank you for contributing to Evaly and helping make education better for everyone!

Build docs developers (and LLMs) love