Skip to content

Boards

leadr.boards

Modules:

leadr.boards.adapters

Modules:

  • orm – Board ORM model.
leadr.boards.adapters.orm

Board ORM model.

Classes:

leadr.boards.adapters.orm.BoardORM

Bases: Base

Board ORM model.

Represents a leaderboard/board that belongs to a game in the database. Maps to the boards table with foreign keys to accounts and games, a unique constraint on short_code (globally unique for direct sharing), and a partial unique constraint on (account_id, game_id, slug) for active boards only.

Attributes:

# leadr.boards.adapters.orm.BoardORM.account
account: Mapped[AccountORM] = relationship('AccountORM')
# leadr.boards.adapters.orm.BoardORM.account_id
account_id: Mapped[UUID] = mapped_column(ForeignKey('accounts.id', ondelete='CASCADE'), nullable=False, index=True)
# leadr.boards.adapters.orm.BoardORM.created_at
created_at: Mapped[timestamp]
# leadr.boards.adapters.orm.BoardORM.created_from_template_id
created_from_template_id: Mapped[UUID | None] = mapped_column(nullable=True, default=None)
# leadr.boards.adapters.orm.BoardORM.deleted_at
deleted_at: Mapped[nullable_timestamp]
# leadr.boards.adapters.orm.BoardORM.description
description: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.boards.adapters.orm.BoardORM.ends_at
ends_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, default=None)
# leadr.boards.adapters.orm.BoardORM.game
game: Mapped[GameORM] = relationship('GameORM')
# leadr.boards.adapters.orm.BoardORM.game_id
game_id: Mapped[UUID] = mapped_column(ForeignKey('games.id', ondelete='CASCADE'), nullable=False, index=True)
# leadr.boards.adapters.orm.BoardORM.icon
icon: Mapped[str | None] = mapped_column(String, nullable=True)
# leadr.boards.adapters.orm.BoardORM.id
id: Mapped[uuid_pk]
# leadr.boards.adapters.orm.BoardORM.is_active
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False)
# leadr.boards.adapters.orm.BoardORM.is_published
is_published: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, server_default=(sa.text('true')))
# leadr.boards.adapters.orm.BoardORM.keep_strategy
keep_strategy: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardORM.name
name: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardORM.short_code
short_code: Mapped[str] = mapped_column(String, nullable=False, unique=True, index=True)
# leadr.boards.adapters.orm.BoardORM.slug
slug: Mapped[str] = mapped_column(String, nullable=False, index=True)
# leadr.boards.adapters.orm.BoardORM.sort_direction
sort_direction: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardORM.starts_at
starts_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, default=None)
# leadr.boards.adapters.orm.BoardORM.tags
tags: Mapped[list[str]] = mapped_column(ARRAY(String), nullable=False, default=list, server_default='{}')
# leadr.boards.adapters.orm.BoardORM.template_name
template_name: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.boards.adapters.orm.BoardORM.unit
unit: Mapped[str | None] = mapped_column(String, nullable=True)
# leadr.boards.adapters.orm.BoardORM.updated_at
updated_at: Mapped[timestamp] = mapped_column(onupdate=(func.now()))
leadr.boards.adapters.orm.BoardTemplateORM

Bases: Base

BoardTemplate ORM model.

Represents a template for automatically generating boards at regular intervals. Maps to the board_templates table with foreign keys to accounts and games. Uses JSONB column for config to support flexible procedural generation configuration.

Functions:

  • from_domain – Convert domain entity to ORM model.
  • to_domain – Convert ORM model to domain entity.

Attributes:

# leadr.boards.adapters.orm.BoardTemplateORM.account
account: Mapped[AccountORM] = relationship('AccountORM')
# leadr.boards.adapters.orm.BoardTemplateORM.account_id
account_id: Mapped[UUID] = mapped_column(ForeignKey('accounts.id', ondelete='CASCADE'), nullable=False, index=True)
# leadr.boards.adapters.orm.BoardTemplateORM.config
config: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict, server_default='{}')
# leadr.boards.adapters.orm.BoardTemplateORM.created_at
created_at: Mapped[timestamp]
# leadr.boards.adapters.orm.BoardTemplateORM.deleted_at
deleted_at: Mapped[nullable_timestamp]
# leadr.boards.adapters.orm.BoardTemplateORM.ends_at
ends_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, default=None)
# leadr.boards.adapters.orm.BoardTemplateORM.from_domain
from_domain(entity)

Convert domain entity to ORM model.

Parameters:

  • entity (BoardTemplate) – The BoardTemplate domain entity to convert.

Returns:

  • BoardTemplateORM – BoardTemplateORM model with all fields populated from domain entity.
# leadr.boards.adapters.orm.BoardTemplateORM.game
game: Mapped[GameORM] = relationship('GameORM')
# leadr.boards.adapters.orm.BoardTemplateORM.game_id
game_id: Mapped[UUID] = mapped_column(ForeignKey('games.id', ondelete='CASCADE'), nullable=False, index=True)
# leadr.boards.adapters.orm.BoardTemplateORM.icon
icon: Mapped[str | None] = mapped_column(String, nullable=True)
# leadr.boards.adapters.orm.BoardTemplateORM.id
id: Mapped[uuid_pk]
# leadr.boards.adapters.orm.BoardTemplateORM.is_active
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.is_published
is_published: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, server_default=(sa.text('true')))
# leadr.boards.adapters.orm.BoardTemplateORM.keep_strategy
keep_strategy: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.name
name: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.name_template
name_template: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.boards.adapters.orm.BoardTemplateORM.next_run_at
next_run_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.repeat_interval
repeat_interval: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.series
series: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.boards.adapters.orm.BoardTemplateORM.slug
slug: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.boards.adapters.orm.BoardTemplateORM.sort_direction
sort_direction: Mapped[str] = mapped_column(String, nullable=False)
# leadr.boards.adapters.orm.BoardTemplateORM.starts_at
starts_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, default=None)
# leadr.boards.adapters.orm.BoardTemplateORM.tags
tags: Mapped[list[str]] = mapped_column(ARRAY(String), nullable=False, default=list, server_default='{}')
# leadr.boards.adapters.orm.BoardTemplateORM.to_domain
to_domain()

Convert ORM model to domain entity.

Returns:

  • BoardTemplate – BoardTemplate domain entity with all fields populated from ORM model.
# leadr.boards.adapters.orm.BoardTemplateORM.unit
unit: Mapped[str | None] = mapped_column(String, nullable=True)
# leadr.boards.adapters.orm.BoardTemplateORM.updated_at
updated_at: Mapped[timestamp] = mapped_column(onupdate=(func.now()))

leadr.boards.api

Modules:

leadr.boards.api.board_routes

Board API routes.

Functions:

Attributes:

leadr.boards.api.board_routes.client_router
client_router = APIRouter()
leadr.boards.api.board_routes.create_board
create_board(request, service, auth)

Create a new board.

Creates a new leaderboard associated with an existing game and account. The game must belong to the specified account.

For regular users, account_id must match their API key's account. For superadmins, any account_id is accepted.

Parameters:

Returns:

  • BoardResponse – BoardResponse with the created board including auto-generated ID and timestamps.

Raises:

  • 403 – User does not have access to the specified account.
  • 404 – Game or account not found.
  • 400 – Game doesn't belong to the specified account.
leadr.boards.api.board_routes.get_board
get_board(board_id, service, auth)

Get a board by ID.

Parameters:

Returns:

Raises:

  • 403 – User does not have access to this board's account.
  • 404 – Board not found.
leadr.boards.api.board_routes.handle_list_boards
handle_list_boards(auth, service, game_service, pagination, account_id, game_id, code, game_slug, slug, is_active, is_published, starts_before, starts_after, ends_before, ends_after)

Shared handler for listing boards with filtering.

Parameters:

  • auth (AuthContext) – Authentication context with user info.
  • service (BoardService) – Board service instance.
  • game_service (GameService) – Game service instance for game_slug resolution.
  • pagination (PaginationParams) – Pagination parameters (cursor, limit, sort).
  • account_id (AccountID | None) – Optional account ID to filter boards by.
  • game_id (GameID | None) – Optional game ID to filter boards by.
  • code (str | None) – Optional short code to filter boards by.
  • game_slug (str | None) – Optional game slug to filter boards by game (resolves to game_id).
  • slug (str | None) – Optional board slug to filter by specific board (requires game_slug).
  • is_active (bool | None) – Optional filter for active status.
  • is_published (bool | None) – Optional filter for published status.
  • starts_before (datetime | None) – Optional filter for boards starting before this time.
  • starts_after (datetime | None) – Optional filter for boards starting after this time.
  • ends_before (datetime | None) – Optional filter for boards ending before this time.
  • ends_after (datetime | None) – Optional filter for boards ending after this time.

Returns:

Raises:

  • 400 – Invalid cursor, sort field, or cursor state mismatch.
  • 404 – Game or board not found when using slug filters.
leadr.boards.api.board_routes.list_boards_admin
list_boards_admin(auth, service, game_service, pagination, account_id=None, game_id=None, code=None, game_slug=None, slug=None, is_active=None, is_published=None, starts_before=None, starts_after=None, ends_before=None, ends_after=None)

List boards (Admin API).

For regular users:

  • If account_id not provided, defaults to their API key's account
  • If account_id provided and they are superadmin, can access any account
  • If account_id provided and NOT superadmin, must match their account (validated in AuthContext)

Filtering:

  • Use ?game_id={id} or ?game_slug={slug} to filter boards by game
  • Use ?game_slug={game_slug}&slug={slug} to find a specific board within a game
  • Use ?code={code} to filter boards by short code
  • Use ?is_active=true/false to filter by active status
  • Use ?is_published=true/false to filter by published status
  • Use ?starts_before=&starts_after= for start date range
  • Use ?ends_before=&ends_after= for end date range
  • Note: board slug filter requires game_slug parameter

Pagination:

  • Default: 20 items per page, sorted by created_at:desc,id:asc
  • Custom sort: Use ?sort=name:asc,created_at:desc
  • Valid sort fields: id, name, slug, short_code, created_at, updated_at
  • Navigation: Use next_cursor/prev_cursor from response
Example GET /v1/boards?account_id=acc_123&limit=50&sort=name:asc GET /v1/boards?game_slug=my-game&is_active=true GET /v1/boards?game_slug=my-game&slug=weekly-challenge GET /v1/boards?starts_after=2025-01-01T00:00:00Z&ends_before=2025-12-31T23:59:59Z

Parameters:

  • auth (AdminAuthContextDep) – Admin authentication context with user info.
  • service (BoardServiceDep) – Injected board service dependency.
  • game_service (GameServiceDep) – Injected game service dependency.
  • pagination (Annotated[PaginationParams, Depends()]) – Pagination parameters (cursor, limit, sort).
  • account_id (Annotated[AccountID | None, Query(description='Filter by account ID')]) – Optional account ID to filter boards by.
  • game_id (Annotated[GameID | None, Query(description='Filter by game ID')]) – Optional game ID to filter boards by.
  • code (Annotated[str | None, Query(description='Filter by short code')]) – Optional short code to filter boards by.
  • game_slug (Annotated[str | None, Query(description='Filter by game slug')]) – Optional game slug to filter boards by game (resolves to game_id).
  • slug (Annotated[str | None, Query(description='Filter by board slug (requires game_slug)')]) – Optional board slug to filter by specific board (requires game_slug).
  • is_active (Annotated[bool | None, Query(description='Filter by active status')]) – Optional filter for active status.
  • is_published (Annotated[bool | None, Query(description='Filter by published status')]) – Optional filter for published status.
  • starts_before (Annotated[datetime | None, Query(description='Filter boards starting before this time (ISO 8601)')]) – Optional filter for boards starting before this time.
  • starts_after (Annotated[datetime | None, Query(description='Filter boards starting after this time (ISO 8601)')]) – Optional filter for boards starting after this time.
  • ends_before (Annotated[datetime | None, Query(description='Filter boards ending before this time (ISO 8601)')]) – Optional filter for boards ending before this time.
  • ends_after (Annotated[datetime | None, Query(description='Filter boards ending after this time (ISO 8601)')]) – Optional filter for boards ending after this time.

Returns:

Raises:

  • 400 – Invalid cursor, sort field, cursor state mismatch, or slug without game_slug.
  • 404 – Game or board not found when using slug filters.
leadr.boards.api.board_routes.list_boards_client
list_boards_client(auth, service, game_service, pagination, game_id=None, code=None, game_slug=None, slug=None, is_active=None, is_published=None, starts_before=None, starts_after=None, ends_before=None, ends_after=None)

List boards (Client API).

Account ID is automatically derived from the authenticated device's account. Clients can optionally filter by various criteria to find specific boards.

Filtering:

  • Use ?game_id={id} or ?game_slug={slug} to filter boards by game
  • Use ?game_slug={game_slug}&slug={slug} to find a specific board within a game
  • Use ?code={code} to filter boards by short code
  • Use ?is_active=true/false to filter by active status
  • Use ?is_published=true/false to filter by published status
  • Use ?starts_before=&starts_after= for start date range
  • Use ?ends_before=&ends_after= for end date range
  • Note: board slug filter requires game_slug parameter

Pagination:

  • Default: 20 items per page, sorted by created_at:desc,id:asc
  • Custom sort: Use ?sort=name:asc,created_at:desc
  • Valid sort fields: id, name, slug, short_code, created_at, updated_at
  • Navigation: Use next_cursor/prev_cursor from response
Example GET /v1/client/boards?code=WEEKLY-CHALLENGE&limit=50 GET /v1/client/boards?game_slug=my-game&is_active=true GET /v1/client/boards?game_slug=my-game&slug=weekly-challenge GET /v1/client/boards?starts_after=2025-01-01T00:00:00Z

Parameters:

  • auth (ClientAuthContextDep) – Client authentication context with device info.
  • service (BoardServiceDep) – Injected board service dependency.
  • game_service (GameServiceDep) – Injected game service dependency.
  • pagination (Annotated[PaginationParams, Depends()]) – Pagination parameters (cursor, limit, sort).
  • game_id (Annotated[GameID | None, Query(description='Filter by game ID')]) – Optional game ID to filter boards by.
  • code (Annotated[str | None, Query(description='Filter by short code')]) – Optional short code to filter boards by.
  • game_slug (Annotated[str | None, Query(description='Filter by game slug')]) – Optional game slug to filter boards by game (resolves to game_id).
  • slug (Annotated[str | None, Query(description='Filter by board slug (requires game_slug)')]) – Optional board slug to filter by specific board (requires game_slug).
  • is_active (Annotated[bool | None, Query(description='Filter by active status')]) – Optional filter for active status.
  • is_published (Annotated[bool | None, Query(description='Filter by published status')]) – Optional filter for published status.
  • starts_before (Annotated[datetime | None, Query(description='Filter boards starting before this time (ISO 8601)')]) – Optional filter for boards starting before this time.
  • starts_after (Annotated[datetime | None, Query(description='Filter boards starting after this time (ISO 8601)')]) – Optional filter for boards starting after this time.
  • ends_before (Annotated[datetime | None, Query(description='Filter boards ending before this time (ISO 8601)')]) – Optional filter for boards ending before this time.
  • ends_after (Annotated[datetime | None, Query(description='Filter boards ending after this time (ISO 8601)')]) – Optional filter for boards ending after this time.

Returns:

Raises:

  • 400 – Invalid cursor, sort field, cursor state mismatch, or slug without game_slug.
  • 404 – Game or board not found when using slug filters.
leadr.boards.api.board_routes.logger
logger = logging.getLogger(__name__)
leadr.boards.api.board_routes.router
router = APIRouter()
leadr.boards.api.board_routes.update_board
update_board(board_id, request, service, auth)

Update a board.

Supports updating any board field or soft-deleting the board.

Parameters:

Returns:

  • BoardResponse – BoardResponse with the updated board details.

Raises:

  • 403 – User does not have access to this board's account.
  • 404 – Board not found.
leadr.boards.api.board_schemas

API request and response models for boards.

Classes:

leadr.boards.api.board_schemas.BoardCreateRequest

Bases: BaseModel

Request model for creating a board.

Attributes:

# leadr.boards.api.board_schemas.BoardCreateRequest.account_id
account_id: AccountID = Field(description='ID of the account this board belongs to')
# leadr.boards.api.board_schemas.BoardCreateRequest.created_from_template_id
created_from_template_id: BoardTemplateID | None = Field(default=None, description='Optional template ID this board was created from')
# leadr.boards.api.board_schemas.BoardCreateRequest.description
description: str | None = Field(default=None, description='Optional short description of the board')
# leadr.boards.api.board_schemas.BoardCreateRequest.ends_at
ends_at: datetime | None = Field(default=None, description='Optional end time for time-bounded boards (UTC)')
# leadr.boards.api.board_schemas.BoardCreateRequest.game_id
game_id: GameID = Field(description='ID of the game this board belongs to')
# leadr.boards.api.board_schemas.BoardCreateRequest.icon
icon: str | None = Field(default='fa-crown', description="Icon identifier for the board. Defaults to 'fa-crown'")
# leadr.boards.api.board_schemas.BoardCreateRequest.is_active
is_active: bool = Field(default=True, description='Whether the board is currently active')
# leadr.boards.api.board_schemas.BoardCreateRequest.is_published
is_published: bool = Field(default=True, description='Whether the board is published and visible on public web views')
# leadr.boards.api.board_schemas.BoardCreateRequest.keep_strategy
keep_strategy: KeepStrategy = Field(default=(KeepStrategy.ALL), description='Strategy for keeping multiple scores from the same user')
# leadr.boards.api.board_schemas.BoardCreateRequest.name
name: str = Field(description='Name of the board')
# leadr.boards.api.board_schemas.BoardCreateRequest.short_code
short_code: str | None = Field(default=None, description='Globally unique short code for direct sharing. Auto-generated if not provided')
# leadr.boards.api.board_schemas.BoardCreateRequest.slug
slug: str | None = Field(default=None, description='Optional URL-friendly slug. If not provided, will be auto-generated from name')
# leadr.boards.api.board_schemas.BoardCreateRequest.sort_direction
sort_direction: SortDirection = Field(default=(SortDirection.DESCENDING), description='Direction to sort scores')
# leadr.boards.api.board_schemas.BoardCreateRequest.starts_at
starts_at: datetime | None = Field(default=None, description='Optional start time for time-bounded boards (UTC)')
# leadr.boards.api.board_schemas.BoardCreateRequest.tags
tags: list[str] | None = Field(default=None, description='Optional list of tags for categorization')
# leadr.boards.api.board_schemas.BoardCreateRequest.template_name
template_name: str | None = Field(default=None, description='Optional template name this board was created from')
# leadr.boards.api.board_schemas.BoardCreateRequest.unit
unit: str | None = Field(default=None, description="Unit of measurement for scores (e.g., 'seconds', 'points'). Optional")
leadr.boards.api.board_schemas.BoardResponse

Bases: BaseModel

Response model for a board.

Functions:

  • from_domain – Convert domain entity to response model.

Attributes:

# leadr.boards.api.board_schemas.BoardResponse.account_id
account_id: AccountID = Field(description='ID of the account this board belongs to')
# leadr.boards.api.board_schemas.BoardResponse.created_at
created_at: datetime = Field(description='Timestamp when the board was created (UTC)')
# leadr.boards.api.board_schemas.BoardResponse.created_from_template_id
created_from_template_id: BoardTemplateID | None = Field(default=None, description='Template ID this board was created from, or null')
# leadr.boards.api.board_schemas.BoardResponse.description
description: str | None = Field(default=None, description='Short description of the board')
# leadr.boards.api.board_schemas.BoardResponse.ends_at
ends_at: datetime | None = Field(default=None, description='End time for time-bounded boards (UTC)')
# leadr.boards.api.board_schemas.BoardResponse.from_domain
from_domain(board)

Convert domain entity to response model.

Parameters:

  • board (Board) – The domain Board entity to convert.

Returns:

  • BoardResponse – BoardResponse with all fields populated from the domain entity.
# leadr.boards.api.board_schemas.BoardResponse.game_id
game_id: GameID = Field(description='ID of the game this board belongs to')
# leadr.boards.api.board_schemas.BoardResponse.icon
icon: str | None = Field(description='Icon identifier for the board, or null')
# leadr.boards.api.board_schemas.BoardResponse.id
id: BoardID = Field(description='Unique identifier for the board')
# leadr.boards.api.board_schemas.BoardResponse.is_active
is_active: bool = Field(description='Whether the board is currently active')
# leadr.boards.api.board_schemas.BoardResponse.is_published
is_published: bool = Field(description='Whether the board is published and visible on public web views')
# leadr.boards.api.board_schemas.BoardResponse.keep_strategy
keep_strategy: KeepStrategy = Field(description='Strategy for keeping scores from same user')
# leadr.boards.api.board_schemas.BoardResponse.name
name: str = Field(description='Name of the board')
# leadr.boards.api.board_schemas.BoardResponse.short_code
short_code: str = Field(description='Globally unique short code for direct sharing')
# leadr.boards.api.board_schemas.BoardResponse.slug
slug: str = Field(description='URL-friendly slug for the board (auto-generated, read-only)')
# leadr.boards.api.board_schemas.BoardResponse.sort_direction
sort_direction: SortDirection = Field(description='Direction to sort scores')
# leadr.boards.api.board_schemas.BoardResponse.starts_at
starts_at: datetime | None = Field(default=None, description='Start time for time-bounded boards (UTC)')
# leadr.boards.api.board_schemas.BoardResponse.tags
tags: list[str] = Field(default_factory=list, description='List of tags for categorization')
# leadr.boards.api.board_schemas.BoardResponse.template_name
template_name: str | None = Field(default=None, description='Template name this board was created from, or null')
# leadr.boards.api.board_schemas.BoardResponse.unit
unit: str | None = Field(description='Unit of measurement for scores, or null')
# leadr.boards.api.board_schemas.BoardResponse.updated_at
updated_at: datetime = Field(description='Timestamp of last update (UTC)')
leadr.boards.api.board_schemas.BoardUpdateRequest

Bases: BaseModel

Request model for updating a board.

Attributes:

# leadr.boards.api.board_schemas.BoardUpdateRequest.created_from_template_id
created_from_template_id: BoardTemplateID | None = Field(default=None, description='Updated template ID')
# leadr.boards.api.board_schemas.BoardUpdateRequest.deleted
deleted: bool | None = Field(default=None, description='Set to true to soft delete the board')
# leadr.boards.api.board_schemas.BoardUpdateRequest.description
description: str | None = Field(default=None, description='Updated board description')
# leadr.boards.api.board_schemas.BoardUpdateRequest.ends_at
ends_at: datetime | None = Field(default=None, description='Updated end time')
# leadr.boards.api.board_schemas.BoardUpdateRequest.icon
icon: str | None = Field(default=None, description='Updated icon identifier')
# leadr.boards.api.board_schemas.BoardUpdateRequest.is_active
is_active: bool | None = Field(default=None, description='Updated active status')
# leadr.boards.api.board_schemas.BoardUpdateRequest.is_published
is_published: bool | None = Field(default=None, description='Updated published status')
# leadr.boards.api.board_schemas.BoardUpdateRequest.keep_strategy
keep_strategy: KeepStrategy | None = Field(default=None, description='Updated keep strategy')
# leadr.boards.api.board_schemas.BoardUpdateRequest.name
name: str | None = Field(default=None, description='Updated board name')
# leadr.boards.api.board_schemas.BoardUpdateRequest.short_code
short_code: str | None = Field(default=None, description='Updated short code')
# leadr.boards.api.board_schemas.BoardUpdateRequest.sort_direction
sort_direction: SortDirection | None = Field(default=None, description='Updated sort direction')
# leadr.boards.api.board_schemas.BoardUpdateRequest.starts_at
starts_at: datetime | None = Field(default=None, description='Updated start time')
# leadr.boards.api.board_schemas.BoardUpdateRequest.tags
tags: list[str] | None = Field(default=None, description='Updated tags list')
# leadr.boards.api.board_schemas.BoardUpdateRequest.template_name
template_name: str | None = Field(default=None, description='Updated template name')
# leadr.boards.api.board_schemas.BoardUpdateRequest.unit
unit: str | None = Field(default=None, description='Updated unit of measurement')
leadr.boards.api.board_template_routes

Board template API routes.

Functions:

Attributes:

leadr.boards.api.board_template_routes.create_board_template
create_board_template(request, service, auth)

Create a new board template.

Creates a template for automatically generating boards at regular intervals. The game must belong to the specified account.

For regular users, account_id must match their API key's account. For superadmins, any account_id is accepted.

Parameters:

Returns:

Raises:

  • 403 – User does not have access to the specified account.
  • 404 – Game or account not found.
  • 400 – Game doesn't belong to the specified account.
leadr.boards.api.board_template_routes.get_board_template
get_board_template(template_id, service, auth)

Get a board template by ID.

Parameters:

Returns:

Raises:

  • 403 – User does not have access to this template's account.
  • 404 – Template not found.
leadr.boards.api.board_template_routes.list_board_templates
list_board_templates(auth, service, pagination, account_id=None, game_id=None)

List board templates for an account with pagination, optionally filtered by game.

For regular users, account_id is automatically derived from their API key. For superadmins, account_id is optional - if omitted, returns templates from all accounts.

Pagination:

  • Default: 20 items per page, sorted by created_at:desc,id:asc
  • Custom sort: Use ?sort=name:asc,created_at:desc
  • Valid sort fields: id, name, created_at, updated_at
  • Navigation: Use next_cursor/prev_cursor from response
Example GET /v1/board-templates?account_id=acc_123&game_id=gam_456&limit=50&sort=name:asc

Parameters:

Returns:

Raises:

  • 400 – Invalid cursor, sort field, or cursor state mismatch.
  • 403 – User does not have access to the specified account.
leadr.boards.api.board_template_routes.router
router = APIRouter()
leadr.boards.api.board_template_routes.update_board_template
update_board_template(template_id, request, service, auth)

Update a board template.

Supports updating any template field or soft-deleting the template.

Parameters:

Returns:

Raises:

  • 403 – User does not have access to this template's account.
  • 404 – Template not found.
leadr.boards.api.board_template_schemas

API request and response models for board templates.

Classes:

leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest

Bases: BaseModel

Request model for creating a board template.

Attributes:

# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.account_id
account_id: AccountID = Field(description='ID of the account this template belongs to')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.config
config: dict[str, Any] | None = Field(default=None, description='Reserved for future procedural generation (bounds, variables, randomization rules)')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.ends_at
ends_at: datetime | None = Field(default=None, description='Optional end time for time-bounded boards')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.game_id
game_id: GameID = Field(description='ID of the game this template belongs to')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.icon
icon: str | None = Field(default='fa-crown', description='Icon identifier for boards created from this template')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.is_active
is_active: bool = Field(description='Whether the template is currently active')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.is_published
is_published: bool = Field(default=True, description='Whether boards created from this template should be published')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.keep_strategy
keep_strategy: KeepStrategy = Field(default=(KeepStrategy.ALL), description='Strategy for keeping multiple scores from the same user')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.name
name: str = Field(description='Name of the template')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.name_template
name_template: str | None = Field(default=None, description='Optional template string for generating board names')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.next_run_at
next_run_at: datetime = Field(description='Next scheduled time to create a board from this template (UTC)')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.repeat_interval
repeat_interval: str = Field(description="PostgreSQL interval syntax for repeat frequency (e.g., '7 days', '1 month')")
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.series
series: str | None = Field(default=None, description='Optional series identifier for sequential board naming')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.slug
slug: str | None = Field(default=None, description='URL-friendly slug for boards created from this template')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.sort_direction
sort_direction: SortDirection = Field(default=(SortDirection.DESCENDING), description='Direction to sort scores (ascending/descending)')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.starts_at
starts_at: datetime | None = Field(default=None, description='Optional start time for time-bounded boards')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.tags
tags: list[str] | None = Field(default=None, description='List of tags for categorizing boards created from this template')
# leadr.boards.api.board_template_schemas.BoardTemplateCreateRequest.unit
unit: str | None = Field(default=None, description="Unit of measurement for scores (e.g., 'seconds', 'points')")
leadr.boards.api.board_template_schemas.BoardTemplateResponse

Bases: BaseModel

Response model for a board template.

Functions:

  • from_domain – Convert domain entity to response model.

Attributes:

# leadr.boards.api.board_template_schemas.BoardTemplateResponse.account_id
account_id: AccountID = Field(description='ID of the account this template belongs to')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.config
config: dict[str, Any] = Field(default_factory=dict, description='Reserved for future procedural generation (bounds, variables, randomization rules)')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.created_at
created_at: datetime = Field(description='Timestamp when the template was created (UTC)')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.ends_at
ends_at: datetime | None = Field(description='Optional end time for time-bounded boards')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.from_domain
from_domain(template)

Convert domain entity to response model.

Parameters:

  • template (BoardTemplate) – The domain BoardTemplate entity to convert.

Returns:

# leadr.boards.api.board_template_schemas.BoardTemplateResponse.game_id
game_id: GameID = Field(description='ID of the game this template belongs to')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.icon
icon: str | None = Field(description='Icon identifier for boards created from this template')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.id
id: BoardTemplateID = Field(description='Unique identifier for the template')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.is_active
is_active: bool = Field(description='Whether the template is currently active')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.is_published
is_published: bool = Field(description='Whether boards created from this template should be published')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.keep_strategy
keep_strategy: KeepStrategy = Field(description='Strategy for keeping multiple scores from the same user')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.name
name: str = Field(description='Name of the template')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.name_template
name_template: str | None = Field(default=None, description='Template string for generating board names, or null')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.next_run_at
next_run_at: datetime = Field(description='Next scheduled run time (UTC)')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.repeat_interval
repeat_interval: str = Field(description='Repeat frequency in PostgreSQL interval syntax')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.series
series: str | None = Field(default=None, description='Series identifier for sequential board naming, or null')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.slug
slug: str | None = Field(description='URL-friendly slug for boards created from this template, or null')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.sort_direction
sort_direction: SortDirection = Field(description='Direction to sort scores (ascending/descending)')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.starts_at
starts_at: datetime | None = Field(description='Optional start time for time-bounded boards')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.tags
tags: list[str] = Field(description='List of tags for categorizing boards created from this template')
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.unit
unit: str | None = Field(description="Unit of measurement for scores (e.g., 'seconds', 'points')")
# leadr.boards.api.board_template_schemas.BoardTemplateResponse.updated_at
updated_at: datetime = Field(description='Timestamp of last update (UTC)')
leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest

Bases: BaseModel

Request model for updating a board template.

Attributes:

# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.config
config: dict[str, Any] | None = Field(default=None, description='Updated config (reserved for procedural generation)')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.deleted
deleted: bool | None = Field(default=None, description='Set to true to soft delete the template')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.ends_at
ends_at: datetime | None = Field(default=None, description='Updated end time')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.icon
icon: str | None = Field(default=None, description='Updated icon identifier')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.is_active
is_active: bool | None = Field(default=None, description='Updated active status')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.is_published
is_published: bool | None = Field(default=None, description='Updated published status')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.keep_strategy
keep_strategy: KeepStrategy | None = Field(default=None, description='Updated keep strategy')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.name
name: str | None = Field(default=None, description='Updated template name')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.name_template
name_template: str | None = Field(default=None, description='Updated name template')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.next_run_at
next_run_at: datetime | None = Field(default=None, description='Updated next run time')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.repeat_interval
repeat_interval: str | None = Field(default=None, description='Updated repeat interval')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.series
series: str | None = Field(default=None, description='Updated series identifier')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.slug
slug: str | None = Field(default=None, description='Updated slug')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.sort_direction
sort_direction: SortDirection | None = Field(default=None, description='Updated sort direction')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.starts_at
starts_at: datetime | None = Field(default=None, description='Updated start time')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.tags
tags: list[str] | None = Field(default=None, description='Updated tags list')
# leadr.boards.api.board_template_schemas.BoardTemplateUpdateRequest.unit
unit: str | None = Field(default=None, description='Updated unit of measurement')

leadr.boards.domain

Modules:

leadr.boards.domain.board

Board domain model.

Classes:

leadr.boards.domain.board.Board

Bases: Entity

Board domain entity.

Represents a leaderboard/board that belongs to a game. Boards define how scores are tracked, sorted, and displayed. Each board has a globally unique short_code for direct sharing and can be time-bounded with start/end dates.

Each board belongs to exactly one game and inherits the game's account for multi-tenancy. Boards can be created from templates and can have custom tags for categorization.

Functions:

Attributes:

# leadr.boards.domain.board.Board.account_id
account_id: AccountID = Field(frozen=True, description='ID of the account this board belongs to (immutable)')
# leadr.boards.domain.board.Board.created_at
created_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp when entity was created (UTC)')
# leadr.boards.domain.board.Board.created_from_template_id
created_from_template_id: BoardTemplateID | None = Field(default=None, description='Optional template ID this board was created from')
# leadr.boards.domain.board.Board.deleted_at
deleted_at: datetime | None = Field(default=None, description='Timestamp when entity was soft-deleted (UTC), or null if active')
# leadr.boards.domain.board.Board.description
description: str | None = Field(default=None, description='Short description of the board')
# leadr.boards.domain.board.Board.ends_at
ends_at: datetime | None = Field(default=None, description='Optional end time for time-bounded boards')
# leadr.boards.domain.board.Board.game_id
game_id: GameID = Field(frozen=True, description='ID of the game this board belongs to (immutable)')
# leadr.boards.domain.board.Board.icon
icon: str | None = Field(description='Icon identifier for the board', default='fa-crown')
# leadr.boards.domain.board.Board.id
id: BoardID = Field(frozen=True, default_factory=BoardID, description='Unique board identifier')
# leadr.boards.domain.board.Board.is_active
is_active: bool = Field(description='Whether the board is currently active', default=True)
# leadr.boards.domain.board.Board.is_deleted
is_deleted: bool

Check if entity is soft-deleted.

Returns:

  • bool – True if the entity has a deleted_at timestamp, False otherwise.
# leadr.boards.domain.board.Board.is_published
is_published: bool = Field(description='Whether the board is published and visible on public web views', default=True)
# leadr.boards.domain.board.Board.keep_strategy
keep_strategy: KeepStrategy = Field(description='Strategy for keeping multiple scores from the same user', default=(KeepStrategy.ALL))
# leadr.boards.domain.board.Board.model_config
model_config = ConfigDict(validate_assignment=True)
# leadr.boards.domain.board.Board.name
name: str = Field(description='Name of the board')
# leadr.boards.domain.board.Board.restore
restore()

Restore a soft-deleted entity.

Clears the deleted_at timestamp, making the entity active again.

Example > > > account.soft_delete() > > > account.restore() > > > assert account.is_deleted is False
# leadr.boards.domain.board.Board.short_code
short_code: str = Field(description='Globally unique short code for direct board sharing')
# leadr.boards.domain.board.Board.slug
slug: str = Field(description='URL-friendly slug for the board (unique per game when active)')
# leadr.boards.domain.board.Board.soft_delete
soft_delete()

Mark entity as soft-deleted.

Sets the deleted_at timestamp to the current UTC time. Entities that are already deleted are not affected (deleted_at remains at original deletion time).

Example > > > account = Account(name="Test", slug="test") > > > account.soft_delete() > > > assert account.is_deleted is True
# leadr.boards.domain.board.Board.sort_direction
sort_direction: SortDirection = Field(description='Direction to sort scores (ascending/descending)', default=(SortDirection.DESCENDING))
# leadr.boards.domain.board.Board.starts_at
starts_at: datetime | None = Field(default=None, description='Optional start time for time-bounded boards')
# leadr.boards.domain.board.Board.tags
tags: list[str] = Field(default_factory=list, description='List of tags for categorizing the board')
# leadr.boards.domain.board.Board.template_name
template_name: str | None = Field(default=None, description='Optional name of the template this board was created from')
# leadr.boards.domain.board.Board.unit
unit: str | None = Field(description="Unit of measurement for scores (e.g., 'seconds', 'points')", default=None)
# leadr.boards.domain.board.Board.updated_at
updated_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp of last update (UTC)')
# leadr.boards.domain.board.Board.validate_name
validate_name(value)

Validate board name is not empty.

Parameters:

  • value (str) – The board name to validate.

Returns:

  • str – The validated and trimmed board name.

Raises:

  • ValueError – If board name is empty or whitespace only.
# leadr.boards.domain.board.Board.validate_short_code
validate_short_code(value)

Validate short_code is not empty.

Parameters:

  • value (str) – The short_code to validate.

Returns:

  • str – The validated and trimmed short_code.

Raises:

  • ValueError – If short_code is empty or whitespace only.
# leadr.boards.domain.board.Board.validate_slug
validate_slug(value)

Validate slug format (lowercase alphanumeric with hyphens).

Parameters:

  • value (str) – The slug to validate.

Returns:

  • str – The validated slug.

Raises:

leadr.boards.domain.board.KeepStrategy

Bases: str, Enum

Strategy for keeping scores from the same user.

Attributes:

# leadr.boards.domain.board.KeepStrategy.ALL
ALL = 'ALL'
# leadr.boards.domain.board.KeepStrategy.BEST_ONLY
BEST_ONLY = 'BEST_ONLY'
# leadr.boards.domain.board.KeepStrategy.FIRST_ONLY
FIRST_ONLY = 'FIRST_ONLY'
# leadr.boards.domain.board.KeepStrategy.LATEST_ONLY
LATEST_ONLY = 'LATEST_ONLY'
leadr.boards.domain.board.SortDirection

Bases: str, Enum

Sort direction for board scores.

Attributes:

# leadr.boards.domain.board.SortDirection.ASCENDING
ASCENDING = 'ASCENDING'
# leadr.boards.domain.board.SortDirection.DESCENDING
DESCENDING = 'DESCENDING'
leadr.boards.domain.board_template

BoardTemplate domain model.

Classes:

leadr.boards.domain.board_template.BoardTemplate

Bases: Entity

BoardTemplate domain entity.

Represents a template for automatically generating boards at regular intervals. Templates belong to a game and define the configuration for boards that will be created by the pg_cron scheduler.

Each template specifies a repeat interval (PostgreSQL interval syntax), configuration for boards to be created, and can optionally use template variables in the name generation. Templates can be activated/deactivated and track the next scheduled run.

Functions:

Attributes:

# leadr.boards.domain.board_template.BoardTemplate.account_id
account_id: AccountID = Field(frozen=True, description='ID of the account this template belongs to (immutable)')
# leadr.boards.domain.board_template.BoardTemplate.config
config: dict[str, Any] = Field(default_factory=dict, description='Reserved for future procedural generation (bounds, variables, randomization rules)')
# leadr.boards.domain.board_template.BoardTemplate.created_at
created_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp when entity was created (UTC)')
# leadr.boards.domain.board_template.BoardTemplate.deleted_at
deleted_at: datetime | None = Field(default=None, description='Timestamp when entity was soft-deleted (UTC), or null if active')
# leadr.boards.domain.board_template.BoardTemplate.ends_at
ends_at: datetime | None = Field(default=None, description='Optional end time for time-bounded boards')
# leadr.boards.domain.board_template.BoardTemplate.game_id
game_id: GameID = Field(frozen=True, description='ID of the game this template belongs to (immutable)')
# leadr.boards.domain.board_template.BoardTemplate.generate_name
generate_name(timestamp, series_value)

Generate a board name using the name template.

If name_template is None, returns the template's name. Otherwise, substitutes placeholders with values derived from the timestamp and series.

Supported placeholders:

  • {year}: 4-digit year (e.g., 2025)
  • {month}: Full month name (e.g., July)
  • {month_short}: Abbreviated month (e.g., Jul)
  • {week}: ISO week number (e.g., 29)
  • {quarter}: Quarter (e.g., Q1, Q2, Q3, Q4)
  • {date}: ISO date (e.g., 2025-07-15)
  • {series}: Sequential series value

Parameters:

  • timestamp (datetime) – The datetime to use for generating time-based placeholders.
  • series_value (int | None) – Optional series value for {series} placeholder.

Returns:

  • str – The generated board name.

Raises:

  • ValueError – If the name_template contains invalid placeholders or if {series} is used but series_value is None.
# leadr.boards.domain.board_template.BoardTemplate.icon
icon: str | None = Field(description='Icon identifier for boards created from this template', default='fa-crown')
# leadr.boards.domain.board_template.BoardTemplate.id
id: BoardTemplateID = Field(frozen=True, default_factory=BoardTemplateID, description='Unique board template identifier')
# leadr.boards.domain.board_template.BoardTemplate.is_active
is_active: bool = Field(description='Whether the template is currently active')
# leadr.boards.domain.board_template.BoardTemplate.is_deleted
is_deleted: bool

Check if entity is soft-deleted.

Returns:

  • bool – True if the entity has a deleted_at timestamp, False otherwise.
# leadr.boards.domain.board_template.BoardTemplate.is_published
is_published: bool = Field(description='Whether boards created from this template should be published', default=True)
# leadr.boards.domain.board_template.BoardTemplate.keep_strategy
keep_strategy: KeepStrategy = Field(description='Strategy for keeping multiple scores from the same user', default=(KeepStrategy.ALL))
# leadr.boards.domain.board_template.BoardTemplate.model_config
model_config = ConfigDict(validate_assignment=True)
# leadr.boards.domain.board_template.BoardTemplate.name
name: str = Field(description='Name of the template')
# leadr.boards.domain.board_template.BoardTemplate.name_template
name_template: str | None = Field(default=None, description='Optional template string for generating board names')
# leadr.boards.domain.board_template.BoardTemplate.next_run_at
next_run_at: datetime = Field(description='Next scheduled time to create a board from this template')
# leadr.boards.domain.board_template.BoardTemplate.repeat_interval
repeat_interval: str = Field(description="PostgreSQL interval syntax for repeat frequency (e.g., '7 days', '1 month')")
# leadr.boards.domain.board_template.BoardTemplate.restore
restore()

Restore a soft-deleted entity.

Clears the deleted_at timestamp, making the entity active again.

Example > > > account.soft_delete() > > > account.restore() > > > assert account.is_deleted is False
# leadr.boards.domain.board_template.BoardTemplate.series
series: str | None = Field(default=None, description="Optional series identifier for sequential board naming (e.g., 'weekly', 'seasonal')")
# leadr.boards.domain.board_template.BoardTemplate.slug
slug: str | None = Field(default=None, description='URL-friendly slug for boards created from this template')
# leadr.boards.domain.board_template.BoardTemplate.soft_delete
soft_delete()

Mark entity as soft-deleted.

Sets the deleted_at timestamp to the current UTC time. Entities that are already deleted are not affected (deleted_at remains at original deletion time).

Example > > > account = Account(name="Test", slug="test") > > > account.soft_delete() > > > assert account.is_deleted is True
# leadr.boards.domain.board_template.BoardTemplate.sort_direction
sort_direction: SortDirection = Field(description='Direction to sort scores (ascending/descending)', default=(SortDirection.DESCENDING))
# leadr.boards.domain.board_template.BoardTemplate.starts_at
starts_at: datetime | None = Field(default=None, description='Optional start time for time-bounded boards')
# leadr.boards.domain.board_template.BoardTemplate.tags
tags: list[str] = Field(default_factory=list, description='List of tags for categorizing boards created from this template')
# leadr.boards.domain.board_template.BoardTemplate.unit
unit: str | None = Field(description="Unit of measurement for scores (e.g., 'seconds', 'points')", default=None)
# leadr.boards.domain.board_template.BoardTemplate.updated_at
updated_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp of last update (UTC)')
# leadr.boards.domain.board_template.BoardTemplate.validate_name
validate_name(value)

Validate template name is not empty.

Parameters:

  • value (str) – The template name to validate.

Returns:

  • str – The validated and trimmed template name.

Raises:

  • ValueError – If template name is empty or whitespace only.
# leadr.boards.domain.board_template.BoardTemplate.validate_repeat_interval
validate_repeat_interval(value)

Validate repeat_interval uses PostgreSQL interval syntax.

Parameters:

  • value (str) – The interval string to validate.

Returns:

  • str – The validated interval string.

Raises:

# leadr.boards.domain.board_template.BoardTemplate.validate_slug
validate_slug(value)

Validate slug format (lowercase alphanumeric with hyphens).

Parameters:

  • value (str | None) – The slug to validate, or None.

Returns:

  • str | None – The validated slug, or None if not provided.

Raises:

leadr.boards.domain.interval_parser

Utilities for parsing PostgreSQL interval syntax.

Functions:

leadr.boards.domain.interval_parser.parse_interval_to_timedelta
parse_interval_to_timedelta(interval_string)

Parse PostgreSQL interval syntax to Python timedelta.

Supports formats like:

  • "7 days"
  • "1 week"
  • "2 hours"
  • "30 minutes"

Parameters:

  • interval_string (str) – PostgreSQL interval syntax string.

Returns:

Raises:

  • ValueError – If interval format is invalid or unsupported.
Example > > > parse_interval_to_timedelta("7 days") > > > timedelta(days=7) > > > parse_interval_to_timedelta("1 week") > > > timedelta(weeks=1)

leadr.boards.services

Modules:

leadr.boards.services.board_service

Board service for managing board operations.

Classes:

  • BoardService – Service for managing board lifecycle and operations.
leadr.boards.services.board_service.BoardService

Bases: BaseService[Board, BoardRepository]

Service for managing board lifecycle and operations.

This service orchestrates board creation, updates, and retrieval by coordinating between the domain models and repository layer. Ensures business rules like game validation are enforced.

Functions:

Attributes:

# leadr.boards.services.board_service.BoardService.create_board
create_board(account_id, game_id, name, icon='fa-crown', unit=None, is_active=True, is_published=True, sort_direction=SortDirection.DESCENDING, keep_strategy=KeepStrategy.ALL, slug=None, short_code=None, created_from_template_id=None, template_name=None, starts_at=None, ends_at=None, tags=None, description=None)

Create a new board.

Parameters:

  • account_id (AccountID) – The ID of the account that owns this board.
  • game_id (GameID) – The ID of the game this board belongs to.
  • name (str) – The board name.
  • icon (str | None) – Icon identifier for the board. Defaults to "fa-crown".
  • unit (str | None) – Unit of measurement for scores. Defaults to None.
  • is_active (bool) – Whether the board is currently active. Defaults to True.
  • is_published (bool) – Whether the board is published and visible on public web views. Defaults to True.
  • sort_direction (SortDirection) – Direction to sort scores. Defaults to DESCENDING.
  • keep_strategy (KeepStrategy) – Strategy for keeping multiple scores from same user. Defaults to ALL.
  • slug (str | None) – Optional URL-friendly slug. If not provided, auto-generated from name.
  • short_code (str | None) – Globally unique short code for direct sharing.
  • created_from_template_id (BoardTemplateID | None) – Optional template ID this board was created from.
  • template_name (str | None) – Optional template name.
  • starts_at (datetime | None) – Optional start time for time-bounded boards.
  • ends_at (datetime | None) – Optional end time for time-bounded boards.
  • tags (list[str] | None) – Optional list of tags for categorization.
  • description (str | None) – Optional short description of the board.

Returns:

  • Board – The created Board domain entity.

Raises:

Example > > > board = await service.create_board( > > > ... account_id=account.id, > > > ... game_id=game.id, > > > ... name="Speed Run Board", > > > ... icon="trophy", > > > ... unit="seconds", > > > ... is_active=True, > > > ... sort_direction=SortDirection.ASCENDING, > > > ... keep_strategy=KeepStrategy.BEST_ONLY, > > > ... )
# leadr.boards.services.board_service.BoardService.create_board_from_template
create_board_from_template(template)

Create a new board from a board template.

Extracts configuration from the template and calculates time boundaries based on the template's repeat_interval. Automatically generates a unique short code for the board. If the template has a series field, generates a sequential series value and uses it in the board name.

Parameters:

  • template (BoardTemplate) – The BoardTemplate to create a board from.

Returns:

  • Board – The created Board domain entity.

Raises:

  • ValueError – If interval parsing fails, game doesn't belong to account, or name generation fails.
Example > > > board = await service.create_board_from_template(template)
# leadr.boards.services.board_service.BoardService.delete
delete(entity_id)

Soft-delete an entity.

Parameters:

Raises:

# leadr.boards.services.board_service.BoardService.get_board
get_board(board_id)

Get a board by its ID.

Parameters:

  • board_id (BoardID) – The ID of the board to retrieve.

Returns:

  • Board | None – The Board domain entity if found, None otherwise.
# leadr.boards.services.board_service.BoardService.get_board_by_short_code
get_board_by_short_code(short_code)

Get a board by its short_code.

Parameters:

  • short_code (str) – The short_code to search for.

Returns:

  • Board | None – The Board domain entity if found, None otherwise.
# leadr.boards.services.board_service.BoardService.get_by_id
get_by_id(entity_id)

Get an entity by its ID.

Parameters:

Returns:

  • DomainEntityT | None – The domain entity if found, None otherwise
# leadr.boards.services.board_service.BoardService.get_by_id_or_raise
get_by_id_or_raise(entity_id)

Get an entity by its ID or raise EntityNotFoundError.

Parameters:

Returns:

Raises:

# leadr.boards.services.board_service.BoardService.list_all
list_all()

List all non-deleted entities.

Returns:

# leadr.boards.services.board_service.BoardService.list_boards
list_boards(account_id=None, game_id=None, code=None, is_active=None, is_published=None, starts_before=None, starts_after=None, ends_before=None, ends_after=None, pagination=None)

List boards with optional filtering.

Parameters:

  • account_id (AccountID | None) – Optional account ID to filter by
  • game_id (GameID | None) – Optional game ID to filter by
  • code (str | None) – Optional short code to filter by
  • is_active (bool | None) – Optional filter for active status
  • is_published (bool | None) – Optional filter for published status
  • starts_before (datetime | None) – Optional filter for boards starting before this time
  • starts_after (datetime | None) – Optional filter for boards starting after this time
  • ends_before (datetime | None) – Optional filter for boards ending before this time
  • ends_after (datetime | None) – Optional filter for boards ending after this time
  • pagination (PaginationParams | None) – Optional pagination parameters

Returns:

# leadr.boards.services.board_service.BoardService.list_boards_by_account
list_boards_by_account(account_id)

List all boards for an account.

Parameters:

  • account_id (AccountID) – The ID of the account to list boards for.

Returns:

  • list[Board] – List of Board domain entities for the account.
# leadr.boards.services.board_service.BoardService.repository
repository = self._create_repository(session)
# leadr.boards.services.board_service.BoardService.soft_delete
soft_delete(entity_id)

Soft-delete an entity and return it before deletion.

Useful for endpoints that need to return the deleted entity in the response.

Parameters:

Returns:

Raises:

# leadr.boards.services.board_service.BoardService.update_board
update_board(board_id, name=None, icon=None, short_code=None, unit=None, is_active=None, is_published=None, sort_direction=None, keep_strategy=None, created_from_template_id=None, template_name=None, starts_at=None, ends_at=None, tags=None, description=None)

Update board fields.

Parameters:

  • board_id (BoardID) – The ID of the board to update
  • name (str | None) – New board name, if provided
  • icon (str | None) – New icon, if provided
  • short_code (str | None) – New short_code, if provided
  • unit (str | None) – New unit, if provided
  • is_active (bool | None) – New is_active status, if provided
  • is_published (bool | None) – New is_published status, if provided
  • sort_direction (SortDirection | None) – New sort_direction, if provided
  • keep_strategy (KeepStrategy | None) – New keep_strategy, if provided
  • created_from_template_id (BoardTemplateID | None) – New created_from_template_id, if provided
  • template_name (str | None) – New template_name, if provided
  • starts_at (datetime | None) – New starts_at, if provided
  • ends_at (datetime | None) – New ends_at, if provided
  • tags (list[str] | None) – New tags list, if provided
  • description (str | None) – New description, if provided

Returns:

  • Board – The updated Board domain entity

Raises:

leadr.boards.services.board_tasks

Background tasks for board processing.

Contains tasks for:

  • Processing due board templates and creating boards
  • Expiring boards past their end date

Functions:

Attributes:

leadr.boards.services.board_tasks.expire_boards
expire_boards()

Expire boards that have passed their end date.

Queries for active boards where ends_at \<= now() and sets is_active=False.

This task is designed to be called periodically (e.g., every minute).

leadr.boards.services.board_tasks.logger
logger = logging.getLogger(__name__)
leadr.boards.services.board_tasks.process_due_templates
process_due_templates()

Process all due board templates and create boards.

Queries for active templates where next_run_at \<= now(), creates boards from each template, and updates the template's next_run_at.

This task is designed to be called periodically (e.g., every minute).

leadr.boards.services.board_template_service

BoardTemplate service for managing board template operations.

Classes:

leadr.boards.services.board_template_service.BoardTemplateService

Bases: BaseService[BoardTemplate, BoardTemplateRepository]

Service for managing board template lifecycle and operations.

This service orchestrates board template creation, updates, and retrieval by coordinating between the domain models and repository layer. Ensures business rules like game validation are enforced.

Functions:

Attributes:

# leadr.boards.services.board_template_service.BoardTemplateService.advance_template_schedule
advance_template_schedule(template_id)

Advance a template's next_run_at by its repeat_interval.

This is typically called after successfully creating a board from the template.

Parameters:

Returns:

  • BoardTemplate – The updated BoardTemplate with advanced next_run_at.

Raises:

Example > > > template = await service.advance_template_schedule(template.id) > > > > > > # template.next_run_at is now advanced by repeat_interval
# leadr.boards.services.board_template_service.BoardTemplateService.create_board_template
create_board_template(account_id, game_id, name, slug, repeat_interval, next_run_at, is_active, is_published=True, name_template=None, series=None, icon='fa-crown', unit=None, sort_direction=SortDirection.DESCENDING, keep_strategy=KeepStrategy.ALL, starts_at=None, ends_at=None, tags=None, config=None)

Create a new board template.

Parameters:

  • account_id (AccountID) – The ID of the account that owns this template.
  • game_id (GameID) – The ID of the game this template belongs to.
  • name (str) – The template name.
  • repeat_interval (str) – PostgreSQL interval syntax for repeat frequency.
  • next_run_at (datetime) – Next scheduled time to create a board.
  • is_active (bool) – Whether the template is currently active.
  • name_template (str | None) – Optional template string for generating board names.
  • series (str | None) – Optional series identifier for sequential board naming.
  • config (dict[str, Any] | None) – Optional configuration object for boards created from this template.
  • config_template – Optional template configuration for random generation.

Returns:

Raises:

  • EntityNotFoundError – If the game doesn't exist.
  • ValueError – If the game doesn't belong to the specified account or if name_template contains invalid placeholders.
Example > > > template = await service.create_board_template( > > > ... account_id=account.id, > > > ... game_id=game.id, > > > ... name="Weekly Speed Run Template", > > > ... name_template="Week {series} - {year}", > > > ... series="weekly", > > > ... repeat_interval="7 days", > > > ... next_run_at=datetime.now(UTC) + timedelta(days=7), > > > ... is_active=True, > > > ... )
# leadr.boards.services.board_template_service.BoardTemplateService.delete
delete(entity_id)

Soft-delete an entity.

Parameters:

Raises:

# leadr.boards.services.board_template_service.BoardTemplateService.get_board_template
get_board_template(template_id)

Get a board template by its ID.

Parameters:

Returns:

  • BoardTemplate | None – The BoardTemplate domain entity if found, None otherwise.
# leadr.boards.services.board_template_service.BoardTemplateService.get_by_id
get_by_id(entity_id)

Get an entity by its ID.

Parameters:

Returns:

  • DomainEntityT | None – The domain entity if found, None otherwise
# leadr.boards.services.board_template_service.BoardTemplateService.get_by_id_or_raise
get_by_id_or_raise(entity_id)

Get an entity by its ID or raise EntityNotFoundError.

Parameters:

Returns:

Raises:

# leadr.boards.services.board_template_service.BoardTemplateService.list_all
list_all()

List all non-deleted entities.

Returns:

# leadr.boards.services.board_template_service.BoardTemplateService.list_board_templates_by_account
list_board_templates_by_account(account_id, pagination=None)

List all board templates for an account with optional pagination.

Parameters:

  • account_id (AccountID | None) – The ID of the account to list templates for. If None, returns all templates (superadmin use case).
  • pagination (PaginationParams | None) – Optional pagination parameters.

Returns:

# leadr.boards.services.board_template_service.BoardTemplateService.list_board_templates_by_game
list_board_templates_by_game(account_id, game_id, pagination=None)

List all board templates for a specific game with optional pagination.

Parameters:

  • account_id (AccountID | None) – The ID of the account. If None, returns templates from all accounts (superadmin use case).
  • game_id (GameID) – The ID of the game to list templates for.
  • pagination (PaginationParams | None) – Optional pagination parameters.

Returns:

# leadr.boards.services.board_template_service.BoardTemplateService.repository
repository = self._create_repository(session)
# leadr.boards.services.board_template_service.BoardTemplateService.soft_delete
soft_delete(entity_id)

Soft-delete an entity and return it before deletion.

Useful for endpoints that need to return the deleted entity in the response.

Parameters:

Returns:

Raises:

# leadr.boards.services.board_template_service.BoardTemplateService.update_board_template
update_board_template(template_id, name=None, slug=None, name_template=None, series=None, icon=None, unit=None, sort_direction=None, keep_strategy=None, starts_at=None, ends_at=None, tags=None, repeat_interval=None, config=None, next_run_at=None, is_active=None, is_published=None)

Update board template fields.

Parameters:

  • template_id (BoardTemplateID) – The ID of the template to update.
  • name (str | None) – New template name, if provided.
  • name_template (str | None) – New name template, if provided.
  • series (str | None) – New series identifier, if provided.
  • repeat_interval (str | None) – New repeat interval, if provided.
  • config (dict[str, Any] | None) – New config, if provided.
  • config_template – New config template, if provided.
  • next_run_at (datetime | None) – New next_run_at, if provided.
  • is_active (bool | None) – New is_active status, if provided.

Returns:

Raises:

leadr.boards.services.dependencies

Board service dependency injection.

Functions:

Attributes:

leadr.boards.services.dependencies.BoardServiceDep
BoardServiceDep = Annotated[BoardService, Depends(get_board_service)]
leadr.boards.services.dependencies.BoardTemplateServiceDep
BoardTemplateServiceDep = Annotated[BoardTemplateService, Depends(get_board_template_service)]
leadr.boards.services.dependencies.get_board_service
get_board_service(db)

Get BoardService dependency.

Parameters:

Returns:

  • BoardService – BoardService instance for handling board operations
leadr.boards.services.dependencies.get_board_template_service
get_board_template_service(db)

Get BoardTemplateService dependency.

Parameters:

Returns:

leadr.boards.services.repositories

Board repository services.

Classes:

leadr.boards.services.repositories.BoardRepository

Bases: BaseRepository[Board, BoardORM]

Board repository for managing board persistence.

Functions:

  • count_boards_by_template – Count boards created from a specific template.
  • create – Create a new entity in the database.
  • delete – Soft delete an entity by setting its deleted_at timestamp.
  • filter – Filter boards by account and optional criteria.
  • get_by_id – Get an entity by its ID.
  • get_by_short_code – Get board by short_code.
  • get_by_slug – Get board by slug within account and game scope.
  • list_boards – List boards with optional filtering.
  • update – Update an existing entity in the database.

Attributes:

# leadr.boards.services.repositories.BoardRepository.SORTABLE_FIELDS
SORTABLE_FIELDS = {'id', 'name', 'slug', 'short_code', 'created_at', 'updated_at'}
# leadr.boards.services.repositories.BoardRepository.count_boards_by_template
count_boards_by_template(template_id)

Count boards created from a specific template.

Parameters:

Returns:

  • int – Number of boards created from this template
# leadr.boards.services.repositories.BoardRepository.create
create(entity)

Create a new entity in the database.

Parameters:

Returns:

# leadr.boards.services.repositories.BoardRepository.delete
delete(entity_id)

Soft delete an entity by setting its deleted_at timestamp.

Parameters:

Raises:

# leadr.boards.services.repositories.BoardRepository.filter
filter(account_id=None, **kwargs)

Filter boards by account and optional criteria.

Parameters:

  • account_id (UUID4 | PrefixedID | None) – Optional account ID to filter by. If None, returns all boards (superadmin use case). Regular users should always pass account_id.
  • **kwargs (Any) – Additional filter parameters (reserved for future use)

Returns:

  • list[Board] – List of boards for the account matching the filter criteria
# leadr.boards.services.repositories.BoardRepository.get_by_id
get_by_id(entity_id, include_deleted=False)

Get an entity by its ID.

Parameters:

  • entity_id (UUID4 | PrefixedID) – Entity ID to retrieve
  • include_deleted (bool) – If True, include soft-deleted entities. Defaults to False.

Returns:

  • DomainEntityT | None – Domain entity if found, None otherwise
# leadr.boards.services.repositories.BoardRepository.get_by_short_code
get_by_short_code(short_code)

Get board by short_code.

Parameters:

  • short_code (str) – The short_code to search for

Returns:

  • Board | None – Board entity if found, None otherwise
# leadr.boards.services.repositories.BoardRepository.get_by_slug
get_by_slug(account_id, game_id, slug, is_active=None)

Get board by slug within account and game scope.

Lookups are scoped to account_id and game_id to respect the partial unique constraint (account_id, game_id, slug) WHERE is_active=true.

Parameters:

  • account_id (UUID4 | AccountID) – The account ID to filter by
  • game_id (UUID4 | GameID) – The game ID to filter by
  • slug (str) – The slug to search for
  • is_active (bool | None) – Optional filter for active status. If None, returns board regardless of active status.

Returns:

  • Board | None – Board entity if found, None otherwise
# leadr.boards.services.repositories.BoardRepository.list_boards
list_boards(account_id=None, game_id=None, code=None, is_active=None, is_published=None, starts_before=None, starts_after=None, ends_before=None, ends_after=None, pagination=None)

List boards with optional filtering.

Parameters:

  • account_id (UUID4 | AccountID | None) – Optional account ID to filter by
  • game_id (UUID4 | GameID | None) – Optional game ID to filter by
  • code (str | None) – Optional short code to filter by
  • is_active (bool | None) – Optional filter for active status
  • is_published (bool | None) – Optional filter for published status
  • starts_before (datetime | None) – Optional filter for boards starting before this time
  • starts_after (datetime | None) – Optional filter for boards starting after this time
  • ends_before (datetime | None) – Optional filter for boards ending before this time
  • ends_after (datetime | None) – Optional filter for boards ending after this time
  • pagination (PaginationParams | None) – Optional pagination parameters

Returns:

Raises:

# leadr.boards.services.repositories.BoardRepository.session
session = session
# leadr.boards.services.repositories.BoardRepository.update
update(entity)

Update an existing entity in the database.

Parameters:

Returns:

Raises:

leadr.boards.services.repositories.BoardTemplateRepository

Bases: BaseRepository[BoardTemplate, BoardTemplateORM]

BoardTemplate repository for managing board template persistence.

Functions:

  • create – Create a new entity in the database.
  • delete – Soft delete an entity by setting its deleted_at timestamp.
  • filter – Filter board templates by account and optional game.
  • get_by_id – Get an entity by its ID.
  • update – Update an existing entity in the database.

Attributes:

# leadr.boards.services.repositories.BoardTemplateRepository.SORTABLE_FIELDS
SORTABLE_FIELDS = {'id', 'name', 'created_at', 'updated_at'}
# leadr.boards.services.repositories.BoardTemplateRepository.create
create(entity)

Create a new entity in the database.

Parameters:

Returns:

# leadr.boards.services.repositories.BoardTemplateRepository.delete
delete(entity_id)

Soft delete an entity by setting its deleted_at timestamp.

Parameters:

Raises:

# leadr.boards.services.repositories.BoardTemplateRepository.filter
filter(account_id=None, game_id=None, pagination=None, **kwargs)

Filter board templates by account and optional game.

Parameters:

  • account_id (AccountID | None) – Optional account ID to filter by. If None, returns all templates (superadmin use case). Regular users should always pass account_id.
  • game_id (GameID | None) – OPTIONAL - Game ID to filter by
  • pagination (PaginationParams | None) – Optional pagination parameters
  • **kwargs (Any) – Additional filter parameters (reserved for future use)

Returns:

Raises:

# leadr.boards.services.repositories.BoardTemplateRepository.get_by_id
get_by_id(entity_id, include_deleted=False)

Get an entity by its ID.

Parameters:

  • entity_id (UUID4 | PrefixedID) – Entity ID to retrieve
  • include_deleted (bool) – If True, include soft-deleted entities. Defaults to False.

Returns:

  • DomainEntityT | None – Domain entity if found, None otherwise
# leadr.boards.services.repositories.BoardTemplateRepository.session
session = session
# leadr.boards.services.repositories.BoardTemplateRepository.update
update(entity)

Update an existing entity in the database.

Parameters:

Returns:

Raises:

leadr.boards.services.short_code_generator

Utility for generating unique short codes for boards.

Short codes are used for direct board sharing (e.g., example.com/board/ABC123XY). They must be globally unique across all boards.

Functions:

Attributes:

leadr.boards.services.short_code_generator.CHARSET
CHARSET = '23456789ABCDEFGHJKMNPQRSTUVWXYZ'
leadr.boards.services.short_code_generator.CODE_LENGTH
CODE_LENGTH = 5
leadr.boards.services.short_code_generator.generate_short_code
generate_short_code()

Generate a random 8-character alphanumeric short code.

Uses cryptographically strong random number generator for security. Excludes ambiguous characters (0/O, 1/I/l) for better readability.

Returns:

  • str – 5-character uppercase alphanumeric code (e.g., 'A7B3X').
Example > > > code = generate_short_code() > > > len(code) > > > 5 > > > code.isupper() > > > True
leadr.boards.services.short_code_generator.generate_unique_short_code
generate_unique_short_code(session, max_retries=10)

Generate a globally unique short code with collision retry logic.

Generates random codes and checks database for uniqueness. If a collision is detected, retries up to max_retries times before raising an error.

Parameters:

  • session (AsyncSession) – Database session for uniqueness checking.
  • max_retries (int) – Maximum number of generation attempts (default 10).

Returns:

  • str – Unique 5-character short code guaranteed not to exist in database.

Raises:

  • RuntimeError – If unable to generate unique code within max_retries attempts.
Example > > > code = await generate_unique_short_code(session) > > > > > > # Code is guaranteed to be unique in database