feat: add description field to boards and update related components for onboarding

This commit is contained in:
Abhimanyu Saharan
2026-02-11 18:19:29 +05:30
parent 25eb45bf54
commit c6417bcffb
15 changed files with 148 additions and 6 deletions

View File

@@ -175,6 +175,7 @@ async def start_onboarding(
prompt = (
"BOARD ONBOARDING REQUEST\n\n"
f"Board Name: {board.name}\n"
f"Board Description: {board.description or '(not provided)'}\n"
"You are the gateway agent. Ask the user 6-10 focused questions total:\n"
"- 3-6 questions to clarify the board goal.\n"
"- 1 question to choose a unique name for the board lead agent "

View File

@@ -23,6 +23,7 @@ class Board(TenantScoped, table=True):
organization_id: UUID = Field(foreign_key="organizations.id", index=True)
name: str
slug: str = Field(index=True)
description: str = Field(default="")
gateway_id: UUID | None = Field(default=None, foreign_key="gateways.id", index=True)
board_group_id: UUID | None = Field(
default=None,

View File

@@ -11,6 +11,7 @@ from sqlmodel import SQLModel
_ERR_GOAL_FIELDS_REQUIRED = "Confirmed goal boards require objective and success_metrics"
_ERR_GATEWAY_REQUIRED = "gateway_id is required"
_ERR_DESCRIPTION_REQUIRED = "description is required"
RUNTIME_ANNOTATION_TYPES = (datetime, UUID)
@@ -19,6 +20,7 @@ class BoardBase(SQLModel):
name: str
slug: str
description: str
gateway_id: UUID | None = None
board_group_id: UUID | None = None
board_type: str = "goal"
@@ -37,6 +39,10 @@ class BoardCreate(BoardBase):
@model_validator(mode="after")
def validate_goal_fields(self) -> Self:
"""Require gateway and goal details when creating a confirmed goal board."""
description = self.description.strip()
if not description:
raise ValueError(_ERR_DESCRIPTION_REQUIRED)
self.description = description
if self.gateway_id is None:
raise ValueError(_ERR_GATEWAY_REQUIRED)
if (
@@ -53,6 +59,7 @@ class BoardUpdate(SQLModel):
name: str | None = None
slug: str | None = None
description: str | None = None
gateway_id: UUID | None = None
board_group_id: UUID | None = None
board_type: str | None = None
@@ -68,6 +75,13 @@ class BoardUpdate(SQLModel):
# Treat explicit null like "unset" is invalid for patch updates.
if "gateway_id" in self.model_fields_set and self.gateway_id is None:
raise ValueError(_ERR_GATEWAY_REQUIRED)
if "description" in self.model_fields_set:
if self.description is None:
raise ValueError(_ERR_DESCRIPTION_REQUIRED)
description = self.description.strip()
if not description:
raise ValueError(_ERR_DESCRIPTION_REQUIRED)
self.description = description
return self

View File

@@ -0,0 +1,37 @@
"""Add description field to boards.
Revision ID: c3b58a391f2e
Revises: b308f2876359
Create Date: 2026-02-11 00:00:00.000000
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "c3b58a391f2e"
down_revision = "b308f2876359"
branch_labels = None
depends_on = None
def upgrade() -> None:
"""Add required board description column."""
op.add_column(
"boards",
sa.Column(
"description",
sa.String(),
nullable=False,
server_default="",
),
)
op.alter_column("boards", "description", server_default=None)
def downgrade() -> None:
"""Remove board description column."""
op.drop_column("boards", "description")

View File

@@ -6,7 +6,7 @@ from uuid import uuid4
import pytest
from app.schemas.board_onboarding import BoardOnboardingConfirm
from app.schemas.boards import BoardCreate
from app.schemas.boards import BoardCreate, BoardUpdate
def test_goal_board_requires_objective_and_metrics_when_confirmed() -> None:
@@ -18,6 +18,7 @@ def test_goal_board_requires_objective_and_metrics_when_confirmed() -> None:
BoardCreate(
name="Goal Board",
slug="goal",
description="Ship onboarding improvements.",
gateway_id=uuid4(),
board_type="goal",
goal_confirmed=True,
@@ -26,6 +27,7 @@ def test_goal_board_requires_objective_and_metrics_when_confirmed() -> None:
BoardCreate(
name="Goal Board",
slug="goal",
description="Ship onboarding improvements.",
gateway_id=uuid4(),
board_type="goal",
goal_confirmed=True,
@@ -36,7 +38,13 @@ def test_goal_board_requires_objective_and_metrics_when_confirmed() -> None:
def test_goal_board_allows_missing_objective_before_confirmation() -> None:
"""Draft goal boards may omit objective/success_metrics before confirmation."""
BoardCreate(name="Draft", slug="draft", gateway_id=uuid4(), board_type="goal")
BoardCreate(
name="Draft",
slug="draft",
description="Iterate on backlog hygiene.",
gateway_id=uuid4(),
board_type="goal",
)
def test_general_board_allows_missing_objective() -> None:
@@ -44,11 +52,30 @@ def test_general_board_allows_missing_objective() -> None:
BoardCreate(
name="General",
slug="general",
description="General coordination board.",
gateway_id=uuid4(),
board_type="general",
)
def test_board_create_requires_description() -> None:
"""Board creation should reject empty descriptions."""
with pytest.raises(ValueError, match="description is required"):
BoardCreate(
name="Goal Board",
slug="goal",
description=" ",
gateway_id=uuid4(),
board_type="goal",
)
def test_board_update_rejects_empty_description_patch() -> None:
"""Patch payloads should reject blank descriptions."""
with pytest.raises(ValueError, match="description is required"):
BoardUpdate(description=" ")
def test_onboarding_confirm_requires_goal_fields() -> None:
"""Onboarding confirm should enforce goal fields for goal board types."""
with pytest.raises(