sirenamc/stackline
Stackline, a team task board you run from the web or from Claude/ChatGPT. FastAPI + DataK3 + appid + Models + MCP.
A remix template · 0 remixes · Remix sirenamc/stackline
app/boards/application/ports.py
"""What the use cases need from the outside world. infrastructure/ provides it; tests fake it."""
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, Protocol
from boards.domain.model import Board, BoardList, Card, Role
@dataclass(frozen=True)
class Event:
"""One line of the activity log: who did what, to which card, and what changed."""
board_id: str
card_number: Optional[int]
actor: str
action: str # "created", "moved", "edited", "assigned", "member added", ...
field: Optional[str] = None
before: Optional[str] = None
after: Optional[str] = None
at: Optional[datetime] = None
class BoardRepository(Protocol):
def get(self, board_id: str) -> Optional[Board]: ...
def boards_for(self, email: str) -> list: ...
# Each write touches only what it names. Members are never written as a side effect of
# saving a board, so a stale copy of a board can't bring back someone the owner removed.
def save_board(self, board: Board) -> None: ... # title and owner only
def save_list(self, board_id: str, lst: BoardList) -> None: ...
def save_membership(self, board_id: str, email: str, role: Role) -> None: ...
def remove_membership(self, board_id: str, email: str) -> None: ...
def get_card(self, number: int) -> Optional[Card]: ...
def cards_on(self, board_id: str) -> list: ...
def insert_card(self, card: Card) -> Card: ... # under a number never used before
def save_card(self, card: Card) -> None: ...
def delete_card(self, number: int) -> None: ...
def delete_board(self, board_id: str) -> None: ... # cards, lists, people, log; numbers stay claimed
def log(self, event: Event) -> None: ...
def history(self, board_id: str, card_number: int) -> list: ...
def activity(self, board_id: str, limit: int) -> list: ...
def save_embedding(self, number: int, text_hash: str, vector: list) -> None: ...
def embeddings(self, board_ids: list) -> dict: ... # {card number: (text_hash, vector)}
class Assistant(Protocol):
def checklist(self, title: str, description: str) -> list: ...
def summary(self, facts: str) -> str: ...
def embed(self, texts: list) -> list: ...
def plan(self, goal: str, deadline: str, today: str) -> list: ... # steps for set_up_board