Complete Phase 2: Frontend implementation with React + TypeScript

Frontend Features:
- React 18 + Vite + TypeScript + Tailwind CSS + Zustand
- JWT authentication with automatic token refresh
- Tree library with search and category filtering
- Full tree navigation (decision/action/solution nodes)
- Session management with notes and completion
- Session history with export (Markdown/Text/HTML)
- ErrorBoundary for graceful error handling

Backend Fixes:
- CORS: Added port 5174 to allowed origins
- Sessions: Fixed JSONB datetime serialization (mode='json')

Documentation:
- Updated PROGRESS.md with Phase 2 completion
- Updated 03-DEVELOPMENT-ROADMAP.md with checked items
- Added PHASE-2.5-PERSONAL-BRANCHING.md spec

Seed Data:
- Added backend/scripts/seed_data.py with Password Reset tree

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-01-27 22:42:22 -05:00
parent 7d96807fb1
commit cd10ecd42c
51 changed files with 9014 additions and 111 deletions

57
frontend/src/api/trees.ts Normal file
View File

@@ -0,0 +1,57 @@
import apiClient from './client'
import type { Tree, TreeListItem, TreeCreate, TreeUpdate } from '@/types'
export interface TreeListParams {
page?: number
size?: number
category?: string
include_inactive?: boolean
}
export interface TreeListResponse {
items: TreeListItem[]
total: number
page: number
size: number
pages: number
}
export const treesApi = {
async list(params?: TreeListParams): Promise<TreeListItem[]> {
const response = await apiClient.get<TreeListItem[]>('/trees', { params })
return response.data
},
async get(id: string): Promise<Tree> {
const response = await apiClient.get<Tree>(`/trees/${id}`)
return response.data
},
async create(data: TreeCreate): Promise<Tree> {
const response = await apiClient.post<Tree>('/trees', data)
return response.data
},
async update(id: string, data: TreeUpdate): Promise<Tree> {
const response = await apiClient.put<Tree>(`/trees/${id}`, data)
return response.data
},
async delete(id: string): Promise<void> {
await apiClient.delete(`/trees/${id}`)
},
async categories(): Promise<string[]> {
const response = await apiClient.get<string[]>('/trees/categories')
return response.data
},
async search(query: string, category?: string): Promise<TreeListItem[]> {
const response = await apiClient.get<TreeListItem[]>('/trees/search', {
params: { q: query, category },
})
return response.data
},
}
export default treesApi