Skip to main content

Backend Getting Started

Learn how to develop with the Boards Python backend SDK.

Overview

The Boards backend is built with:

  • FastAPI - Modern, fast web framework for building APIs
  • Strawberry GraphQL - Code-first GraphQL library with Python type hints
  • SQLAlchemy 2.0 - Python SQL toolkit and ORM
  • PostgreSQL - Relational database with JSON support
  • Redis - In-memory cache and job queue
  • Pydantic - Data validation using Python type annotations

Project Structure

packages/backend/
├── alembic/ # Alembic migrations (async)
│ └── versions/
├── alembic.ini
├── src/boards/
│ ├── api/ # FastAPI application
│ ├── dbmodels/ # ORM models (authoritative)
│ ├── database/ # Connection helpers + compatibility shim
│ ├── graphql/ # GraphQL schema and resolvers
│ ├── providers/
│ ├── generators/
│ ├── storage/
│ └── config.py
└── tests/

Development Workflow

1. Environment Setup

cd packages/backend

# Install dependencies (automatically creates venv and installs dev dependencies)
# Dev dependencies include all providers (OpenAI, Anthropic, etc.) and storage backends for typecheck
uv sync

2. Configuration

Copy the example environment file:

cp .env.example .env

Key configuration options:

# Database
BOARDS_DATABASE_URL=postgresql://boards:boards_dev@localhost:5433/boards_dev

# Redis
BOARDS_REDIS_URL=redis://localhost:6380/0

# Storage
BOARDS_STORAGE_PROVIDER=local
BOARDS_STORAGE_LOCAL_PATH=./uploads

# Authentication
BOARDS_AUTH_PROVIDER=supabase
BOARDS_AUTH_SUPABASE_URL=your_supabase_url
BOARDS_AUTH_SUPABASE_SERVICE_KEY=your_service_key

3. Start Development Server

# Using uvicorn directly
uvicorn boards.api.app:app --reload --port 8088

# Or using the module
python -m boards.api.app

The API will be available at:

Database Development

Alembic-based migrations

Boards uses Alembic with async engines and timestamped filenames. Models live in boards.dbmodels.

  • Create a revision (autogenerate from models):
uv run alembic revision -m "add feature" --autogenerate
  • Apply migrations:
uv run alembic upgrade head
  • Roll back:
uv run alembic downgrade -1

Importing models

# src/boards/graphql/resolvers/user.py
from boards.dbmodels import Users, Boards

GraphQL API

Type Definitions

GraphQL types are defined using Strawberry with Python type hints:

# src/boards/graphql/types/user.py
import strawberry
from typing import List, Optional

@strawberry.type
class User:
id: strawberry.ID
email: str
display_name: str
avatar_url: Optional[str] = None
boards: List["Board"] = strawberry.field(resolver=resolve_user_boards)

Resolvers

# src/boards/graphql/resolvers/user.py
from typing import List
from boards.dbmodels import Users, Boards

def resolve_user_boards(user: Users, info) -> List[Boards]:
return user.boards

Queries and Mutations

# src/boards/graphql/queries/user.py
@strawberry.type
class UserQuery:
@strawberry.field
def user(self, id: strawberry.ID) -> Optional[User]:
return get_user_by_id(id)

@strawberry.type
class UserMutation:
@strawberry.mutation
def update_user(self, id: strawberry.ID, input: UserInput) -> User:
return update_user(id, input)

Provider System

Creating a Provider

# src/boards/providers/my_provider.py
from boards.providers.base import BaseProvider
from typing import Dict, Any, AsyncGenerator

class MyProvider(BaseProvider):
name = "my_provider"

async def generate_image(
self,
prompt: str,
params: Dict[str, Any]
) -> AsyncGenerator[Dict[str, Any], None]:
# Implementation here
yield {"status": "processing", "progress": 50}
yield {"status": "completed", "output": {"url": "..."}}

Registering Providers

# src/boards/providers/__init__.py
from .replicate import ReplicateProvider
from .my_provider import MyProvider

PROVIDERS = {
"replicate": ReplicateProvider,
"my_provider": MyProvider,
}

Code Quality

Pre-commit Hooks

Set up pre-commit hooks to automatically check code quality before commits:

# Install pre-commit hooks (one-time setup)
uv run pre-commit install # Runs on every commit
uv run pre-commit install --hook-type pre-push # Runs before push

# Run all hooks manually
uv run pre-commit run --all-files # Commit hooks
uv run pre-commit run --hook-stage push --all-files # Push hooks (includes tests)

# Run a specific hook
uv run pre-commit run ruff --all-files

On every commit, the hooks automatically:

  • Lint and format Python code with ruff
  • Type check with pyright
  • Lint and type check frontend packages
  • Check for common issues (trailing whitespace, large files, merge conflicts)

Before every push, the hooks automatically:

  • Run all backend tests (pytest)
  • Run all frontend tests (vitest)

Linting

# Run ruff linter
uv run ruff check .

# Auto-fix issues
uv run ruff check . --fix

# Format code
uv run ruff format .

Type Checking

# Run pyright
uv run pyright

# Or use the Makefile
make typecheck-backend

Testing

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=boards --cov-report=html

# Run specific test file
uv run pytest tests/test_api.py

# Run with verbose output
uv run pytest -v

Writing Tests

# tests/test_providers.py
import pytest
from boards.providers.my_provider import MyProvider

@pytest.mark.asyncio
async def test_my_provider_generate_image():
provider = MyProvider()
async for result in provider.generate_image("test prompt", {}):
assert "status" in result

Debugging

Logging Configuration

# src/boards/config.py
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("boards")

Database Debugging

# Enable SQL logging
from sqlalchemy import create_engine
engine = create_engine(database_url, echo=True) # Logs all SQL queries

GraphQL Debugging

Visit http://localhost:8088/graphql to use the GraphiQL interface for testing queries and mutations.

Next Steps