Tech Stack

Frontend

  • React - modern UI Library, huge ecosystem and community support, stable and known as easy to build web apps;
  • Vite build tool - modern and lightweight, proides fast dev server with hot module replacement, easy customization;
  • Typescript - superset of JavaScript, provides type safety for better IDE interaction and less error prone;
  • Possible extensions:
    • Redux - modern state management used with react;
    • Router - most popular React routing solution;
    • Tailwind CSS - rapid and consistend design.

Backend

  • Python 3.11+ – mature, familiar language with rich ecosystem, great support for FastAPI, async I/O, testing, and deployment in self-hosted environments;
  • FastAPI – modern, high-performance async web framework with type hints and automatic OpenAPI docs, ideal for a clean REST API for auth, teams, pairings, grading, and reviews;
  • Pydantic – robust data validation and serialization layer for request/response models, ensuring consistent schemas for grades, teams, and assignments;
  • Uvicorn – lightweight ASGI server well-suited for FastAPI, simple to run in Docker and sufficient for expected traffic;
  • SQLAlchemy – ORM and query toolkit on top of PostgreSQL, keeps domain logic explicit and maintainable without scattering raw SQL;
  • Alembic – schema migration tool integrated with SQLAlchemy, used to evolve DB schema safely as requirements change;

Database

  • PostgreSQL – reliable relational database for users, teams, assignments, pairings, grades, and file metadata, easy to host on-prem and widely supported;

Testing

We use pytest as our primary testing framework. It was chosen because:

  • It has a clean, minimal syntax and is easy to scale.
  • It supports fixtures, parametrization, and plugins out of the box.
  • It integrates seamlessly with pytest-cov for coverage measurement.
  • It is the most widely adopted testing tool in modern Python backend development.

Unit tests

Location and naming conventions:

  • All backend unit tests are located in:
    backend/peer-pilot/tests/
  • Test files must be named:
    test_*.py
  • Test functions must start with:
    test_
  • API-level tests are grouped under:
    backend/peer-pilot/tests/api/
  • Shared fixtures are placed in:
    tests/conftest.py

How to run unit tests

  • From the backend root: pytest
  • Run a specific test file: pytest tests/test_example.py
  • Run a single test: pytest tests/test_example.py::test_specific_case

How to generate a coverage report

Generate terminal + XML coverage output: pytest --cov=app --cov-report=xml --cov-report=term

This produces: coverage.xml

The XML file is used by CI to evaluate coverage levels.


How to adjust minimum coverage thresholds

The minimum threshold is defined in pytest.ini: –cov-fail-under=30 To increase or decrease it, simply update the value:

CI also reads the same number from the generated XML report for validation.


Why this coverage report format?

  • XML is compatible with modern CI systems, such as GitHub Actions, Codecov, and SonarQube.
  • It is the standard output format for pytest-cov, requiring no extra tooling.
  • It allows CI to parse precise numeric coverage values.
  • Developers still get immediate feedback through terminal reports.

This format strikes a balance between human readability and automation compatibility.


Why these minimum coverage thresholds?

Current threshold: 30%.

Chosen because:

  • The project is still in early development.
  • Some modules (schemas, ORM models) have inherently low ROI for testing.
  • It prevents completely untested code while allowing rapid iteration.
  • It offers a baseline quality floor without slowing the team.

Coverage thresholds planned for MVP

Expected overall target: 60–70%

Module-specific targets:

Module Area Target
Business logic/services 80–90%
Scoring/aggregation 70–80%
API endpoints 50–60%
Database models/ORM 10–20%

These levels reflect:

  • Core logic → must be highly reliable
  • API → moderate safety requirement
  • Models → stable, low failure risk

Modules selected for unit tests and why

The following modules were prioritized:

  • Grade aggregation logic
    • High complexity
    • Direct impact on user grades
  • Dashboard composition
    • Integrates multiple datasets
    • Changes often
  • Peer review scoring
    • Core business logic
    • Direct customer impact
  • Team/student relational logic
    • Sensitive to regression
  • Endpoint contract tests
    • /dashboard, /grades
    • Provide user-facing functionality
    • Must stay stable

Modules were selected based on:

  • Complexity
  • Change frequency
  • Customer importance
  • Risk of regression

Static analysis

Overview

To ensure consistent code quality, early bug detection, and maintainable documentation, the project uses several static analysis tools.
Each formal language in the codebase (Python, Markdown) requires a dedicated tool for formatting and validation.
For Python specifically, additional type checking is required to detect issues before runtime.


Selected tools and justification

1. Ruff (Python linter + formatter)

Purpose: Formatting, linting, import sorting
Why chosen:

  • Extremely fast (written in Rust)
  • Replaces multiple tools: Black, Flake8, isort
  • Provides a consistent formatting standard for the entire Python codebase
  • Integrates seamlessly with CI and pre-commit
  • Good autofix support reduces developer overhead

Covers requirements:

  • Code formatting checker
  • Linter for Python
  • Ensures stylistic & structural consistency

2. Mypy (Python static type checker)

Purpose: Static type checking for Python
Why chosen:

  • Mature ecosystem and widely adopted in industry
  • Best-in-class type inference for dynamically typed code
  • Great compatibility with FastAPI / Pydantic (used in the project)
  • Detects type-related bugs before execution
  • Helps enforce stable APIs between service layers

Covers requirements:

  • Mandatory for dynamic languages to detect errors early
  • Ensures type safety in business logic and API layers

Purpose: Validates internal & external links inside Markdown documentation
Why chosen:

  • Integrated with mdBook ecosystem
  • Detects broken internal references (e.g., renamed pages)
  • Prevents deployment of invalid docs
  • CI-friendly output

Covers requirements:
✔ Required link checker for docs
✔ Prevents broken navigation in published documentation


4. markdownlint (Markdown formatting checker)

Purpose: Enforces consistent Markdown formatting
Why chosen:

  • Ensures readability across the entire documentation set
  • Prevents inconsistent headings, indentations, and list styles
  • Integrates easily with editors and CI

Covers requirements:

  • Formatter/linter for Markdown files
  • Ensures consistent documentation style

Summary of Tools

Tool Language Purpose
Ruff Python Formatter + linter
Mypy Python Type checker
markdownlint Markdown Formatting consistency
mdbook-linkcheck Markdown Detect broken links in documentation

These tools collectively ensure:

  • Correct formatting
  • Early detection of type errors
  • High documentation quality
  • CI-enforced consistency across the entire repository