Code Quality Tools¶
This document describes all code quality tools used in the project, their configuration, and how to run them locally.
Overview¶
The project uses a comprehensive suite of tools to maintain code quality:
| Layer | Tool | Purpose | Config File |
|---|---|---|---|
| Backend | Ruff | Linting + Formatting | pyproject.toml |
| Backend | MyPy | Type Checking | pyproject.toml |
| Backend | pytest | Testing | pyproject.toml |
| Backend | Hypothesis | Property-based Testing | pyproject.toml |
| Backend | Bandit | Security Scanning | (via Ruff S rules) |
| Backend | Vulture | Dead Code Detection | vulture_whitelist.py |
| Backend | Radon | Complexity Metrics | (CLI args) |
| Frontend | ESLint | Linting | frontend/eslint.config.mjs |
| Frontend | Prettier | Formatting | frontend/package.json |
| Frontend | TypeScript | Type Checking | frontend/tsconfig.json |
| Frontend | Vitest | Testing | frontend/vite.config.ts |
| Frontend | Playwright | E2E Testing | frontend/playwright.config.ts |
| Frontend | Knip | Dead Code Detection | frontend/package.json |
| Both | Hadolint | Dockerfile Linting | .pre-commit-config.yaml |
| Both | Semgrep | Security Scanning | semgrep.yml |
Backend Tools (Python)¶
Ruff - Linting and Formatting¶
Ruff is an extremely fast Python linter and formatter written in Rust.
Configuration (pyproject.toml):
[tool.ruff]
target-version = "py314"
line-length = 100
src = ["backend"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort (import sorting)
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"ARG", # flake8-unused-arguments
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"PTH", # flake8-use-pathlib
"ERA", # eradicate (commented-out code)
"PL", # Pylint
"RUF", # Ruff-specific rules
"ASYNC", # flake8-async
"S", # flake8-bandit (security)
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
Commands:
# Check for linting errors
uv run ruff check backend/
# Auto-fix linting errors
uv run ruff check --fix backend/
# Check formatting
uv run ruff format --check backend/
# Auto-format code
uv run ruff format backend/
MyPy - Type Checking¶
MyPy performs static type checking on Python code.
Configuration (pyproject.toml):
[tool.mypy]
python_version = "3.14"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
ignore_missing_imports = true
plugins = ["pydantic.mypy"]
Commands:
# Run type checking
uv run mypy backend/
# Run with specific options
uv run mypy backend/ --ignore-missing-imports
pytest - Testing Framework¶
pytest is the testing framework used for all backend tests.
Configuration (pyproject.toml):
[tool.pytest.ini_options]
testpaths = ["backend/tests"]
python_files = ["test_*.py"]
asyncio_mode = "auto"
addopts = "-n auto --dist=worksteal -v --strict-markers --tb=short"
timeout = 5
markers = [
"asyncio: mark test as an async test",
"unit: mark test as a unit test",
"integration: mark test as an integration test (5s timeout)",
"e2e: mark test as an end-to-end pipeline test",
"gpu: mark test as a GPU test",
"slow: mark test as legitimately slow (30s timeout)",
"benchmark: mark test as a benchmark test",
"serial: mark test as requiring serial execution",
]
Commands:
# Run all tests
uv run pytest backend/tests/
# Run unit tests with parallel execution
uv run pytest backend/tests/unit/ -n auto --dist=worksteal
# Run integration tests (serial execution)
uv run pytest backend/tests/integration/ -n0
# Run with coverage
uv run pytest backend/tests/ --cov=backend --cov-report=term-missing
# Run specific test file
uv run pytest backend/tests/unit/test_cameras.py -v
# Run tests matching a pattern
uv run pytest -k "test_camera" -v
Hypothesis - Property-Based Testing¶
Hypothesis generates test cases automatically based on property specifications.
Configuration (pyproject.toml):
[tool.hypothesis.profiles.ci]
max_examples = 100
deadline = 1000
database = "none"
print_blob = true
[tool.hypothesis.profiles.dev]
max_examples = 500
deadline = 5000
database = "directory:.hypothesis"
Usage in tests:
from hypothesis import given, strategies as st
@given(st.integers(min_value=0, max_value=100))
def test_risk_score_bounds(score):
"""Property: risk scores must be bounded."""
assert 0 <= process_risk(score) <= 100
Coverage Configuration¶
Configuration (pyproject.toml):
[tool.coverage.run]
source = ["backend"]
omit = ["backend/tests/*", "backend/examples/*", "backend/main.py"]
[tool.coverage.report]
fail_under = 95
show_missing = true
precision = 2
Coverage thresholds:
| Test Type | Threshold | Enforcement |
|---|---|---|
| Unit | 85% | CI |
| Integration | 50% | CI |
| Combined | 80% | Local |
| Overall | 95% | CI (final) |
Vulture - Dead Code Detection¶
Vulture finds unused code in Python projects.
Commands:
# Run dead code detection
uv run vulture backend/ --min-confidence 80
# With whitelist (for false positives)
uv run vulture backend/ vulture_whitelist.py --min-confidence 80
Radon - Complexity Metrics¶
Radon computes code complexity metrics.
Commands:
# Cyclomatic complexity (show grades A-F)
uv run radon cc backend/ -a -s
# Maintainability index
uv run radon mi backend/ -s
# Only show complex functions (grade C or worse)
uv run radon cc backend/ -a -nc
Complexity grades:
| Grade | Complexity | Risk |
|---|---|---|
| A | 1-5 | Low |
| B | 6-10 | Low |
| C | 11-20 | Moderate |
| D | 21-30 | High |
| E | 31-40 | Very High |
| F | 41+ | Untestable |
Frontend Tools (TypeScript/React)¶
ESLint - Linting¶
ESLint is the JavaScript/TypeScript linter with React-specific rules.
Configuration (frontend/eslint.config.mjs):
// Key enabled rule sets:
// - @eslint/js recommended
// - typescript-eslint recommended + recommendedTypeChecked
// - react, react-hooks, jsx-a11y plugins
// - import ordering
// Key rules:
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'import/order': ['error', { 'newlines-between': 'always' }],
Commands:
Prettier - Code Formatting¶
Prettier enforces consistent code formatting.
Configuration (in frontend/package.json):
Commands:
TypeScript - Type Checking¶
TypeScript provides static type checking for the frontend.
Configuration (frontend/tsconfig.json):
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx"
}
}
Commands:
Vitest - Unit Testing¶
Vitest is the testing framework for frontend unit tests.
Commands:
cd frontend
# Run tests in watch mode
npm test
# Run tests once
npm test -- --run
# Run with coverage
npm run test:coverage
# Run with UI
npm run test:ui
Playwright - E2E Testing¶
Playwright runs end-to-end browser tests.
Commands:
cd frontend
# Run all E2E tests
npm run test:e2e
# Run in headed mode (visible browser)
npm run test:e2e:headed
# Run in debug mode
npm run test:e2e:debug
# View test report
npm run test:e2e:report
# Run specific browser
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
Knip - Dead Code Detection¶
Knip finds unused files, dependencies, and exports in TypeScript projects.
Commands:
Pre-commit Hooks¶
Pre-commit hooks run automatically before each commit to catch issues early.
Installation¶
# Install pre-commit (if not already installed)
pip install pre-commit
# Install hooks
pre-commit install
# Install pre-push hooks (for tests)
pre-commit install --hook-type pre-push
Hook Configuration (.pre-commit-config.yaml)¶
| Hook | Stage | Purpose |
|---|---|---|
| trailing-whitespace | pre-commit | Remove trailing whitespace |
| end-of-file-fixer | pre-commit | Ensure files end with newline |
| check-yaml | pre-commit | Validate YAML syntax |
| check-json | pre-commit | Validate JSON syntax |
| check-merge-conflict | pre-commit | Detect merge conflict markers |
| detect-private-key | pre-commit | Prevent committing private keys |
| hadolint | pre-commit | Lint Dockerfiles |
| semgrep | pre-commit | Security scanning (Python) |
| ruff | pre-commit | Python linting |
| ruff-format | pre-commit | Python formatting |
| mypy | pre-commit | Python type checking |
| prettier | pre-commit | Format non-frontend files |
| prettier-frontend | pre-commit | Format frontend files |
| eslint | pre-commit | Frontend linting |
| typescript-check | pre-commit | Frontend type checking |
| auto-rebase | pre-push | Rebase on origin/main |
| fast-test | pre-push | Run unit tests |
| api-types-contract | pre-push | Verify API types are current |
| check-test-mocks | pre-commit | Verify integration tests mock slow services |
| check-test-timeouts | pre-commit | Verify tests mock slow sleeps |
Running Hooks Manually¶
# Run all hooks on all files
pre-commit run --all-files
# Run specific hook
pre-commit run ruff --all-files
pre-commit run mypy --all-files
# Skip hooks (emergencies only!)
SKIP=fast-test git commit -m "message"
CI/CD Enforcement¶
All quality checks are enforced in CI (.github/workflows/ci.yml).
Backend CI Jobs¶
| Job | Tool | Blocking |
|---|---|---|
| Backend Lint | Ruff | Yes |
| Backend Type Check | MyPy | Yes |
| Backend Unit Tests | pytest | Yes |
| Backend Integration Tests | pytest | Yes |
| Dead Code Detection | Vulture | No |
| Complexity Check | Radon | No |
Frontend CI Jobs¶
| Job | Tool | Blocking |
|---|---|---|
| Frontend Lint | ESLint | Yes |
| Frontend Type Check | TypeScript | Yes |
| Frontend Tests | Vitest | Yes |
| E2E Tests (Chromium) | Playwright | No* |
| E2E Tests (Firefox/WebKit) | Playwright | No |
| Dead Code Detection | Knip | No |
| API Types Contract | Custom | Yes |
*E2E tests are temporarily non-blocking while stabilizing.
Security CI Jobs¶
| Job | Tool | Blocking |
|---|---|---|
| Admin Endpoint Security | pytest | Yes |
| Security Scanning | Semgrep | Yes |
Quick Reference Commands¶
Full Validation (Recommended Before PRs)¶
# Run everything
./scripts/validate.sh
# Backend only
./scripts/validate.sh --backend
# Frontend only
./scripts/validate.sh --frontend
Backend Quick Commands¶
# Lint and format
uv run ruff check --fix backend/ && uv run ruff format backend/
# Type check
uv run mypy backend/
# Run tests
uv run pytest backend/tests/ -v
# Run tests with coverage
uv run pytest backend/tests/ --cov=backend --cov-report=term-missing
Frontend Quick Commands¶
cd frontend
# Lint and format
npm run lint:fix && npm run format
# Type check
npm run typecheck
# Run tests
npm test -- --run
# Run E2E tests
npm run test:e2e
All Pre-commit Hooks¶
Troubleshooting¶
Ruff Errors¶
# See what rules are being violated
uv run ruff check backend/ --show-source
# Auto-fix with unsafe fixes
uv run ruff check --fix --unsafe-fixes backend/
MyPy Errors¶
# Show detailed error messages
uv run mypy backend/ --show-error-codes
# Generate stubs for missing packages
uv run stubgen -p package_name
ESLint Errors¶
# See rule documentation
npx eslint --print-config src/App.tsx
# Disable rule for specific line
// eslint-disable-next-line @typescript-eslint/no-explicit-any
TypeScript Errors¶
# See compiler diagnostics
npx tsc --noEmit --diagnostics
# Generate declaration files to debug types
npx tsc --declaration --emitDeclarationOnly
Related Documentation¶
- Contributing Guide - Development workflow
- Testing Guide - Test strategy and patterns
- Setup Guide - Development environment setup
- CLAUDE.md - Project instructions