Contributing¶
Guidelines for contributing to this project.
Getting Started¶
1. Fork and Clone¶
2. Set Up Development Environment¶
# Install dependencies
uv sync --locked --all-extras --dev
# Configure environment (includes COMPOSE_FILE for local development)
cp .env.example .env
# Start infrastructure (PostgreSQL, Redis, MinIO)
docker compose up -d postgres redis minio
# Create MinIO buckets, run migrations, and collect static files
docker compose up minio-create-buckets migrations collectstatic
Manual Migrations
You can also run migrations manually using make makemigrations and make migrate.
3. Create a Branch¶
Code Standards¶
Formatting¶
All code must be formatted with Ruff:
Linting¶
All code must pass linting:
This runs:
ruff check— Python linterty check— Type checkingpyrefly check— Type checkingmypy— Type checking
We use multiple type checkers because each might catch different issues. See Development Environment for details.
Testing¶
All tests must pass with 80% coverage:
Pull Request Process¶
1. Create Your Changes¶
- Write code following existing patterns
- Add tests for new functionality
- Update documentation if needed
2. Run Quality Checks¶
3. Commit Your Changes¶
Write clear commit messages:
4. Push and Create PR¶
Then create a Pull Request on GitHub.
5. Address Review Feedback¶
- Respond to comments
- Make requested changes
- Push updates
Code Style¶
Python¶
- Follow PEP 8 (enforced by Ruff)
- Use type hints for all functions
- Write docstrings for public APIs
Controllers¶
Follow the controller pattern:
class MyController(Controller):
def __init__(self, dependency: Dependency) -> None:
self._dependency = dependency
def register(self, registry: Router) -> None:
registry.add_api_operation(...)
def handle_exception(self, exception: Exception) -> NoReturn:
...
Settings¶
Use Pydantic Settings:
class MySettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="MY_")
setting_name: str = "default"
Testing Guidelines¶
Test Structure¶
@pytest.mark.django_db(transaction=True)
def test_feature_name(test_client: TestClient) -> None:
# Arrange
...
# Act
response = test_client.post("/endpoint", json={...})
# Assert
assert response.status_code == 200
Test Isolation¶
Use fixtures for isolation:
def test_with_mock(container: Container) -> None:
mock = MagicMock()
container.register(Service, instance=mock)
...
Documentation¶
Adding Documentation¶
- Add new files to
docs/en/ - Update navigation in
docs/mkdocs.yml - Follow existing formatting patterns
Building Documentation¶
Issue Reporting¶
Bug Reports¶
Include:
- Python version
- Steps to reproduce
- Expected behavior
- Actual behavior
- Error messages
Feature Requests¶
Include:
- Use case description
- Proposed solution
- Alternatives considered
Questions?¶
- Open a GitHub Discussion
- Check existing issues and discussions
License¶
By contributing, you agree that your contributions will be licensed under the same license as the project.