Files
resolutionflow/backend/app/schemas/step_library.py
chihlasm e0089a9c5a feat: update all endpoints and schemas for account-based model
Replace team_id with account_id across all API endpoints (trees,
categories, tags, steps, step_categories, admin, auth). Add new
accounts and webhooks endpoints. Registration now atomically creates
Account + Subscription, with account_invite_code bypassing the
platform invite gate.

Schemas updated for account_id/account_role. 82 tests passing
including 18 new tests for accounts, subscriptions, and permissions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 02:39:01 -05:00

136 lines
3.7 KiB
Python

from datetime import datetime
from decimal import Decimal
from typing import Optional, Literal
from uuid import UUID
from pydantic import BaseModel, Field
class StepCommand(BaseModel):
"""A command that can be run as part of a step."""
label: str
command: str
command_type: Optional[str] = None # e.g., 'powershell', 'cmd', 'bash'
class StepContent(BaseModel):
"""Content structure for step library entries (stored as JSONB)."""
instructions: str = Field(..., min_length=1)
help_text: Optional[str] = None
commands: Optional[list[StepCommand]] = None
# Base schemas
class StepLibraryBase(BaseModel):
title: str = Field(..., min_length=1, max_length=255)
step_type: Literal['decision', 'action', 'solution']
content: StepContent
category_id: Optional[UUID] = None
tags: list[str] = Field(default_factory=list)
visibility: Literal['private', 'team', 'public'] = 'private'
class StepLibraryCreate(StepLibraryBase):
account_id: Optional[UUID] = None
class StepLibraryUpdate(BaseModel):
title: Optional[str] = Field(None, min_length=1, max_length=255)
step_type: Optional[Literal['decision', 'action', 'solution']] = None
content: Optional[StepContent] = None
category_id: Optional[UUID] = None
tags: Optional[list[str]] = None
visibility: Optional[Literal['private', 'team', 'public']] = None
class StepLibraryResponse(StepLibraryBase):
id: UUID
created_by: UUID
account_id: Optional[UUID] = None
usage_count: int
rating_average: Decimal
rating_count: int
helpful_yes: int
helpful_no: int
is_featured: bool
is_verified: bool
is_active: bool
created_at: datetime
updated_at: datetime
# Computed fields (populated by API)
category_name: Optional[str] = None
author_name: Optional[str] = None
class Config:
from_attributes = True
class StepLibraryListResponse(BaseModel):
id: UUID
title: str
step_type: str
visibility: str
category_id: Optional[UUID] = None
category_name: Optional[str] = None
tags: list[str]
usage_count: int
rating_average: Decimal
rating_count: int
is_featured: bool
created_by: UUID
author_name: Optional[str] = None
created_at: datetime
class Config:
from_attributes = True
# Rating schemas
class StepRatingBase(BaseModel):
rating: int = Field(..., ge=1, le=5)
was_helpful: Optional[bool] = None
review_text: Optional[str] = Field(None, max_length=500)
class StepRatingCreate(StepRatingBase):
session_id: Optional[UUID] = None # For verified use tracking
class StepRatingUpdate(BaseModel):
rating: Optional[int] = Field(None, ge=1, le=5)
was_helpful: Optional[bool] = None
review_text: Optional[str] = Field(None, max_length=500)
class StepRatingResponse(StepRatingBase):
id: UUID
step_id: UUID
user_id: UUID
is_verified_use: bool
session_id: Optional[UUID] = None
is_visible: bool
created_at: datetime
updated_at: datetime
# Computed
user_name: Optional[str] = None
class Config:
from_attributes = True
# Search and filter schemas
class StepSearchParams(BaseModel):
q: Optional[str] = None # Full-text search query
category_id: Optional[UUID] = None
tags: Optional[list[str]] = None
min_rating: Optional[float] = Field(None, ge=0, le=5)
step_type: Optional[Literal['decision', 'action', 'solution']] = None
visibility: Optional[Literal['private', 'team', 'public']] = None
sort_by: Literal['recent', 'popular', 'highest_rated', 'most_used'] = 'recent'
limit: int = Field(20, ge=1, le=100)
offset: int = Field(0, ge=0)
class PopularTagResponse(BaseModel):
tag: str
count: int