Files
resolutionflow/docs/IMPLEMENTATION-PLAN-STEP-LIBRARY-FRONTEND.md
Michael Chihlas 67a98bc25c docs: Add implementation plan and project review from stale branches
Cherry-picked useful documentation from branches being cleaned up:
- IMPLEMENTATION-PLAN-STEP-LIBRARY-FRONTEND.md: Planning doc for Step Library frontend
- PROJECT-REVIEW-2026-02-02.md: Project status review from February 2026

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 18:17:44 -05:00

591 lines
17 KiB
Markdown

# Implementation Plan: Step Library Frontend + Tree Editor Validation
> **Date:** February 3, 2026
> **Scope:** Issues #1, #8, #9, #10
> **Estimated Components:** 8 new files, 4 modified files
> **Parallel Workstreams:** 2
---
## Overview
This plan covers two parallel workstreams:
| Workstream | Issues | Description |
|------------|--------|-------------|
| **A** | #1 | Tree Editor Validation UI |
| **B** | #10#9#8 | Step Library Frontend (sequential) |
Both workstreams are independent and can be developed simultaneously.
---
## Workstream A: Tree Editor Validation (Issue #1)
### Current State
The validation logic **already exists** in `treeEditorStore.ts:519-658`. It checks:
- ✅ Tree name required
- ✅ Decision nodes need question + options
- ✅ Option labels required
- ✅ Action/Solution nodes need titles
- ✅ At least one solution node
- ✅ Orphan node detection
- ✅ Invalid node reference detection
### What's Missing
1. **UI to display validation errors** - No visual feedback shown to user
2. **Prevent save on errors** - Save button should be disabled or show confirmation
3. **Circular reference detection** - Not implemented in current validation
4. **Real-time validation** - Currently only validates on explicit call
### Tasks
#### A.1: Add Circular Reference Detection
**File:** `frontend/src/store/treeEditorStore.ts`
Add to the `validate()` function after line 624:
```typescript
// Check for circular references in next_node_id chains
const detectCircularRefs = (startId: string, visited: Set<string> = new Set()): boolean => {
if (visited.has(startId)) return true
visited.add(startId)
const node = findNodeInTree(startId, state.treeStructure)
if (!node) return false
// Check options
if (node.options) {
for (const opt of node.options) {
if (opt.next_node_id && detectCircularRefs(opt.next_node_id, new Set(visited))) {
errors.push({
nodeId: node.id,
message: `Circular reference detected: "${opt.label}" creates a loop`,
severity: 'error'
})
return true
}
}
}
// Check next_node_id
if (node.next_node_id && detectCircularRefs(node.next_node_id, new Set(visited))) {
errors.push({
nodeId: node.id,
message: `Circular reference detected in node "${node.title || node.id}"`,
severity: 'error'
})
return true
}
return false
}
// Run from root
detectCircularRefs('root')
```
#### A.2: Create Validation Summary Component
**File:** `frontend/src/components/tree-editor/ValidationSummary.tsx` (NEW)
```typescript
interface ValidationSummaryProps {
errors: ValidationError[]
onSelectNode: (nodeId: string) => void
}
```
Features:
- Collapsible panel showing error/warning count
- Click error to select the problematic node
- Color-coded: red for errors, yellow for warnings
- Icon indicators (AlertCircle, AlertTriangle from lucide-react)
#### A.3: Integrate Validation UI into TreeEditorPage
**File:** `frontend/src/pages/TreeEditorPage.tsx`
Modifications:
1. Call `validate()` before save attempt
2. Show ValidationSummary when errors exist
3. Block save if any severity='error' exists (warnings allow save)
4. Add "Validate" button in toolbar for manual check
5. Auto-validate on blur from form fields (debounced)
#### A.4: Visual Node Error Indicators
**File:** `frontend/src/components/tree-editor/NodeList.tsx`
Modifications:
- Add red border/highlight to nodes with validation errors
- Show error icon badge on problem nodes
- Tooltip on hover showing the specific error
### Acceptance Criteria - Workstream A
- [ ] Cannot save tree without a name
- [ ] Cannot save tree without at least one solution node
- [ ] Validation errors display in a clear, clickable list
- [ ] Clicking an error selects the problematic node
- [ ] Circular references are detected and blocked
- [ ] Orphan nodes show as warnings (allow save with confirmation)
- [ ] Save button disabled when errors exist
---
## Workstream B: Step Library Frontend (Issues #10, #9, #8)
### Dependencies
- Backend API complete ✅ (`/api/v1/steps/*`, `/api/v1/step-categories/*`)
- No frontend API client exists yet
### Execution Order
```
#10 Step Library Browser Component
#9 Custom Step Creation Modal (embeds browser)
#8 Add Custom Step Button (triggers modal)
```
---
### Issue #10: Step Library Browser Component
#### B.1: Create Steps API Client
**File:** `frontend/src/api/steps.ts` (NEW)
```typescript
// API client for step library endpoints
export const stepsApi = {
list: (params?: StepListParams) => Promise<StepListItem[]>
get: (id: string) => Promise<Step>
create: (data: StepCreate) => Promise<Step>
update: (id: string, data: StepUpdate) => Promise<Step>
delete: (id: string) => Promise<void>
search: (query: string) => Promise<StepListItem[]>
getPopularTags: () => Promise<PopularTag[]>
rate: (id: string, data: RatingCreate) => Promise<Rating>
updateRating: (id: string, data: RatingUpdate) => Promise<Rating>
deleteRating: (id: string) => Promise<void>
getReviews: (id: string) => Promise<Review[]>
}
```
#### B.2: Create Step Categories API Client
**File:** `frontend/src/api/stepCategories.ts` (NEW)
```typescript
export const stepCategoriesApi = {
list: () => Promise<StepCategory[]>
get: (id: string) => Promise<StepCategory>
}
```
#### B.3: Add TypeScript Types
**File:** `frontend/src/types/step.ts` (NEW)
```typescript
export interface StepCommand {
label: string
command: string
command_type?: string
}
export interface StepContent {
instructions: string
help_text?: string
commands?: StepCommand[]
}
export interface Step {
id: string
title: string
step_type: 'decision' | 'action' | 'solution'
content: StepContent
visibility: 'private' | 'team' | 'public'
category_id?: string
category_name?: string
tags: string[]
usage_count: number
rating_average: number
rating_count: number
helpful_yes: number
helpful_no: number
is_featured: boolean
is_verified: boolean
created_by: string
author_name?: string
created_at: string
updated_at: string
}
export interface StepListItem {
id: string
title: string
step_type: string
visibility: string
category_id?: string
category_name?: string
tags: string[]
usage_count: number
rating_average: number
rating_count: number
is_featured: boolean
created_by: string
author_name?: string
created_at: string
}
export interface StepCategory {
id: string
name: string
description?: string
display_order: number
team_id?: string
is_active: boolean
}
export interface StepListParams {
visibility?: 'private' | 'team' | 'public'
category_id?: string
tags?: string[]
min_rating?: number
step_type?: 'decision' | 'action' | 'solution'
sort_by?: 'recent' | 'popular' | 'highest_rated' | 'most_used'
limit?: number
offset?: number
}
export interface PopularTag {
tag: string
count: number
}
```
#### B.4: Create Step Card Component
**File:** `frontend/src/components/step-library/StepCard.tsx` (NEW)
A card displaying:
- Step title and type badge (decision/action/solution)
- Category name
- Star rating (if rated) or "Not rated" placeholder
- Tags as chips (max 3 visible, "+N more" overflow)
- Author name and created date
- Usage count
- [Preview] and [Insert] buttons
#### B.5: Create Step Detail Modal
**File:** `frontend/src/components/step-library/StepDetailModal.tsx` (NEW)
Full step preview showing:
- Title, type, category, tags
- Full rating breakdown (star distribution chart)
- Instructions (markdown rendered)
- Commands (copyable code blocks)
- Help text
- Top reviews (2-3 shown, "See all" link)
- [Cancel] and [Insert Into Session] buttons
#### B.6: Create Step Library Browser Component
**File:** `frontend/src/components/step-library/StepLibraryBrowser.tsx` (NEW)
Main browser component with:
**Header:**
- Search input (full-text, debounced 300ms)
- Filter dropdowns: Category, Type, Min Rating, Sort By
- Popular tags as clickable chips
**Body:**
- Grouped sections: "My Steps", "Team Steps", "Community"
- Each section collapsible
- Virtualized list for performance (if >50 items)
- Loading skeletons while fetching
- Empty state: "No steps found. Create your first step!"
**Footer:**
- [+ Create New Step] button (optional, for standalone use)
**Props:**
```typescript
interface StepLibraryBrowserProps {
onInsert: (step: Step) => void
onCreateNew?: () => void
showCreateButton?: boolean
}
```
#### B.7: Update API Index
**File:** `frontend/src/api/index.ts`
Add exports for `stepsApi` and `stepCategoriesApi`.
### Acceptance Criteria - Issue #10
- [ ] Can search steps with full-text query
- [ ] Can filter by category, type, minimum rating
- [ ] Can sort by recent, popular, highest rated, most used
- [ ] Steps grouped by visibility (My Steps, Team, Community)
- [ ] Can click step to see full preview modal
- [ ] Can copy commands from preview
- [ ] Can click "Insert" to select a step
- [ ] Popular tags shown and clickable as quick filters
---
### Issue #9: Custom Step Creation Modal
#### B.8: Create Step Form Component
**File:** `frontend/src/components/step-library/StepForm.tsx` (NEW)
Form fields:
- Step Type: Radio group (Decision / Action / Solution)
- Title: Text input (required)
- Instructions: Textarea with markdown support (required)
- Help Text: Textarea (optional)
- Commands: Dynamic array field (optional)
- Each command: label + command + type dropdown
- Category: Dropdown (optional)
- Tags: Tag input with autocomplete (optional)
- Visibility: Dropdown (Private / Team / Public)
- Checkbox: "Save to My Step Library for reuse"
#### B.9: Create Custom Step Modal
**File:** `frontend/src/components/step-library/CustomStepModal.tsx` (NEW)
Tabbed modal with:
- **Tab 1: "Type My Own"** - StepForm component
- **Tab 2: "Browse Library"** - StepLibraryBrowser component
**Props:**
```typescript
interface CustomStepModalProps {
isOpen: boolean
onClose: () => void
onInsertStep: (step: Step | CustomStepDraft) => void
}
```
**Behavior:**
- Tab 1: User fills form, clicks [Insert Step]
- If "Save to library" checked, POST to `/api/v1/steps` first
- Returns step data to parent
- Tab 2: User browses, clicks Insert on a step
- Returns selected step to parent
### Acceptance Criteria - Issue #9
- [ ] Modal has two tabs: "Type My Own" and "Browse Library"
- [ ] Can create custom step with type, title, instructions
- [ ] Can optionally add commands, help text, category, tags
- [ ] Can optionally save step to personal library
- [ ] Can switch to Browse tab and select existing step
- [ ] Insert button returns step data to parent component
---
### Issue #8: Add Custom Step Button in Tree Navigation
#### B.10: Modify TreeNavigationPage
**File:** `frontend/src/pages/TreeNavigationPage.tsx`
Add state:
```typescript
const [showCustomStepModal, setShowCustomStepModal] = useState(false)
const [customSteps, setCustomSteps] = useState<CustomStep[]>([])
```
**UI Changes:**
1. After each decision node's options, add:
```tsx
<button
onClick={() => setShowCustomStepModal(true)}
className="mt-2 text-sm text-primary hover:underline"
>
+ Add Custom Step
</button>
```
2. Add CustomStepModal at bottom of component
3. Handle insert:
```typescript
const handleInsertCustomStep = (step: Step | CustomStepDraft) => {
// Insert after current node in session
const customStep: CustomStep = {
id: crypto.randomUUID(),
inserted_after_node_id: currentNodeId,
step_data: step,
timestamp: new Date().toISOString()
}
setCustomSteps([...customSteps, customStep])
// Navigate to custom step (becomes current)
setCurrentNodeId(customStep.id)
setShowCustomStepModal(false)
}
```
4. Render custom steps in the navigation flow with visual indicator:
```tsx
{/* Custom Step Badge */}
<span className="rounded-full bg-purple-100 px-2 py-1 text-xs font-medium text-purple-800">
Custom Step
</span>
```
#### B.11: Update Session Export
**File:** `frontend/src/components/session/ExportPreviewModal.tsx`
Ensure custom steps are included in export with clear marking:
```markdown
## Step 5: [CUSTOM] Check Additional Logs
*Custom step added by user*
Instructions: ...
```
#### B.12: Update Session Types
**File:** `frontend/src/types/index.ts`
Add:
```typescript
export interface CustomStep {
id: string
inserted_after_node_id: string
step_data: Step | CustomStepDraft
timestamp: string
}
export interface CustomStepDraft {
title: string
step_type: 'decision' | 'action' | 'solution'
content: StepContent
category_id?: string
tags?: string[]
}
```
### Acceptance Criteria - Issue #8
- [ ] "+ Add Custom Step" button visible at each decision point
- [ ] Button opens CustomStepModal
- [ ] Can insert step from "Type My Own" tab
- [ ] Can insert step from "Browse Library" tab
- [ ] Custom steps appear in session flow with visual indicator
- [ ] Custom steps included in session export
- [ ] Session continues after custom step
---
## File Summary
### New Files (10)
| File | Issue | Description |
|------|-------|-------------|
| `components/tree-editor/ValidationSummary.tsx` | #1 | Error/warning display |
| `api/steps.ts` | #10 | Steps API client |
| `api/stepCategories.ts` | #10 | Categories API client |
| `types/step.ts` | #10 | Step TypeScript types |
| `components/step-library/StepCard.tsx` | #10 | Step list item card |
| `components/step-library/StepDetailModal.tsx` | #10 | Step preview modal |
| `components/step-library/StepLibraryBrowser.tsx` | #10 | Main browser component |
| `components/step-library/StepForm.tsx` | #9 | Step creation form |
| `components/step-library/CustomStepModal.tsx` | #9 | Tabbed modal wrapper |
### Modified Files (5)
| File | Issue | Changes |
|------|-------|---------|
| `store/treeEditorStore.ts` | #1 | Add circular reference detection |
| `pages/TreeEditorPage.tsx` | #1 | Integrate validation UI |
| `components/tree-editor/NodeList.tsx` | #1 | Node error indicators |
| `pages/TreeNavigationPage.tsx` | #8 | Add custom step button + modal |
| `api/index.ts` | #10 | Export new API clients |
| `types/index.ts` | #8 | Add CustomStep types |
---
## Execution Plan
### Phase 1: Foundation (Do First)
```
Workstream A Workstream B
───────────── ─────────────
A.1 Circular ref detection B.1 Steps API client
B.2 Categories API client
B.3 TypeScript types
```
### Phase 2: Core Components
```
Workstream A Workstream B
───────────── ─────────────
A.2 ValidationSummary B.4 StepCard
A.3 TreeEditorPage integration B.5 StepDetailModal
A.4 NodeList indicators B.6 StepLibraryBrowser
```
### Phase 3: Integration
```
Workstream A Workstream B
───────────── ─────────────
Testing & polish B.8 StepForm
B.9 CustomStepModal
B.10 TreeNavigationPage integration
B.11-12 Export & types updates
```
---
## Testing Checklist
### Workstream A - Validation
- [ ] Create tree without name → Error shown, save blocked
- [ ] Create tree without solution → Error shown, save blocked
- [ ] Create decision without options → Error shown
- [ ] Create circular reference (A → B → A) → Error detected
- [ ] Create orphan node → Warning shown (can still save)
- [ ] Click error → Node selected
- [ ] Fix all errors → Save enabled
### Workstream B - Step Library
- [ ] Open browser → Steps load, grouped by visibility
- [ ] Search "citrix" → Filtered results appear
- [ ] Filter by category → Results filtered
- [ ] Click step → Preview modal opens
- [ ] Click copy command → Copied to clipboard
- [ ] Click Insert → Modal closes, step returned
- [ ] Create custom step → Form validates, step inserted
- [ ] Save to library checked → Step saved to API
- [ ] Add custom step in navigation → Step appears with badge
- [ ] Complete session → Export includes custom steps
---
## Notes for Implementation
1. **Use existing patterns**: Follow Modal.tsx, TagInput.tsx, and existing page structures
2. **Dark mode**: All components must support light/dark themes via Tailwind classes
3. **Keyboard navigation**: Support Escape to close modals, Enter to submit
4. **Loading states**: Show skeletons or spinners during API calls
5. **Error handling**: Display user-friendly error messages, log details to console
6. **Accessibility**: Use proper ARIA labels, maintain focus management in modals
---
## Questions to Resolve Before Starting
1. **Custom steps persistence**: Should custom steps be saved to the session in the database, or only exist in frontend state until export?
- *Recommendation*: Save to session.decisions with a `is_custom_step: true` flag
2. **Step library page**: Should there be a standalone `/steps` page for browsing the library outside of navigation?
- *Recommendation*: Yes, add this as a future enhancement after Issue #10
3. **Rate limiting**: Should step creation have rate limiting to prevent spam?
- *Recommendation*: Backend concern, out of scope for this plan