Files
resolutionflow/backend/app/schemas/session.py
Michael Chihlas 009c60fbc3 feat: Add custom step creation and backend support (Phase 3A: B.8-B.10, B.13)
Implements custom step creation forms and backend persistence:

Task B.8 - StepForm Component:
- Comprehensive form for creating custom steps
- Step type selection (decision/action/solution) with descriptions
- Required fields: title, instructions (markdown supported)
- Optional fields: help text, commands (dynamic array), category, tags
- Visibility control (private/team/public)
- Save to library checkbox
- Full validation with error display
- Dynamic command management (add/remove, label + command)
- Tag input with Enter key support

Task B.9 - CustomStepModal:
- Tabbed modal interface
- Tab 1: "Type My Own" - embeds StepForm
- Tab 2: "Browse Library" - embeds StepLibraryBrowser
- Handles both saved steps (API) and drafts (no save)
- Loading states during step creation
- Error handling with user feedback
- Returns Step or CustomStepDraft to parent

Task B.10 - Backend Custom Steps Support:
- Database migration: add custom_steps JSONB column to sessions
- Updated Session model with custom_steps field
- Updated SessionResponse schema with custom_steps
- Updated SessionUpdate schema to accept custom_steps
- Migration ready to run: 4cdb5cba1aff

Task B.13 - Session Types Updates:
- Added CustomStep and CustomStepDraft interfaces
- Updated Session interface with custom_steps field
- Updated SessionUpdate interface
- Exported step types from types/index.ts
- Full TypeScript support for custom step integration

Remaining tasks: B.11 (TreeNavigationPage integration), B.12 (Export)
Build tested successfully.

Related: Issues #8, #9, #10

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 19:15:36 -05:00

54 lines
1.5 KiB
Python

from datetime import datetime
from typing import Optional, Any
from uuid import UUID
from pydantic import BaseModel, Field
class DecisionRecord(BaseModel):
node_id: str
question: Optional[str] = None
answer: Optional[str] = None
action_performed: Optional[str] = None
notes: Optional[str] = None
automation_used: Optional[bool] = False
timestamp: datetime
attachments: list[str] = Field(default_factory=list)
class SessionCreate(BaseModel):
tree_id: UUID
ticket_number: Optional[str] = Field(None, max_length=100)
client_name: Optional[str] = Field(None, max_length=255)
class SessionUpdate(BaseModel):
path_taken: Optional[list[str]] = None
decisions: Optional[list[DecisionRecord]] = None
custom_steps: Optional[list[dict[str, Any]]] = None
ticket_number: Optional[str] = Field(None, max_length=100)
client_name: Optional[str] = Field(None, max_length=255)
class SessionResponse(BaseModel):
id: UUID
tree_id: UUID
user_id: UUID
tree_snapshot: dict[str, Any]
path_taken: list[str]
decisions: list[dict[str, Any]]
custom_steps: list[dict[str, Any]] = Field(default_factory=list)
started_at: datetime
completed_at: Optional[datetime] = None
ticket_number: Optional[str] = None
client_name: Optional[str] = None
exported: bool
class Config:
from_attributes = True
class SessionExport(BaseModel):
format: str = Field(default="markdown", pattern="^(text|markdown|html)$")
include_timestamps: bool = True
include_tree_info: bool = True