Skip to content

Contributing

Guidelines for contributing to BuckPow.


Welcome

BuckPow welcomes contributions from engineers, researchers, educators, and makers interested in energy observability for embedded systems.

Whether you improve documentation, firmware, hardware integrations, benchmarking methods, or the web platform, your contributions are appreciated.

Please open an issue before submitting large changes to discuss the proposed implementation.

Getting Started

Prerequisites

  • Python 3.12+
  • Node.js (for frontend tooling, optional)
  • Git

Development Setup

# Clone the repository
git clone https://github.com/arifnd/buckpow.git
cd buckpow

# Install dependencies (creates .venv with uv)
uv sync

# Start development server
fastapi dev src/main.py --port 8000

Running Tests

uv run pytest tests/ -v

Sending Dummy Data

uv run python scripts/send_dummy.py --interval 1

Project Structure

buckpow/
├── src/
│   ├── __init__.py    # App factory, lifespan, middleware
│   ├── main.py        # Entrypoint
│   ├── config.py      # Settings
│   ├── database.py    # SQLAlchemy engine
│   ├── models.py      # Shared Pydantic / ORM bases
│   ├── router.py      # Router aggregation
│   ├── dependencies.py # FastAPI dependencies (re-exports)
│   ├── template_helpers.py # Jinja2 rendering helpers
│   ├── version.py     # App version
│   ├── auth/          # Auth domain
│   ├── devices/       # Device domain
│   ├── sessions/      # Session domain
│   ├── measurements/  # Measurement domain
│   ├── projects/      # Project domain
│   ├── alerts/        # Alert domain
│   ├── audit/         # Audit log domain
│   ├── benchmark/     # Benchmark domain
│   ├── settings/      # Settings domain
│   ├── dashboard/     # Dashboard pages
│   ├── middleware/     # ASGI middleware
│   ├── utils/         # Utility functions
├── templates/         # Jinja2 templates (project root)
├── static/            # CSS, JS
├── firmware/          # Arduino sketches
├── migrations/        # Alembic migrations
├── tests/             # Test suite (by domain)
├── scripts/           # Helper scripts
├── tasks/             # Task management
├── nginx/             # Nginx config for Docker
├── requirements/      # pip-compatible requirements (mirror pyproject.toml)
├── pyproject.toml     # Single source of truth for deps, ruff, pytest
├── mkdocs.yml         # MkDocs config
├── alembic.ini        # Alembic config
├── Dockerfile         # Container build
├── docker-compose.yml # Production stack (PostgreSQL + Nginx)
├── docker-compose.cloud.yml # Cloud deployment stack
├── run.py             # Alternative entrypoint
├── .pre-commit-config.yaml # Pre-commit hooks
├── .env.example       # Environment template
├── .github/           # CI/CD workflows
└── LICENSE            # MIT License

Development Workflow

1. Create a Branch

git checkout -b feature/my-feature
# or
git checkout -b fix/my-bugfix

2. Make Changes

Follow the existing code style and patterns:

  • Services — Business logic goes in src/{domain}/service.py
  • Routes — API routes go in src/{domain}/router.py, dashboard page routes in src/dashboard/
  • Models — SQLAlchemy models in src/{domain}/models.py
  • Schemas — Pydantic schemas in src/{domain}/schemas.py

3. Run Tests

python -m pytest tests/ -v

4. Commit

Write clear, concise commit messages:

git add .
git commit -m "feat: add device toggle endpoint"

5. Push and Create PR

git push origin feature/my-feature

Then open a Pull Request on GitHub.

Code Style

Python

  • Follow PEP 8
  • Use type hints where appropriate
  • Keep functions focused and concise
  • Use snake_case for variables and functions
  • Use PascalCase for classes

Services

All business logic lives in the service layer:

class DeviceService:
    def __init__(self, db: Session):
        self.db = db

    def get_all(self):
        return self.db.query(Device).all()

    def get_by_id(self, device_id: int):
        return self.db.query(Device).filter(Device.id == device_id).first()

Routes

API routes use dependency injection:

@router.get('/devices')
def list_devices(
    db: Session = Depends(get_db),
    current_user: User = Depends(require_user),
):
    devices = DeviceService(db).get_all()
    return devices

Templates

  • Extend base.html
  • Use Tailwind CSS utility classes (compiled from resources/css/app.css)
  • Use HTMX for interactivity and Alpine.js for dropdowns/sidebar state
  • Use inline SVG icons (heroicons) — see docs/developer-guide/frontend.md

Testing

Test Structure

Tests are in the tests/ directory, organized by domain:

tests/
├── auth/
├── devices/
├── sessions/
├── measurements/
├── projects/
├── alerts/
├── audit/
├── benchmark/
├── dashboard/
├── health/
├── settings/
└── conftest.py

Running Tests

# Run all tests
python -m pytest tests/ -v

# Run specific test file
python -m pytest tests/devices/test_devices_routes.py -v

# Run with coverage
python -m pytest tests/ --cov=src --cov-report=term-missing

Writing Tests

Follow existing patterns:

def test_create_device(client, auth_headers):
    response = client.post(
        '/api/v1/devices',
        json={'device_id': 'test-01', 'name': 'Test Device'},
        headers=auth_headers,
    )
    assert response.status_code == 201
    data = response.json()
    assert data['device_id'] == 'test-01'

Documentation

Documentation is built with MkDocs Material:

# Serve locally (MkDocs is installed via `uv sync`)
uv run mkdocs serve

# Build static site
uv run mkdocs build

Adding Pages

  1. Create markdown file in docs/
  2. Add to mkdocs.yml nav
  3. Use ## for sections, ### for subsections

Reporting Issues

Bug Reports

Include:

  • Steps to reproduce
  • Expected behavior
  • Actual behavior
  • Environment (OS, Python version, browser)

Feature Requests

Include:

  • Use case
  • Proposed solution
  • Alternatives considered

License

By contributing, you agree that your contributions will be licensed under the MIT License.