# Contributing to Dispatcharr Thank you for your interest in contributing. Dispatcharr is a complex, production-oriented platform and we hold contributions to a high standard. Please read this guide in full before opening a pull request — it will save everyone time. --- ## Table of Contents - [Before You Start](#before-you-start) - [Project Overview](#project-overview) - [Setting Up the Development Environment](#setting-up-the-development-environment) - [Code Standards](#code-standards) - [Writing Tests](#writing-tests) - [Submitting a Pull Request](#submitting-a-pull-request) - [On AI-Assisted Code](#on-ai-assisted-code) - [What We Will Decline](#what-we-will-decline) --- ## Before You Start **Open an issue before writing code.** If you want to add a feature or fix a non-trivial bug, open a GitHub issue first. This lets us tell you whether it aligns with the project's direction, whether it's already being worked on, and how it should be approached — before you invest time writing code. For small, obvious bug fixes (a typo, an off-by-one error, a missing validation) you can go straight to a PR. --- ## Project Overview Understanding the architecture is a prerequisite for contributing. If you are not familiar with the following, take time to learn them before submitting changes: | Layer | Technology | | ----------- | ------------------------------------------------- | | Backend | Python 3.13, Django 5, Django REST Framework | | Async tasks | Celery 5 with Redis broker | | Real-time | Django Channels (WebSockets), Redis channel layer | | Database | PostgreSQL 17 | | Frontend | React 19, Vite, Mantine UI, Zustand | | API docs | drf-spectacular (OpenAPI) | | Packaging | `uv`, `pyproject.toml`, Hatchling | | Deployment | Docker, Nginx, uWSGI/Daphne | ### Key Django Apps | App | Responsibility | | --------------- | ----------------------------------------------------- | | `apps/channels` | Core channel management | | `apps/proxy` | Stream proxying, client management, failover | | `apps/epg` | EPG ingestion, matching, XMLTV output | | `apps/m3u` | M3U playlist parsing and management | | `apps/output` | M3U, Xtream Codes, XMLTV export | | `apps/hdhr` | HDHomeRun device emulation | | `apps/vod` | VOD library with TMDB/IMDB metadata | | `apps/ffmpeg` | FFmpeg stream profile management | | `apps/plugins` | Plugin/event-hook system | | `apps/accounts` | Auth, permissions, API keys | | `core/` | Shared tasks, scheduling, utilities, Xtream Codes API | Before touching any app, read its models, serializers, and views end-to-end so you understand what already exists. --- ## Setting Up the Development Environment ### Prerequisites - Docker and Docker Compose - Node.js 24+ (for frontend) - Python 3.13+ and [`uv`](https://docs.astral.sh/uv/) ### Backend (Docker — recommended) ```bash # Full stack (modular mode with separate containers) docker compose -f docker/docker-compose.dev.yml up # Or run Django directly against a local Redis/Postgres uv sync uv run python manage.py migrate uv run python manage.py runserver ``` ### Frontend ```bash cd frontend npm install npm run dev # dev server with HMR (proxies API to Django) npm run build # production build npm run test # run Vitest test suite ``` The Vite dev server is configured to proxy `/api/` requests to the Django backend. ### Environment Variables Copy the relevant `docker-compose.*.yml` as a reference for required environment variables. Key ones: | Variable | Purpose | | ----------------------- | ------------------------------------------------------------------------------------------- | | `POSTGRES_*` | Database connection | | `REDIS_*` | Redis broker / channel layer | | `DJANGO_SECRET_KEY` | Django secret (auto-generated in Docker) | | `DISPATCHARR_DEBUG` | Enables Django debug mode **and** starts debugpy for remote debugging (attach on port 5678) | | `DISPATCHARR_LOG_LEVEL` | Log verbosity | --- ## Code Standards ### Backend (Python/Django) - Follow [PEP 8](https://peps.python.org/pep-0008/). Use 4-space indentation. - Follow Django conventions: fat models, thin views, business logic out of serializers. - New API endpoints must use Django REST Framework. Include serializers — do not return raw dicts from views. - New endpoints must be registered in the appropriate `api_urls.py` and must appear correctly in the OpenAPI schema (check via drf-spectacular). - Database changes require a migration: `uv run python manage.py makemigrations `. Migrations must be included in your PR. - Celery tasks belong in `tasks.py` of the relevant app, or `core/tasks.py` for shared tasks. Tasks must be idempotent where possible. - Do not introduce new top-level dependencies without discussion. Add them to `pyproject.toml` with a justification in your PR description. ### Frontend (React/JavaScript) - Code must pass ESLint without errors: `npm run lint` - Code must be formatted with Prettier: `npm run format` - Use existing Mantine UI components. Do not introduce new UI libraries. - State management uses Zustand. New global state belongs in a store under `frontend/src/store/`. Do not use React Context for app-level state. - API calls belong in `frontend/src/api.js`. Do not make `fetch`/`axios` calls directly from components. - Components should be functional. Avoid class components. ### General - Do not leave debug logging, `console.log`, `print()`, or commented-out code in your PR. - Do not reformat or refactor code outside the scope of your change. Noise in diffs makes review harder. - Keep commits focused. One logical change per commit. --- ## Writing Tests Untested code is significantly less likely to be merged. ### Backend - Use Django's `TestCase` for unit/integration tests. - Test files live at `apps//tests/`. - Run the test suite with: `uv run python manage.py test` ### Frontend - Use Vitest and React Testing Library. - Test files live alongside what they test in `__tests__/` directories. - Run with: `npm run test` - Every new store should have a test file under `frontend/src/store/__tests__/`. - Every new page should have a test file under `frontend/src/pages/__tests__/`. --- ## Submitting a Pull Request ### PR Checklist Before opening your PR, verify each of the following yourself: - [ ] I have read this entire document - [ ] I opened (or was assigned to) a GitHub issue for this change before writing code - [ ] I understand — line by line — every change in this PR - [ ] Backend: migrations are included if models changed - [ ] Backend: new endpoints are documented in the OpenAPI schema - [ ] Frontend: ESLint and Prettier pass cleanly - [ ] Tests are included for new functionality - [ ] Existing tests still pass - [ ] No debug artifacts are left in the code - [ ] My PR targets the `dev` branch (or the branch specified in the issue) ### PR Description A good PR description answers: 1. **What** does this change do? 2. **Why** is this change needed? (link to the issue) 3. **How** does it work? Describe any non-obvious technical decisions. 4. **How was it tested?** What did you run to verify this works? One-line PR descriptions like _"fixed bug"_ or _"added feature"_ will be closed and asked to resubmit. ### Review Process Maintainers review PRs as time allows. To keep the process moving: - Respond to review comments promptly. Stale PRs (no activity for 30 days) may be closed. - Do not force-push to a branch under review without flagging it in a comment. - Keep your branch up to date with `dev` by rebasing, not merging `dev` into your branch. --- ## On AI-Assisted Code We are aware that AI coding tools are capable of generating plausible-looking code quickly. We do not prohibit their use, but we require the following: **You must understand every line of code you submit.** AI tools frequently produce code that: - Duplicates logic that already exists elsewhere in the codebase - Ignores the established patterns for how the project is structured - Introduces subtle bugs that are invisible without domain knowledge - Passes superficial review but breaks edge cases in production If you cannot explain, during code review, why a particular line of code is written the way it is — including the tradeoffs involved — the PR will not be merged. There are no exceptions. Using an AI tool to help you understand the codebase, generate a first draft, or write boilerplate is fine. Submitting code you have not read and do not understand is not. --- ## What We Will Decline To save your time and ours, the following types of PRs will be closed without extended review: - **Undiscussed feature additions.** If there is no linked issue where the feature was agreed upon, we will close the PR and ask you to open one. - **Large, unfocused diffs.** A PR that touches 20 files across 5 apps to "improve code quality" is almost never reviewable. Scope your changes. - **Dependency bumps without justification.** Don't open a PR just to bump a library version unless you have identified a specific bug or security issue it resolves. - **Cosmetic/style-only changes.** Reformatting files, renaming variables for preference, or reorganizing imports with no functional change. - **Duplicate work.** Check open PRs and issues before starting. If someone is already working on it, coordinate with them. - **Code the author cannot explain.** See [On AI-Assisted Code](#on-ai-assisted-code). --- ## Questions If you are unsure whether a contribution is a good fit, join the [Discord](https://discord.gg/Sp45V5BcxU) and start a conversation, or comment on the relevant issue. We would rather have a five-minute conversation upfront than a 30-comment review thread on a PR that ultimately doesn't get merged.