ghpsolutions/quadro

Quadro: team boards with roles, history and an MCP endpoint for Claude and ChatGPT

A remix template · 0 remixes · Remix ghpsolutions/quadro

app/boards/application/ports.py

"""What the use cases need from the outside world. Infrastructure provides these."""
from __future__ import annotations

from typing import Optional, Protocol, Sequence

from boards.domain.model import Board, BoardList, Card, Role


class NumberTaken(Exception):
    """The card number was claimed by a concurrent insert; pick the next one."""


class BoardRepository(Protocol):
    # boards and people
    def save_board(self, board: Board) -> None: ...
    def get_board(self, board_id: str) -> Optional[Board]: ...
    def boards_for(self, email: str) -> list[Board]: ...
    def save_member(self, board_id: str, email: str, role: Role) -> None: ...
    def remove_member(self, board_id: str, email: str) -> None: ...

    # lists
    def save_list(self, lst: BoardList) -> None: ...
    def lists_on(self, board_id: str) -> list[BoardList]: ...
    def delete_list(self, list_id: str) -> None: ...

    # cards
    def next_number(self, board_id: str) -> int: ...
    def insert_card(self, card: Card) -> None:
        """Plain insert; raises NumberTaken if the id already exists."""
    def update_card(self, card: Card, expected_version: int) -> bool:
        """Write `card` only if the stored version is still `expected_version`."""
    def get_card(self, card_id: str) -> Optional[Card]: ...
    def cards_on(self, board_ids: Sequence[str]) -> list[Card]: ...
    def delete_card(self, card_id: str) -> None: ...

    # comments and history
    def add_comment(self, comment: dict) -> None: ...
    def comments_for(self, card_id: str) -> list[dict]: ...
    def comment_counts(self, board_id: str) -> dict: ...
    def record(self, event: dict) -> None: ...
    def activity(self, board_id: str, card_id: Optional[str] = None, limit: int = 50) -> list[dict]: ...

    # similarity index
    def save_embedding(self, card_id: str, board_id: str, digest: str, vector: list) -> None: ...
    def embeddings_on(self, board_id: str) -> dict: ...  # card_id -> (digest, vector)


class Assistant(Protocol):
    """Language features backed by Dodil Models."""
    def checklist(self, title: str, description: str) -> list[str]: ...
    def summary(self, facts: str) -> str: ...
    def embed(self, texts: list[str]) -> list[list[float]]: ...