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

17 KiB

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:

// 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)

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)

// 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)

export const stepCategoriesApi = {
  list: () => Promise<StepCategory[]>
  get: (id: string) => Promise<StepCategory>
}

B.3: Add TypeScript Types

File: frontend/src/types/step.ts (NEW)

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:

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:

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:

const [showCustomStepModal, setShowCustomStepModal] = useState(false)
const [customSteps, setCustomSteps] = useState<CustomStep[]>([])

UI Changes:

  1. After each decision node's options, add:
<button
  onClick={() => setShowCustomStepModal(true)}
  className="mt-2 text-sm text-primary hover:underline"
>
  + Add Custom Step
</button>
  1. Add CustomStepModal at bottom of component

  2. Handle insert:

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)
}
  1. Render custom steps in the navigation flow with visual indicator:
{/* 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:

## Step 5: [CUSTOM] Check Additional Logs
*Custom step added by user*

Instructions: ...

B.12: Update Session Types

File: frontend/src/types/index.ts

Add:

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